import { useEffect, useRef, useState, type RefObject } from "react"; import { Stage, Layer, Image, Shape } from "react-konva"; import type { KonvaEventObject } from "konva/lib/Node"; import { useCreateVideoSnapshot } from "../../hooks/useGetvideoSnapshots"; import { useCameraFeedContext } from "../../../../app/context/CameraFeedContext"; const BACKEND_WIDTH = 640; const BACKEND_HEIGHT = 360; const BACKEND_CELL_SIZE = 16; const rows = 22.5; const cols = 40; const gap = 0; const VideoFeedGridPainter = () => { const { state } = useCameraFeedContext(); const cameraFeedID = state.cameraFeedID; const paintedCells = state.paintedCells[cameraFeedID]; const regions = state.regionsByCamera[cameraFeedID]; const selectedRegionIndex = state.selectedRegionIndex; const mode = state.modeByCamera[cameraFeedID]; const { latestBitmapRef, isloading } = useCreateVideoSnapshot(); const [stageSize, setStageSize] = useState({ width: BACKEND_WIDTH, height: BACKEND_HEIGHT }); const isDrawingRef = useRef(false); const currentScale = stageSize.width / BACKEND_WIDTH; const size = BACKEND_CELL_SIZE * currentScale; // eslint-disable-next-line @typescript-eslint/no-explicit-any const paintLayerRef = useRef(null); const draw = (bmp: RefObject): ImageBitmap | null => { if (!bmp || !bmp.current) { return null; } const image = bmp.current; return image; }; const image = draw(latestBitmapRef); const paintCell = (x: number, y: number) => { const col = Math.floor(x / (size + gap)); const row = Math.floor(y / (size + gap)); if (row < 0 || row >= rows || col < 0 || col >= cols) return; const activeRegion = regions[selectedRegionIndex]; if (!activeRegion) return; const key = `${row}-${col}`; const currentColour = regions[selectedRegionIndex].brushColour; const map = paintedCells; const existing = map.get(key); if (mode === "eraser") { if (map.has(key)) { map.delete(key); paintLayerRef.current?.batchDraw(); } return; } if (existing && existing.colour === currentColour) return; map.set(key, { colour: currentColour, region: activeRegion }); paintLayerRef.current?.batchDraw(); }; const handleStageMouseDown = (e: KonvaEventObject) => { if (!regions[selectedRegionIndex]) return; isDrawingRef.current = true; const pos = e.target.getStage()?.getPointerPosition(); if (pos) paintCell(pos.x, pos.y); }; const handleStageMouseMove = (e: KonvaEventObject) => { if (!isDrawingRef.current) return; if (!regions[selectedRegionIndex]) return; const pos = e.target.getStage()?.getPointerPosition(); if (pos) paintCell(pos.x, pos.y); }; const handleStageMouseUp = () => { isDrawingRef.current = false; }; useEffect(() => { const handleResize = () => { const width = window.innerWidth; const aspectRatio = BACKEND_WIDTH / BACKEND_HEIGHT; console.log(window.innerWidth); if (width < 768) { const newWidth = width * 0.8; const newHeight = newWidth / aspectRatio; setStageSize({ width: newWidth, height: newHeight }); } else { const newWidth = width * 0.6; const newHeight = newWidth / aspectRatio; setStageSize({ width: newWidth, height: newHeight }); } }; handleResize(); window.addEventListener("resize", handleResize); return () => window.removeEventListener("resize", handleResize); }, []); if (image === null || isloading) return Loading Video feed…; return (
{ const cells = paintedCells; cells.forEach((cell, key) => { const [rowStr, colStr] = key.split("-"); const row = Number(rowStr); const col = Number(colStr); const x = col * (size + gap); const y = row * (size + gap); ctx.beginPath(); ctx.rect(x, y, size, size); ctx.fillStyle = cell.colour; ctx.fill(); }); ctx.fillStrokeShape(shape); }} width={stageSize.width} height={stageSize.height} />
); }; export default VideoFeedGridPainter;