diff --git a/blog/2024-11-15-playing-with-fire/4-color.mdx b/blog/2024-11-15-playing-with-fire/4-color/index.mdx similarity index 100% rename from blog/2024-11-15-playing-with-fire/4-color.mdx rename to blog/2024-11-15-playing-with-fire/4-color/index.mdx 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 9a9c998..4a93195 100644 --- a/blog/2024-11-15-playing-with-fire/src/Canvas.tsx +++ b/blog/2024-11-15-playing-with-fire/src/Canvas.tsx @@ -10,6 +10,56 @@ function invertImage(sourceImage: ImageData): ImageData { return image; } +class RenderManager { + private isFinished: boolean = false; + private painter: Iterator = null; + constructor(private readonly setImage: (image: [ImageData]) => void) { + requestAnimationFrame(() => this.animate()); + } + + setPainter(painter: Iterator) { + console.log("Received next painter"); + if (!this) { + console.log(this); + return; + } + this.painter = painter; + } + + setFinished() { + console.log("Received finished"); + if (!this) { + console.log(this); + return; + } + this.isFinished = true; + } + + animate() { + console.log("Received next frame"); + if (!this) { + console.log(this); + return; + } + + if (this.isFinished) { + return; + } + + if (!this.painter) { + requestAnimationFrame(() => this.animate()); + } + + const nextImage = this.painter.next().value; + if (nextImage) { + console.log("Received next image"); + this.setImage([nextImage]); + } + + requestAnimationFrame(() => this.animate()); + } +} + type InvertibleCanvasProps = { width: number, height: number, @@ -104,28 +154,10 @@ interface CanvasProps { */ export default function Canvas({width, height, children}: CanvasProps) { const [image, setImage] = useState<[ImageData]>(null); - const [painterHolder, setPainterHolder] = useState<[Iterator]>(null); - useEffect(() => { - if (!painterHolder) { - return; - } + const [renderManager, _setRenderManager] = useState(new RenderManager(setImage)); + const setPainter = (painter: Iterator) => renderManager.setPainter.bind(renderManager)(painter); - const painter = painterHolder[0]; - const nextImage = painter.next().value; - if (nextImage) { - setImage([nextImage]); - setPainterHolder([painter]); - } else { - setPainterHolder(null); - } - }, [painterHolder]); - - const [painter, setPainter] = useState>(null); - useEffect(() => { - if (painter) { - setPainterHolder([painter]); - } - }, [painter]); + useEffect(() => () => { renderManager.setFinished.bind(renderManager)(); }, []); width = width ?? 500; height = height ?? 500;