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

发布于 2024-10-10 18:19:36 字数 145 浏览 2 评论 0原文

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

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

I have a simple HTML5 Canvas example that lets the user draw paths onto a canvas. Is there any way to determine the rectangular bounds of the path / shape that was drawn? (i.e., what is the width, height of the rectangular region surrounding the path).

I realize I could do the math while the shape is being drawn to figure out the bounds, but I wanted to see if there was an easier / built in way.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

千柳 2024-10-17 18:19:37

尽管您必须自己跟踪它,但我建议将其包装在可重用的功能中。这是一个最小的示例,仅跟踪 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);  

Although you have to track it yourself, I would suggest wrapping it up in reusable functionality. Here's a minimal example, tracking it only for moveTo and lineTo. See the live example here: 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);  
你好,陌生人 2024-10-17 18:19:37

受到@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};
}

Inspired by @Phrogz's answer, the answer from Calculate bounding box of arbitrary pixel-based drawing, and his two slightly different demos http://phrogz.net/tmp/canvas_bounding_box.html and http://phrogz.net/tmp/canvas_bounding_box2.html, here is a version not using the alpha channel (it did not work in my case) but just using a comparison to white color.

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};
}
世界如花海般美丽 2024-10-17 18:19:37

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

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

  _calcBoundsFromPath(): TBBox {}

We can learn the _calcBoundsFromPath method from the fabric.js library.This is done based on mathematical calculations.

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

  _calcBoundsFromPath(): TBBox {}
随风而去 2024-10-17 18:19:36

我假设您正在使用 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>

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

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

I assume you are using lineTos the only way I could think of would be to keep a min/max stored for the height and width as the user is drawing paths. Other than that the only way to pull back info from the canvas would be to use getImageData which will only give you raw pixel information.

Quick example showing this

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>

note I just create a bunch of random points. The main thing to remember is set the min/max vals to the coords of the first path a user creates.

I guess you knew that though, so the real answer is no there is unfortunately no built in way currently to do it..

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文