javascript - 在 Canvas 上绘制六边形,测试鼠标单击事件与六边形

标签 javascript html math canvas hexagonal-tiles

我正在 Canvas 上绘制一个基于六边形的网格。

每个六边形都是一个包含 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);

  }

当单击 Canvas 时,我想确定是否单击了十六进制,如果单击了,则确定是哪个十六进制(按列/行)。 这是数学问题。

我该怎么做?

这里有完整的工作示例: http://codepen.io/anon/pen/RrMzKy?editors=1111

最佳答案

如果将六边形中心视为圆心,则单击的六边形是其中心最接近单击的六边形。 (应该可以优化这一点,而无需测试到每个可能的单元的距离)。

为了解决不完全覆盖的问题,假设在可见六边形周围的附加环中有更多(不可见)六边形。

如果选择其中之一,或者距离大于圆半径,则点击不在可见的六边形上。

某种程度上基于您自己建议的代码的重构,并避免了两个循环,因为唯一的好处是消除了单个 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
}

关于javascript - 在 Canvas 上绘制六边形,测试鼠标单击事件与六边形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35036585/

相关文章:

php - 为什么有些 PHP 电子邮件正文包含周围的 html 代码,而其他则没有?那不是 PHPMailer

html - html 通讯中的图像叠加表

javascript - 如何对具有相同 ID 的不同元素使用 datetimepicker()

mysql - 有没有办法对 MySQL 查询进行数学运算?

c# - C# 中的复杂计算

javascript - 如何捕获 SSE Eventsource 确认

javascript - AngularJS和FileReader如何将文件保存到路径

如果输入框未填充,Javascript 隐藏 HTML 文本

algorithm - 2 ^ n 的相反数

javascript - 如果不满足要求则停止行动