### [Canvas 六边形棋盘:点击着色的做法](https://www.huociguo.com/article/1580) **Published:** 2026-10-01T10:43:46 **Author:** 米了 **Excerpt:** 一个 canvas 画整盘,靠坐标换算与点在多边形判定定位格子。含六边形布局计算、命中检测与三个性能要点。 棋盘类界面里,给每个格子建一个 canvas 是最容易想到的做法,代价是节点数暴涨、事件要逐个绑定。单个 canvas 承载整盘,靠坐标换算定位格子,节点只剩一个。 ![屏幕上的代码与反光,用于说明 Canvas 绘制与命中判定](https://api.huociguo.com/wp-content/uploads/2026/10/d3.jpg) 整盘绘制加一次命中判定,比逐格建节点更轻 ## 布局计算 ```js const R = 24; // 外接圆半径 const W = Math.sqrt(3) * R; // 横向间距 const H = 2 * R; // 格高 const rowGap = H * 0.75; // 纵向间距 function center(col, row) { const x = W * (col + (row % 2 ? 0.5 : 0)); const y = rowGap * row; return { x, y }; } ``` 尖顶六边形按行交错排布,奇数行整体右移半个格宽。绘制时按中心点依次连出六个顶点即可。 ## 命中检测 ```js function pointInPolygon(px, py, pts) { let inside = false; for (let i = 0, j = pts.length - 1; i < pts.length; j = i++) { const [xi, yi] = pts[i]; const [xj, yj] = pts[j]; if ((yi > py) !== (yj > py) && px < ((xj - xi) * (py - yi)) / (yj - yi) + xi) { inside = !inside; } } return inside; } ``` 射线法对任意多边形都成立。棋盘规模大时先按行列粗筛,只对候选格子做多边形判定,判定次数大幅下降。 ## 三个要点 1. 坐标换算要减去画布偏移。事件坐标减去 `getBoundingClientRect()` 的结果,得到画布内坐标。 2. 按 devicePixelRatio 放大位图。CSS 尺寸与位图尺寸分开设置,再用 scale 校正,否则边缘发虚。 3. 重绘只清一次画布。状态变更后整体重绘,增量擦除带来的残影比全量重绘更难处理。 ## 交互层 click 处理选中与着色,mousemove 处理悬停高亮,两者复用同一套命中逻辑。触屏环境补充 touchstart 的坐标读取,换算方式一致。 **Tags:** Canvas, 事件监听, 命中检测, 图形绘制, 网页性能 **Categories:** HTML5 ---