2

在画布中,我创建了一个 2d 上下文。在那种情况下......有一个功能......我能够创建一些“圆形对象”。现在,我想要的是获取单个圆形对象的 ImageData,而不是整个上下文的图像数据。

在下面的代码中,你可以看到我的愿望被注释掉了。

var c = document.getElementById('canvas');
var ctx = c.getContext('2d');

var circle = function (X,Y) {
    var that = this;
    that.X = X;
    that.Y = Y;
    that.clicked = function(e) {
        //
        //
        //!!!!!!!!!!!!!!
        // Code below works fine, on context level
        imgData = ctx.getImageData(e.pageX, e.pageY, 1, 1);
        //
        // Code below is at the level of the circle, that's what I want, but isn't working
        imgData = that.getImageData(e.pageX, e.pageY, 1, 1);
        //!!!!!!!!!!!!!!
        //
        //
        alert(imgData.data[3]);
    }
    that.draw = function () {
        ctx.save();
        ctx.translate(that.X, that.Y);
        ctx.fillStyle = '#33cc33';
        ctx.beginPath();
        ctx.arc(0, 0, 50, 0, 2 * Math.PI);
        ctx.fill();
        ctx.stroke();
        ctx.restore();
    }
}
var circles = new Array();
circles.push(new circle(50,50));
document.addEventListener('click',function() {
    circles.forEach(function(circ,index){
        circ.clicked();
    });
})

那么,如何获取特定对象的图像数据呢?

编辑: 我知道我需要先画圆,我稍后在我的代码中这样做,但是如果我在上下文中有一个背景矩形,当我点击圆旁边时,它会得到的 imageData背景矩形,当我想返回 alpha rgba 的 0 值时。

4

5 回答 5

4

为此,您需要将所有绘图记录为“阴影画布”。最常见的方法是创建形状对象并将它们存储在例如数组中:

  • 在画布上绘制形状
  • 记录其类型、位置、尺寸、颜色和方向并将其存储为对象并将该对象推送到数组

当您需要获取孤立的形状或对象作为图像时:

  • 获取鼠标位置(如果要单击对象以选择它)
  • 迭代对象数组以查看哪个对象被“命中”
  • 创建该形状尺寸的临时画布
  • 将形状绘制到临时画布中
  • 将数据提取为图像(ctx.getImageData(x, y, w, h)canvas.toDataURL()

当您需要调整画布大小时,您只需迭代所有对象并重新绘制它们。您甚至可以使用此方法序列化数据以进行存储。

对象的示例可以是:

function Rectangle(x, y, w, h, fill, stroke) {
    this.x = x;
    this.y = y;
    this.width = w;
    this.height = h;
    this.fill = fill;
    this.stroke = stroke;
}

您可以扩展此对象以将其自身呈现到画布上,并为您提供与其他形状隔离的自身位图。将此添加到上面的代码中:

Rectangle.prototype.render = function(ctx) {
    if (this.fill) {                  /// fill only if fill is defined
        ctx.fillStyle = this.fill;
        ctx.fillRect(this.x, this.y, this.width, this.height);
    }
    if (this.stroke) {                /// stroke only if stroke is defined
        ctx.strokeStyle = this.stroke;
        ctx.strokeRect(this.x, this.y, this.width, this.height);
    }
}

Rectangle.prototype.toBitmap = function() {

    var tcanvas = document.createElement('canvas'),  /// create temp canvas
        tctx = tcanvas.getContext('2d');             /// temp context

    tcanvas.width = this.width;         /// set width = shape width
    tcanvas.height = this.height;
    tctx.translate(-this.x, -this.y);   /// make sure shape is drawn at origin

    this.render(tcxt);                  /// render itself to temp context

    return tcanvas.toDataURL();         /// return image (or use getImageData)
}

您只需绘制形状,根据位置创建对象等:

var rect = new Rectangle(x, y, w, h, fillColor, strokeColor);

myShapeArray.push(rect);

当您需要渲染形状时:

for(var i = 0, shape; shape = myShapeArray[i++];)
    shape.render(ctx);

当您需要获取它的位图时(您通过鼠标单击提前检索了它的索引):

var image = myShapeArray[index].toBitmap();

当然:您可以为圆、线等制作类似的对象。

希望这可以帮助!

于 2014-02-10T23:55:51.503 回答
1

请记住,Canvas 是一种位图图形工具。您在单个上下文中绘制的任何内容都将成为同一对象的一部分。您无法为您用来在该画布上绘制的每个“对象”获取单独的图像数据......它被绘制......扁平化......一旦你点击draw().

您可以做类似您正在寻找的事情的唯一方法是创建单独的画布上下文,您可以将它们叠加在一起。这可以通过使用 KineticJS ( http://www.html5canvastutorials.com/kineticjs/html5-canvas-events-tutorials-introduction-with-kineticjs/ ) 之类的库来更好地处理。唯一的其他选择是使用面向对象的绘图工具,例如 SVG(通过 Raphael.js,例如:http ://raphaeljs.com ),它确实在图形空间中保留了单独的对象。

有关 getImageData 的参考,请参阅http://www.html5canvastutorials.com/advanced/html5-canvas-get-image-data-tutorial/

于 2014-02-10T14:44:57.763 回答
1

您可以使用三角函数而不是尝试使用 getImageData 定位颜色。

例如,如果你有一个这样定义的圆圈:

var centerX=150;
var centerY=150;
var radius=20;
var circleColor="red";

然后您可以测试是否有任何 x,y 在该圆圈内,如下所示:

// returns true if x,y is inside the red circle
isXYinCircle(140,140,centerX,centerY,radius);

function isXYinCircle(x,y,cx,cy,r){
    var dx=x-cx;
    var dy=y-cy;
    return(dx*dx+dy*dy<=r*r);
}

如果 x,y 在那个红色圆圈内,那么您知道 x,y 处的颜色是“红色”

如果您有多个重叠的圆圈,您可以按递增的 z-index 顺序测试每个圆圈。最后一个在内部报告 x,y 的圆圈将是 x,y 处的颜色。

于 2014-02-10T16:02:57.190 回答
0

这是因为that不是CanvasGraphicsContext. 尝试:

that.draw();
imgData = ctx.getImageData(e.pageX, e.pageY, 1, 1);
于 2014-02-10T14:40:26.260 回答
0

首先,我创建了我的 2 个画布元素。1 显示,1 计算像素数据。

var c = document.getElementById('canvas');
var c2 = document.getElementById('canvas2');
var ctx = c.getContext('2d');
var ctx2 = c2.getContext('2d');

var width = window.innerWidth,
    height = window.innerHeight;

c.width = ctx.width = c2.width = ctx2.width = width;
c.height = ctx.height = c2.height = ctx2.height = height;

比我创建图像的功能

function Afbeelding(src, X, Y, W, H) {
    var that = this;
    that.X = X;
    that.Y = Y;
    that.W = W;
    that.H = H;
    that.onClick = function () { };
    that.image = new Image(that.W, that.H);
    that.image.src = src;
    that.draw = function (context) { 
        context = (typeof context != 'undefined') ? context : ctx;
        context.save();
        context.translate(that.X, that.Y);
        context.drawImage(that.image, 0, 0, that.W, that.H);
        context.restore();
    }

当触发 document.click 事件时,将调用下一个函数(在 Afbeelding 函数内):

that.clicked = function (e) {
    if ((e.pageX > that.X - (that.W / 2) && e.pageX < that.X + (that.W / 2)) && (e.pageY > that.Y - (that.H / 2) && e.pageY < that.Y + (that.H / 2))) {
        if (that.isNotTransparent(e)) {
            that.onClick();
        }
    }
}

此函数(也在 Afbeelding 函数内部)用于检查像素的透明度。

    that.isNotTransparent = function (e) {
        var result = false;
        ctx2.clearRect(0, 0, width, height);
        that.draw(ctx2);
        var imgData = ctx2.getImageData(e.pageX, e.pageY, 1, 1);
        ctx2.clearRect(0, 0, width, height);
        if (imgData.data[3] > 0) {
            result = true;
        }
        return result;
    }
}

而下面的一切都是为了把上面的东西放在上面。

var items = new Array();

var afb = new Afbeelding();
afb.draw();
afb.onClick = function () {
    alert('clicked');
}
items.push(afb);


document.addEventListener('mousedown', function (e) {
    items.forEach(function (item, index) {
        item.clicked(e);
    });
});
于 2014-02-12T14:50:27.183 回答