All files / src/widgets/canvas/ui GridCanvas.tsx

92.59% Statements 50/54
63.63% Branches 7/11
75% Functions 3/4
100% Lines 45/45

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';