From 1aa45e3f59bc90b206d6cfc6d75a62b9536252cb Mon Sep 17 00:00:00 2001 From: Bradlee Speice Date: Sat, 30 Nov 2024 12:39:54 -0500 Subject: [PATCH] Split paint/render image to handle callback depth Iterator state still uses the same pattern, not sure how problematic that is. --- .../src/Canvas.tsx | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/blog/2024-11-15-playing-with-fire/src/Canvas.tsx b/blog/2024-11-15-playing-with-fire/src/Canvas.tsx index 8d46cfd..85e152f 100644 --- a/blog/2024-11-15-playing-with-fire/src/Canvas.tsx +++ b/blog/2024-11-15-playing-with-fire/src/Canvas.tsx @@ -55,29 +55,28 @@ export default function Canvas({width, height, children}: CanvasProps) { } }, []); - const {colorMode} = useColorMode(); - // Holder objects are used to force re-painting even if the iterator // returns a modified image with the same reference type ImageHolder = { image?: ImageData }; - const [imageHolder, setImageHolder] = useState({ image: null }); - useEffect(() => { - const image = imageHolder.image; - if (!image) { - // No image is available, leave the canvas as-is - return; - } - if (!canvasCtx) { - // Canvas is not ready for the image we have, - // re-submit the image and wait for the ref to populate - setImageHolder({ image }); + const [paintImage, setPaintImage] = useState({ image: null }); + useEffect(() => { + if (paintImage.image && canvasCtx) { + canvasCtx.putImageData(paintImage.image, 0, 0); + } + }, [paintImage, canvasCtx]); + + const {colorMode} = useColorMode(); + const [renderImage, setRenderImage] = useState({ image: null }); + useEffect(() => { + const image = renderImage.image; + if (!image) { return; } // If light mode is active, paint the image as-is if (colorMode === 'light') { - canvasCtx.putImageData(image, 0, 0); + setPaintImage({ image }); return; } @@ -89,8 +88,8 @@ export default function Canvas({width, height, children}: CanvasProps) { const isAlpha = index % 4 === 3; paintImage.data[index] = isAlpha ? value : 255 - value; }) - canvasCtx.putImageData(paintImage, 0, 0); - }, [colorMode, imageHolder]); + setPaintImage({ image: paintImage }); + }, [colorMode, renderImage]); // Image iterators (painters) are also in a holder; this allows // re-submitting the existing iterator to draw the next frame, @@ -115,7 +114,7 @@ export default function Canvas({width, height, children}: CanvasProps) { const image = painter.next().value; if (image) { - setImageHolder({ image }); + setRenderImage({ image }); setAnimHolder({ painter }); } else { setAnimHolder({ painter: null });