import React, { useEffect, useRef } from 'react'; import type { SceneGrid } from '../../../shared/types'; import styles from './SceneGridOverlay.module.css'; type Viewport = { x: number; y: number; w: number; h: number }; type Props = { grid: SceneGrid | null | undefined; viewport: Viewport | null; }; function drawSquareGrid( ctx: CanvasRenderingContext2D, w: number, h: number, cell: number, ): void { ctx.beginPath(); for (let x = 0; x <= w + 0.5; x += cell) { ctx.moveTo(x + 0.5, 0); ctx.lineTo(x + 0.5, h); } for (let y = 0; y <= h + 0.5; y += cell) { ctx.moveTo(0, y + 0.5); ctx.lineTo(w, y + 0.5); } ctx.stroke(); } /** Flat-top hex grid; `cell` ≈ ширина гекса (расстояние между параллельными сторонами по X ≈ 0.75·cell между центрами). */ function drawHexGrid(ctx: CanvasRenderingContext2D, w: number, h: number, cell: number): void { const hexW = cell; const vert = (Math.sqrt(3) / 2) * hexW; const horiz = hexW * 0.75; const r = hexW / 2; ctx.beginPath(); const cols = Math.ceil(w / horiz) + 2; const rows = Math.ceil(h / vert) + 2; for (let row = -1; row < rows; row++) { for (let col = -1; col < cols; col++) { const cx = col * horiz; const cy = row * vert + (col % 2 === 0 ? 0 : vert / 2); for (let i = 0; i < 6; i++) { const a = (Math.PI / 3) * i; const x = cx + r * Math.cos(a); const y = cy + r * Math.sin(a); if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y); } ctx.closePath(); } } ctx.stroke(); } export function SceneGridOverlay({ grid, viewport }: Props) { const canvasRef = useRef(null); useEffect(() => { const canvas = canvasRef.current; if (!canvas || !viewport || !grid?.enabled) return; const dpr = Math.max(1, Math.min(2, window.devicePixelRatio || 1)); const w = Math.max(1, Math.round(viewport.w)); const h = Math.max(1, Math.round(viewport.h)); canvas.width = Math.round(w * dpr); canvas.height = Math.round(h * dpr); canvas.style.width = `${w}px`; canvas.style.height = `${h}px`; const ctx = canvas.getContext('2d'); if (!ctx) return; ctx.setTransform(dpr, 0, 0, dpr, 0, 0); ctx.clearRect(0, 0, w, h); const minDim = Math.min(w, h); const cell = Math.max(4, grid.sizeN * minDim); ctx.strokeStyle = grid.color || '#ffffff'; ctx.lineWidth = 1; ctx.globalAlpha = 0.72; if (grid.type === 'hex') { drawHexGrid(ctx, w, h, cell); } else { drawSquareGrid(ctx, w, h, cell); } }, [ grid?.enabled, grid?.type, grid?.sizeN, grid?.color, viewport?.x, viewport?.y, viewport?.w, viewport?.h, ]); if (!viewport || !grid?.enabled) return null; return (
); }