【问题标题】:detecting a click inside a hexagon drawn using canvas?检测使用画布绘制的六边形内的点击?
【发布时间】:2017-12-06 16:17:36
【问题描述】:

我正在处理某种布局,我需要在其中绘制一个需要可点击的六边形。我正在使用 Path2D 构造和 isPointInPath 函数。我正在构建一个动画,其中创建了许多六边形,然后每个移动到某个位置。移动完成后,我将 onclick 事件处理程序附加到某些六边形。但是有一些奇怪的行为。

一些已初始化的变量

const COLOR_DARK = "#73b6c6";
const COLOR_LIGHT = "#c3dadd";
const COLOR_PRIMARY = "#39a4c9";

const TYPE_PRIMARY = 'primary';

let hexagons = [];

下面是绘制六边形的函数。

function drawHex(ctx, x, y, hexProps, stroke, color) {

    let myPath = new Path2D();

    myPath.moveTo(x + hexProps.width*0.5, y);
    myPath.lineTo(x, y + hexProps.height*hexProps.facShort);
    myPath.lineTo(x, y + hexProps.height*hexProps.facLong);
    myPath.lineTo(x + hexProps.width*0.5, y + hexProps.height);
    myPath.lineTo(x + hexProps.width, y + hexProps.height*hexProps.facLong);
    myPath.lineTo(x + hexProps.width, y + hexProps.height*hexProps.facShort);
    myPath.lineTo(x + hexProps.width*0.5, y);
    myPath.closePath();

    if (stroke){
        ctx.strokeStyle = color;
        ctx.stroke(myPath);
    } else {
        ctx.fillStyle = color;
        ctx.fill(myPath);
    }

    return myPath;
}

这个函数填充六边形数组

function populateLeftHex(canvasWidth, canvasHeight, hexProps) {

const startX = canvasWidth / 2;
const startY = canvasHeight / 2;
const baseLeft = canvasWidth * 0.05;

for(let i = 0; i < 5; i++){
    let hexNumber = (i % 4 == 0)? 2: 1;

    for(let j = 0; j < hexNumber; j++){
        hexagons.push({
            startX: startX,
            startY: startY,
            endX: baseLeft + (2 * j) + ((i % 2 == 0)? (hexProps.width * j) : (hexProps.width/2)),
            endY: ((i + 1) * hexProps.height) - ((i) * hexProps.height * hexProps.facShort)  + (i* 2),
            stroke: true,
            color: ( i % 2 == 0 && j % 2 == 0)? COLOR_DARK : COLOR_LIGHT,
            type: TYPE_PRIMARY
        });
    }
}

}

这里是我调用 isPointInPath 函数的地方。

   window.onload = function (){
const c = document.getElementById('canvas');

const canvasWidth = c.width = window.innerWidth,
    canvasHeight = c.height = window.innerHeight,
    ctx = c.getContext('2d');

window.requestAnimFrame = (function (callback) {
    return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {
            window.setTimeout(callback, 1000 / 60);
        };
})();

console.log(canvasWidth);

let hexProps = {
  width: canvasWidth * 0.075,
    get height () {
      return this.width/Math.sqrt(3) + (1.5)*(this.width/Math.sqrt(2)/2);
    } ,
    facShort: 0.225,
    get facLong () {
      return 1 - this.facShort;
    }
};


populateLeftHex(canvasWidth, canvasHeight, hexProps);

let pct = 0;
const fps = 200;

animate();


function animate () {

    setTimeout(function () {
    // increment pct towards 100%
    pct += .03;

    // if we're not done, request another animation frame
    if (pct < 1.00) {
        requestAnimFrame(animate);
    } else { //if pct is no longer less than 1.00, then the movement animation is over.
        hexagons.forEach(function (hex) {
            if(hex.type === TYPE_PRIMARY) {

                console.info(hex.path);


                c.onclick = function(e) {

                    let x = e.clientX - c.offsetLeft,
                        y = e.clientY - c.offsetTop;
                    console.info(ctx.isPointInPath(hex.path, (e.clientX - c.offsetLeft), (e.clientY - c.offsetTop) ));
                };
            }
        })
    }

    ctx.clearRect(0, 0, c.width, c.height);

        // draw all hexagons
        for ( let i = 0; i < hexagons.length; i++) {

            // get reference to next shape
            let hex = hexagons[i];

            // note: dx/dy are fixed values
            // they could be put in the shape object for efficiency
            let dx = hex.endX - hex.startX;
            let dy = hex.endY - hex.startY;
            let nextX = hex.startX + dx * pct;
            let nextY = hex.startY + dy * pct;
            hex = hexagons[i];
            ctx.fillStyle = hex.color;
            hex.path = drawHex(ctx, nextX, nextY, hexProps, hex.stroke, hex.color);


        }

    }, 1000 / fps);
}

你能帮我弄清楚我做错了什么吗?也许我误解了 Path2D 的工作原理?提前致谢。

【问题讨论】:

  • 您绘制的多条路径(六边形)正确吗?我不认为这是最好的方法。 isPointInPath() 只会告诉你一个点是否在当前路径中。您必须在绘图时检查该点。您的代码现在的工作方式,它只会检查点击是否在最后绘制的六边形中。至少,我是这样理解文档的。
  • 没错,drawHex函数绘制了一个六边形。但我多次调用它。现在发生了一种奇怪的行为......我正在构建一个复杂的动画......我会更新问题

标签: javascript html canvas html5-canvas path-2d


【解决方案1】:

由于您的示例不完整,因此必须做一些工作来构建测试页面,但这对我有用-尽管我的六边形是凹的...

var myCanvas = document.getElementById("myCanvas");
var ctx = myCanvas.getContext("2d");

var hexProps = {width:100, height:100, facShort:-2, facLong:10};

var hexagons = [];

 function drawHex(ctx, x, y, hexProps, stroke, color) {

     let myPath = new Path2D();

     myPath.moveTo(x + hexProps.width*0.5, y);
     myPath.lineTo(x, y + hexProps.height*hexProps.facShort);
     myPath.lineTo(x, y + hexProps.height*hexProps.facLong);
     myPath.lineTo(x + hexProps.width*0.5, y + hexProps.height);
     myPath.lineTo(x + hexProps.width, y + hexProps.height*hexProps.facLong);
     myPath.lineTo(x + hexProps.width, y + hexProps.height*hexProps.facShort);
     myPath.lineTo(x + hexProps.width*0.5, y);
     myPath.closePath();

     if (stroke){
         ctx.strokeStyle = color;
         ctx.stroke(myPath);
     } else {
         ctx.fillStyle = color;
         ctx.fill(myPath);
     }

     return myPath;
 }

hexagons.push({type:0, path:drawHex(ctx,100,100,hexProps,false,"#0f0")});

   hexagons.forEach(function (hex) {
            if(hex.type === 0) {

                console.info(hex.path);


                myCanvas.onclick = function(e) {

                    let x = e.clientX - myCanvas.offsetLeft,
                        y = e.clientY - myCanvas.offsetTop;
                    console.info(x,y);
                    console.info(ctx.isPointInPath(hex.path, (e.clientX - 
 myCanvas.offsetLeft), (e.clientY - myCanvas.offsetTop) ));

                };
            }
        })
&lt;canvas width=500 height=500 id=myCanvas style='border:1px solid red'&gt;&lt;/canvas&gt;

测试点击在预期的地方给出真假:

test.htm:48 165 168
test.htm:49 true
test.htm:48 151 336
test.htm:49 false
test.htm:48 124 314
test.htm:49 true
test.htm:48 87 311
test.htm:49 false

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 2015-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多