【问题标题】:How to select HTML5 canvas shapes?如何选择 HTML5 画布形状?
【发布时间】:2017-09-11 06:47:44
【问题描述】:

我有一个 HTML5 画布,我在上面绘制了几个形状。

我想要发生的是,当鼠标单击任何形状时,应该选择该形状(至少它可以判断选择了哪种形状)。

谢谢。

【问题讨论】:

  • 你可以使用像 fabric.js 这样的画布库。

标签: javascript html canvas html5-canvas


【解决方案1】:

尝试使用现有的画布库(或创建您自己的),该库在选择形状时具有事件。

下面的例子使用Kinetic JS library,下面的例子来自HTML5 Canvas Region Events Example

var triangle = new Kinetic.Shape(function(){
    var context = this.getContext();
    context.beginPath();
    context.lineWidth = 4;
    context.strokeStyle = "black";
    context.fillStyle = "#00D2FF";
    context.moveTo(120, 50);
    context.lineTo(250, 80);
    context.lineTo(150, 170);
    context.closePath();
    context.fill();
    context.stroke();
});

triangle.on("mouseout", function(){
    writeMessage(messageLayer, "Mouseout triangle");
});

triangle.on("mousemove", function(){
    var mousePos = stage.getMousePosition();
    var x = mousePos.x - 120;
    var y = mousePos.y - 50;
    writeMessage(messageLayer, "x: " + x + ", y: " + y);
});

shapesLayer.add(triangle);

var circle = new Kinetic.Shape(function(){
    var canvas = this.getCanvas();
    var context = this.getContext();
    context.beginPath();
    context.arc(380, canvas.height / 2, 70, 0, Math.PI * 2, true);
    context.fillStyle = "red";
    context.fill();
    context.lineWidth = 4;
    context.stroke();
});

circle.on("mouseover", function(){
    writeMessage(messageLayer, "Mouseover circle");
});
circle.on("mouseout", function(){
    writeMessage(messageLayer, "Mouseout circle");
});
circle.on("mousedown", function(){
    writeMessage(messageLayer, "Mousedown circle");
});
circle.on("mouseup", function(){
    writeMessage(messageLayer, "Mouseup circle");
});

shapesLayer.add(circle);

stage.add(shapesLayer);
stage.add(messageLayer);


此外,如果光标在形状内,我已经包含了一些鼠标进入检测,而不使用任何 javascript 库。

基于矩形的鼠标进入检测:

function isCursorWithinRectangle(x, y, width, height, mouseX, mouseY) {
    if(mouseX > x && mouseX < x + width && mouseY > y && mouseY < y + height) {
        return true;
    }
    return false;
}


基于圆圈的鼠标检测:

function isCursorWithinCircle(x, y, r, mouseX, mouseY) {
    var distSqr = Math.pow(x - mouseX, 2) + Math.pow(y - mouseY, 2);

    if(distSqr < r * r) {
        return true;
    }
    return false;
}

【讨论】:

    【解决方案2】:

    有一种非常简单的方法可以选择具有像素精度的复杂形状,不涉及边界矩形或数学计算。

    这个想法是将所有形状复制到隐藏的辅助画布上,在其中为每个形状分配独特的颜色。当您在原始画布上执行鼠标悬停或单击事件时,您会保存与可见画布相关的鼠标 (x, y) 坐标,然后使用这些相同坐标在隐藏画布上查找像素颜色。因为每个形状在隐藏的画布上都有一个独特的颜色,所以该颜色对应于用户选择的确切形状。

    请注意,这仅支持大约 1670 万个形状,因为 RGB 只有 24 位颜色,但这应该绰绰有余。

    这是一个使用 D3 和 Canvas 的简单示例:http://bl.ocks.org/syntagmatic/6645345

    【讨论】:

    • 还有 alpha 通道,我们可以从中获得 ~4b 种不同的颜色
    • 是和不是。如果绘制重叠对象,则不能使用 Alpha 通道,因为 RGBA 颜色会混合在一起。
    • 更新:我使用这个方法有一段时间,我注意到如果鼠标在形状的边缘,那么它的颜色会与形状的颜色不同,然后会选择其他对象。但是,我使用距离 = 4,这对我来说似乎没问题。但在未来我认为我必须创建一些距离函数来消除错误选择。
    • 问题出在抗锯齿上。据我所知,您不能真正禁用抗锯齿,因此没有简单的解决方案。 stackoverflow.com/questions/195262/…
    【解决方案3】:

    Canvas 没有像 DOM 那样的 elements 接口。它仅用于绘图。

    您需要将资产创建为对象并使用绘图循环来绘制它们。然后你就忘记了canvas 元素,你使用你的对象,它们的偏移量等等。

    【讨论】:

      猜你喜欢
      • 2018-07-24
      • 1970-01-01
      • 1970-01-01
      • 2013-09-30
      • 2018-01-04
      • 2012-08-14
      • 2017-09-11
      • 1970-01-01
      • 2011-04-12
      相关资源
      最近更新 更多