1
0
Fork 0
tsgames/src/common/components/PointerCanvas.tsx

51 lines
1.6 KiB
TypeScript

import type { HTMLAttributes } from "preact/compat";
import { useEffect, useMemo, useRef } from "preact/hooks";
interface Props extends HTMLAttributes<HTMLCanvasElement> {
dataView: DataView;
pointer: number;
}
export const PointerCanvas = ({ dataView, pointer, ...otherProps }: Props) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
const ctx = useMemo(() => canvasRef.current?.getContext('2d'), [canvasRef.current]);
const imageData = useMemo(() => loadImageData(dataView, pointer), [dataView, pointer]);
useEffect(() => {
if (canvasRef.current) {
canvasRef.current.width = imageData.width;
canvasRef.current.height = imageData.height;
}
}, [imageData, canvasRef.current]);
useEffect(() => {
let raf: number;
const frame = () => {
if (ctx) {
ctx.putImageData(imageData, 0, 0);
}
raf = requestAnimationFrame(frame);
}
raf = requestAnimationFrame(frame);
return () => {
cancelAnimationFrame(raf);
};
}, [ctx, imageData]);
return <>
<canvas ref={canvasRef} {...otherProps} />
</>;
};
export const loadImageData = (dataView: DataView, pointer: number) => {
const width = dataView.getUint16(pointer + 0, true);
const height = dataView.getUint16(pointer + 2, true);
const dataPtr = dataView.getUint32(pointer + 4, true);
const imageBuffer = new Uint8ClampedArray(dataView.buffer, dataPtr, width * height * 4);
const imageData = new ImageData(imageBuffer, width, height);
return imageData;
}