Javascript 在画布上绘制六边形,测试鼠标单击事件与六边形
我正在画布上画一个六边形网格 每个六边形都是一个在x/y坐标中保持6个点的对象。 每个六边形对象还保存其X/Y列/行索引Javascript 在画布上绘制六边形,测试鼠标单击事件与六边形,javascript,html,math,canvas,hexagonal-tiles,Javascript,Html,Math,Canvas,Hexagonal Tiles,我正在画布上画一个六边形网格 每个六边形都是一个在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 globalOf
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);
}
var canvas=document.getElementById(“can”);
画布宽度=200;
画布高度=200;
var ctx=canvas.getContext(“2d”);
变量网格=[];//包含十六进制的数组
var globalOffset=30//不重要,只是为了更平滑的显示
功能点(x,y){
这个.x=x;
这个。y=y;
}
函数十六进制(x、y、大小){
这个尺寸=20;
这个.x=x;
这个。y=y;
此参数为.points=[];
this.id=[];
this.create=函数(x,y){
var offSetX=(大小/2*x)*-1
var offSetY=0;
如果(x%2==1){
offSetY=Math.sqrt(3)/2*this.size;
}
var中心=新点(
x*this.size*2+偏移量x+全局偏移量,
y*Math.sqrt(3)/2*this.size*2+偏移量+全局偏移量
)
这个。中点=中心;
这个.id[0]=x;
this.id[1]=y;
对于(变量i=0;i<6;i++){
变量度=60*i;
var弧度=Math.PI/180*度;
var点=新点(
中心x+尺寸*数学cos(弧度),
中心.y+大小*数学.sin(弧度)
)
这个。点。推(点);
}
}
创建(x,y);
}
}
//确定单击的位置
canvas.addEventListener(“单击”,函数(e){
var rect=canvas.getBoundingClientRect();
var pos={
x:e.clientX-右左,
y:e.clientY-rect.top
}
document.getElementById(“pos”).innerHTML=“单击:”+pos.x+”+pos.y;
});
//创建六边形,设置其中心点,将其推入网格。
函数init(){
对于(变量i=0;i<5;i++){
对于(var j=0;j<4;j++){
var hex=新的hex(i,j,20);
网格推送(十六进制)
}
}
//对于网格中的每个十六进制,绘制十六进制
用于(网格中的var十六进制){
var项目=网格[十六进制];
ctx.beginPath();
ctx.moveTo(item.points[0].x,item.points[0].y);
对于(变量k=1;k
在画布上单击时,我想确定是否单击了十六进制,如果单击了,则确定是哪个十六进制(按列/行)。
这是一道数学题
我该怎么做
这里有一个完整的工作示例:
如果将六边形中心视为圆心,则单击的六边形的中心距单击最近。(应该可以在不测试到每个可能单元的距离的情况下对此进行优化) 为了解释不完全覆盖,假设在可见六边形周围的附加环中有更多(不可见)六边形 如果选择了其中一个,或者距离大于圆半径,则单击不在可见六边形上 在某种程度上基于您自己提出的代码重构,避免两个循环,因为唯一的好处是消除单个
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
}
Grid.prototype.getHexAt=函数(pos){
var=null;
var min=无穷大;
grid.hexes.forEach(函数(十六进制){
var dx=六角中心x-位置x;
变量dy=六角中心y-位置y;
变量距离=数学sqrt(v.x*v.x+v.y*v.y);
if(距离<十六进制尺寸和距离<最小值){
最小值=距离;
最近=十六进制;
}
});
返回最近;//可能返回null
}
有趣的是,阿尔尼塔克的建议是相当好的,因为六边形实际上有点像圆。
这是我的职责。
将鼠标事件位置x/y与每个六边形圆和六边形固有尺寸(宽度/高度)进行比较。
如果鼠标位置x/y+六边形尺寸接近六边形中心,您可能单击了此六边形。
仍然针对所有六边形进行测试。如果您“接近”多个六边形,则获得鼠标轨迹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;
};
Grid.prototype.getHexAt=函数(pos){
var inRange=[];
var=null;
for(网格中的var hex.hexes){
var项目=网格。十六进制[十六进制];
var center=item.center;
if(center.x+item.size>pos.x&¢er.x-item.sizepos.y&¢er.y-item.size1){
var-pick=null;
var-dist=null;
对于(变量i=0;i
你能建议在事件监听器中使用特定的代码吗?不,恐怕不是代码编写服务。我建议了一个算法,应该足以让你开始…这里有许多关于jex网格的线索:这不太正确-你应该使用从毕达哥拉斯到sqrt的笛卡尔距离(x^2+y^2)-而不是仅仅添加x+y
。除非您在该代码之外添加了一个额外的六边形环,否则您还会发现,如果您在网格之外的落下圆的60度径向扇区中单击,它会发出错误的单击