51 lines
1.6 KiB
TypeScript
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;
|
|
} |