确定绘制到画布中的形状/图形的边界

Posted

技术标签:

【中文标题】确定绘制到画布中的形状/图形的边界【英文标题】:Determine bounds of shape / graphics drawn into a Canvas 【发布时间】:2011-06-05 11:45:27 【问题描述】:

我有一个简单的 html5 Canvas 示例,它允许用户在画布上绘制路径。有没有办法确定绘制的路径/形状的矩形边界? (即路径周围矩形区域的宽度、高度是多少)。

我意识到我可以在绘制形状时进行数学计算以确定边界,但我想看看是否有更简单/内置的方法。

【问题讨论】:

使用fabric.js 将允许您将绘制的形状作为单个对象访问,包括其边界坐标。 如果您使用二次或三次贝塞尔曲线,您可以使用 De Casteljau 算法将它们分割成线,然后计算这些线的边界。您可以通过控制点的边界来近似边界,因为整个贝塞尔曲线位于其控制点的凸包中。 【参考方案1】:

我假设您正在使用lineTos,我能想到的唯一方法是在用户绘制路径时为高度和宽度存储一个最小值/最大值。除此之外,从画布中提取信息的唯一方法是使用getImageData,它只会为您提供原始像素信息。

显示此的快速示例

var ctx = document.getElementById("canvas").getContext("2d");
var xMin, xMax, yMin, yMax;

// These are set to where the path starts, i start them at 10,10
xMin = xMax = 10;
yMin = yMax = 10;

ctx.beginPath();
ctx.moveTo(10,10);

for(var i = 0; i <10; i++)
    var x = Math.floor(Math.random()*150),
        y = Math.floor(Math.random()*150);
        
    ctx.lineTo(x,y);
    if(x < xMin)
     xMin = x;   
    
    if(x > xMax)
     xMax = x;   
    
    
    if(y < yMin)
     yMin = y;   
    
    if(y > yMax)
     yMax = y;   
    

ctx.strokeStyle = "rgb(0,0,0)";
ctx.stroke();
ctx.closePath();      

ctx.strokeStyle = "rgb(255,0,0)";
ctx.strokeRect(xMin,yMin,xMax - xMin,yMax - yMin);  
#canvas
    width: 300px;
    height: 300px;
&lt;canvas id="canvas"&gt;&lt;/canvas&gt;

注意我只是创建了一堆随机点。要记住的主要事情是将最小/最大 vals 设置为用户创建的第一条路径的坐标。

我想你知道这一点,所以真正的答案是否定的,不幸的是目前没有内置的方法可以做到这一点..

【讨论】:

【参考方案2】:

受@Phrogz 的回答、Calculate bounding box of arbitrary pixel-based drawing 的回答以及他的两个略有不同的演示 http://phrogz.net/tmp/canvas_bounding_box.html 和 http://phrogz.net/tmp/canvas_bounding_box2.html 的启发,这里有一个不使用 alpha 通道的版本(在我的情况下它不起作用),而只是使用与白色的比较。

function contextBoundingBox(ctx)
    var w=ctx.canvas.width,h=ctx.canvas.height;
    var data = ctx.getImageData(0,0,w,h).data;
    var x,y,minX,minY,maxY,maxY;
    o1: for (y=h;y--;)        for (x=w;x--;)           if ((data[(w*y+x)*4] != 255) && (data[(w*y+x)*4+1] != 255) && (data[(w*y+x)*4+2] != 255))  maxY=y; break o1 
    o2: for (x=w;x--;)        for (y=maxY+1;y--;)      if ((data[(w*y+x)*4] != 255) && (data[(w*y+x)*4+1] != 255) && (data[(w*y+x)*4+2] != 255))  maxX=x; break o2 
    o3: for (x=0;x<=maxX;++x) for (y=maxY+1;y--;)      if ((data[(w*y+x)*4] != 255) && (data[(w*y+x)*4+1] != 255) && (data[(w*y+x)*4+2] != 255))  minX=x; break o3 
    o4: for (y=0;y<=maxY;++y) for (x=minX;x<=maxX;++x) if ((data[(w*y+x)*4] != 255) && (data[(w*y+x)*4+1] != 255) && (data[(w*y+x)*4+2] != 255))  minY=y; break o4 
    return x:minX,y:minY,maxX:maxX,maxY:maxY,w:maxX-minX,h:maxY-minY;

【讨论】:

【参考方案3】:

虽然您必须自己跟踪它,但我建议将其包装在可重用的功能中。这是一个最小的示例,仅针对moveTolineTo 进行跟踪。在此处查看实时示例:http://phrogz.net/tmp/canvas_bounding_box.html

function trackBBox( ctx )
  var begin = ctx.beginPath;
  ctx.beginPath = function()
    this.minX = this.minY = 99999999999;
    this.maxX = this.maxY = -99999999999;
    return begin.call(this);
  ;
  ctx.updateMinMax = function(x,y)
    if (x<this.minX) this.minX = x;
    if (x>this.maxX) this.maxX = x;
    if (y<this.minY) this.minY = y;
    if (y>this.maxY) this.maxY = y;
  ;
  var m2 = ctx.moveTo;
  ctx.moveTo = function(x,y)
    this.updateMinMax(x,y);
    return m2.call(this,x,y);
  ;
  var l2 = ctx.lineTo
  ctx.lineTo = function(x,y)
    this.updateMinMax(x,y);
    return l2.call(this,x,y);
  ;
  ctx.getBBox = function()
    return 
      minX:this.minX,
      maxX:this.maxX,
      minY:this.minY,
      maxY:this.maxY,
      width:this.maxX-this.minX,
      height:this.maxY-this.minY
    ;
  ;


...

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

// Cause the canvas to track its own bounding box for each path
trackBBox(ctx);
ctx.beginPath();
ctx.moveTo(40,40);
for(var i=0; i<10; i++) ctx.lineTo(Math.random()*600,Math.random()*400);

// Find the bounding box of the current path
var bbox = ctx.getBBox();
ctx.strokeRect(bbox.minX,bbox.minY,bbox.width,bbox.height);  

【讨论】:

以上是关于确定绘制到画布中的形状/图形的边界的主要内容,如果未能解决你的问题,请参考以下文章

将画布复制到 p5.js 中的图形对象

Javascript画布 - 矩形中的相交圆孔或如何合并多个圆弧路径

Android使用ontouch在画布上绘制矩形

如何在 KonvaJS 中的图层上绘制倒置元素

HTML5 中的 canvas 画布

如何在jetpack compose中为画布中的路径绘制阴影