import type { HTMLAttributes } from "preact/compat"; import { useEffect, useMemo, useRef } from "preact/hooks"; interface Props extends HTMLAttributes { dataView: DataView; pointer: number; } export const PointerCanvas = ({ dataView, pointer, ...otherProps }: Props) => { const canvasRef = useRef(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 <> ; }; 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; }