在 Canvas 上绘制 Hexagon,测试 mouseclick 事件与 Hexagon
Posted
技术标签:
【中文标题】在 Canvas 上绘制 Hexagon,测试 mouseclick 事件与 Hexagon【英文标题】:Drawing Hexagon on Canvas, testing mouseclick event vs Hexagon 【发布时间】:2016-05-04 08:36:31 【问题描述】:我正在画布上绘制一个基于六边形的网格。
每个六边形都是一个对象,其中包含 x/y 坐标中的 6 个点。 每个六边形对象还保存其 X/Y 列/行索引。
var canvas = document.getElementById("can");
canvas.width = 200;
canvas.height = 200;
var ctx = canvas.getContext("2d");
var grid = []; // array that holds the Hex
var globalOffset = 30 // not important, just for smoother display atm
function Point(x, y)
this.x = x;
this.y = y;
function Hex(x, y, size)
this.size = 20;
this.x = x;
this.y = y;
this.points = [];
this.id = [];
this.create = function(x, y)
var offSetX = (size / 2 * x) * -1
var offSetY = 0;
if (x % 2 == 1)
offSetY = Math.sqrt(3) / 2 * this.size;
var center = new Point(
x * this.size * 2 + offSetX + globalOffset,
y * Math.sqrt(3) / 2 * this.size * 2 + offSetY + globalOffset
)
this.midPoint = center;
this.id[0] = x;
this.id[1] = y;
for (var i = 0; i < 6; i++)
var degree = 60 * i;
var radian = Math.PI / 180 * degree;
var point = new Point(
center.x + size * Math.cos(radian),
center.y + size * Math.sin(radian)
)
this.points.push(point);
this.create(x, y);
//Determine where was clicked
canvas.addEventListener("click", function(e)
var rect = canvas.getBoundingClientRect();
var pos =
x: e.clientX - rect.left,
y: e.clientY - rect.top
document.getElementById("pos").innerhtml = "click on: " + pos.x + " " + pos.y;
);
// Creating Hexagons, setting up their center point, pushing them into Grid.
function init()
for (var i = 0; i < 5; i++)
for (var j = 0; j < 4; j++)
var hex = new Hex(i, j, 20);
grid.push(hex)
//for each Hex in Grid, draw the Hex
for (var hex in grid)
var item = grid[hex];
ctx.beginPath();
ctx.moveTo(item.points[0].x, item.points[0].y);
for (var k = 1; k < item.points.length; k++)
ctx.lineTo(item.points[k].x, item.points[k].y);
ctx.closePath();
ctx.stroke();
var text = item.id;
ctx.fillStyle = "black";
ctx.fillText(text, item.midPoint.x - 7, item.midPoint.y - item.size / 2.2);
点击画布时,我想确定我是否点击了一个十六进制,如果我点击了,是哪个十六进制(按列/行)。 它的数学问题。
我该怎么做?
这里的完整工作示例: http://codepen.io/anon/pen/RrMzKy?editors=1111
【问题讨论】:
这里有很多jex网格的线索:redblobgames.com/grids/hexagons 【参考方案1】:如果您将六边形中心视为圆心,则被点击的六边形是其中心最接近点击的六边形。 (应该可以在不测试到每个可能单元格的距离的情况下对其进行优化)。
为了解释不完整的覆盖范围,假设在可见六边形周围的附加环中有更多(不可见)六边形。
如果选择其中之一,或者如果距离大于圆半径,则点击不在可见的六边形上。
在某种程度上基于您自己提议的代码的重构,并避免了两个循环,因为唯一的好处是消除了单个 sqrt
函数:
Grid.prototype.getHexAt = function(pos)
var closest = null;
var min = Infinity;
grid.hexes.forEach(function(hex)
var dx = hex.center.x - pos.x;
var dy = hex.center.y - pos.y;
var distance = Math.sqrt(v.x * v.x + v.y * v.y);
if (distance < hex.size && distance < min)
min = distance;
closest = hex;
);
return closest; // may return null
【讨论】:
您能建议在事件监听器中使用的特定代码吗? 不,恐怕 SO 不是代码编写服务。我建议了一个算法,应该足以让你开始......【参考方案2】:有趣的是,Alnitak 的建议相当不错,因为六边形确实有点像圆形。 这是我的功能。 将 mousevent 位置 x/y 与每个 Hexagons 圆和 Hexagon 固有大小(宽度/高度)进行比较。 鼠标位置 x/y + 六边形大小是否接近六边形中心,您可能点击了这个六边形。 仍然针对所有 Hexagon 进行测试。如果您“接近”多个,请获取鼠标路线 x/y 与所有有效六边形圆圈的矢量距离。向量最短的六边形就是你点击的那个。
Grid.prototype.getHexAt = function(pos)
var inRange = [];
var closest = null;
for (var hex in grid.hexes)
var item = grid.hexes[hex];
var center = item.center;
if (center.x + item.size > pos.x && center.x - item.size < pos.x)
if (center.y + item.size > pos.y && center.y - item.size < pos.y)
inRange.push(item);
if (inRange.length > 1)
var pick = null;
var dist = null;
for (var i = 0; i < inRange.length; i++)
var vector =
x: inRange[i].center.x - pos.x,
y: inRange[i].center.y - pos.y
;
if (vector.x < 0)
vector.x *= -1;
if (vector.y < 0)
vector.y *= -1;
if (pick == null || vector.x + vector.y < dist)
pick = inRange[i];
dist = vector.x + vector.y;
closest = pick;
else
closest = inRange[0];
return closest;
;
【讨论】:
这不太对——你应该使用与毕达哥拉斯的笛卡尔距离——sqrt(x^2 + y^2)
——而不是仅仅添加x + y
。除非您在此代码之外添加了额外的六边形环,否则您还会发现,如果您在位于最外面的六边形之外的圆的 60 度径向扇区中的网格外单击,它会发出错误的点击。 以上是关于在 Canvas 上绘制 Hexagon,测试 mouseclick 事件与 Hexagon的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Flutter 的 Canvas 上绘制 Widget?
android安卓setShadowLayer canvas绘制矩形阴影 在电脑模拟器上能显示效果 但是到了手机上却没了阴影效果