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

问题描述 投票:0回答:4

我有一个简单的 HTML5 Canvas 示例,可以让用户在画布上绘制路径。有什么方法可以确定所绘制的路径/形状的矩形边界吗? (即路径周围矩形区域的宽度和高度是多少)。

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

javascript html canvas drawing
4个回答
7
投票

我假设您正在使用

lineTo
,我能想到的唯一方法是在用户绘制路径时存储高度和宽度的最小/最大。除此之外,从画布中提取信息的唯一方法是使用
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;
}
<canvas id="canvas"></canvas>

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

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


5
投票

虽然您必须自己跟踪它,但我建议将其包装在可重用的功能中。这是一个最小的示例,仅跟踪

moveTo
lineTo
。请参阅此处的实时示例: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);  

0
投票

受到@Phrogz答案的启发,答案来自计算任意基于像素的绘图的边界框,以及他的两个略有不同的演示http://phrogz.net/tmp/canvas_bounding_box.htmlhttp://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};
}

0
投票

我们可以从fabric.js库中学习_calcBoundsFromPath方法。这是基于数学计算完成的。

https://github.com/fabricjs/fabric.js/blob/master/src/shapes/Path.ts

  _calcBoundsFromPath(): TBBox {}
© www.soinside.com 2019 - 2024. All rights reserved.