| 219 | }; |
| 220 | |
| 221 | const doAnimate = (fnName: keyof Pixel) => { |
| 222 | animationRef.current = requestAnimationFrame(() => doAnimate(fnName)); |
| 223 | const timeNow = performance.now(); |
| 224 | const timePassed = timeNow - timePreviousRef.current; |
| 225 | const timeInterval = 1000 / 60; |
| 226 | |
| 227 | if (timePassed < timeInterval) return; |
| 228 | timePreviousRef.current = timeNow - (timePassed % timeInterval); |
| 229 | |
| 230 | const ctx = canvasRef.current?.getContext('2d'); |
| 231 | if (!ctx || !canvasRef.current) return; |
| 232 | |
| 233 | ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height); |
| 234 | |
| 235 | let allIdle = true; |
| 236 | for (let i = 0; i < pixelsRef.current.length; i++) { |
| 237 | const pixel = pixelsRef.current[i]; |
| 238 | // @ts-ignore |
| 239 | pixel[fnName](); |
| 240 | if (!pixel.isIdle) { |
| 241 | allIdle = false; |
| 242 | } |
| 243 | } |
| 244 | if (allIdle) { |
| 245 | cancelAnimationFrame(animationRef.current); |
| 246 | } |
| 247 | }; |
| 248 | |
| 249 | const handleAnimation = (name: keyof Pixel) => { |
| 250 | if (animationRef.current !== null) { |