Files
image-studio/view/canvas/useCanvasRenderer.ts
2026-07-04 15:27:20 +02:00

48 lines
1.5 KiB
TypeScript

import { useEffect, type RefObject } from "react";
import type { AppStore } from "@editor/store";
import { createRenderer, type RenderFrame } from "@renderer/index";
import { canvasRenderFramesEqual, selectCanvasRenderFrame } from "./renderFrame";
export function useCanvasRenderer(canvasRef: RefObject<HTMLCanvasElement | null>, store: AppStore) {
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const renderer = createRenderer(canvas);
let renderedFrame = selectCanvasRenderFrame(store.getState());
let pendingFrame: RenderFrame | undefined;
let animationFrame: number | undefined;
const flushRender = () => {
animationFrame = undefined;
const frame = pendingFrame;
if (!frame) return;
pendingFrame = undefined;
renderedFrame = frame;
renderer.render(frame);
};
const scheduleRender = (frame: RenderFrame) => {
pendingFrame = frame;
if (animationFrame !== undefined) return;
animationFrame = requestAnimationFrame(flushRender);
};
scheduleRender(renderedFrame);
const unsubscribe = store.subscribe((state) => {
const nextFrame = selectCanvasRenderFrame(state);
const currentFrame = pendingFrame ?? renderedFrame;
if (canvasRenderFramesEqual(currentFrame, nextFrame)) return;
scheduleRender(nextFrame);
});
return () => {
unsubscribe();
if (animationFrame !== undefined) cancelAnimationFrame(animationFrame);
renderer.dispose();
};
}, [canvasRef, store]);
}