Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | 1x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 73x 73x 73x 73x 3x 63x 63x 63x 63x 3x 3x 3x 17x 3x 12x 3x 3x 3x 3x 3x 3x 3x 3x 2x 1x 1x 1x | import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react';
interface GridCanvasProps {
width: number;
height: number;
showGrid: boolean;
background?: string;
}
export const GridCanvas = forwardRef<HTMLCanvasElement, GridCanvasProps>(
({ width, height, showGrid, background = '#ffffff' }, ref) => {
const canvasRef = useRef<HTMLCanvasElement | null>(null);
// buffer. draw a grid one time
const bufferRef = useRef<HTMLCanvasElement | null>(null);
useImperativeHandle(ref, () => canvasRef.current as HTMLCanvasElement, []);
// create buffer
useEffect(() => {
const buf = document.createElement('canvas');
buf.width = width;
buf.height = height;
bufferRef.current = buf;
const ctx = buf.getContext('2d');
Iif (!ctx) return;
ctx.fillStyle = background;
ctx.fillRect(0, 0, width, height);
const GRID = 20;
const LABEL = 100;
ctx.strokeStyle = '#e5e7eb';
ctx.lineWidth = 1;
for (let x = 0; x <= width; x += GRID) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, height);
ctx.stroke();
}
for (let y = 0; y <= height; y += GRID) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(width, y);
ctx.stroke();
}
ctx.fillStyle = '#9ca3af';
ctx.font = '10px sans-serif';
ctx.textBaseline = 'top';
for (let x = 0; x <= width; x += LABEL) ctx.fillText(String(x), x + 2, 2);
for (let y = LABEL; y <= height; y += LABEL)
ctx.fillText(String(y), 2, y + 2);
}, [width, height, background]);
// buffer to canvas
useEffect(() => {
const canvas = canvasRef.current;
const buf = bufferRef.current;
Iif (!canvas || !buf) return;
const ctx = canvas.getContext('2d');
Iif (!ctx) return;
ctx.clearRect(0, 0, width, height);
if (showGrid) {
ctx.drawImage(buf, 0, 0);
} else {
ctx.fillStyle = background;
ctx.fillRect(0, 0, width, height);
}
}, [showGrid, width, height, background]);
return (
<canvas
ref={canvasRef}
width={width}
height={height}
className="absolute inset-0 pointer-events-none"
data-testid="grid-canvas"
/>
);
},
);
GridCanvas.displayName = 'GridCanvas';
|