繁体   English   中英

如何使用HMTL5 Javascript Canvas获得碰撞的三个形状的交集并删除未碰撞的部分?

[英]How can I get the intersection of three shapes colliding and delete the parts that are not colliding using HMTL5 Javascript Canvas?

我最近在这里专门针对 KonvaJs 发布了一个类似的问题,但是,我没有得到任何答案,想直接了解 KonvaJs 使用的根源。 我想知道是否有使用 HMTL5 Javascript Canvas 解决以下问题的标准方法。

如果给我 3 个圆圈并将它们定位为原色圆圈(3 个圆圈彼此相交),是否有一个功能可以帮助我删除不与任何东西碰撞的部分并只保留相交的部分?

另一个示例可能是以形成三角形的方式绘制三条线。 通过删除没有碰撞的部分,我们最终会得到 3 个点(至少在视觉上,不确定我是总共得到 3 个还是堆叠起来得到 6 个),它们是前一个三角形的边缘。

根据我搜索过的内容,我可以通过使用 命中区域来检测碰撞 区域,然后以某种方式在碰撞的部分上应用剪辑功能,以获得所需的结果。 我在这个解决方案中看到的问题是,如果每个形状都是可拖动的,则形状可能会被剪裁,但不会跟随拖动的形状。

我的另一个想法是检测并切割碰撞区域,然后删除没有碰撞的区域,然后将它们组合在一起。 (我不知道怎么把它们切成小块……)

我不确定上面提到的任何想法是否是解决它的正确/最佳方法......

合成可以做到这一点。

诀窍是在第二个离屏画布上处理每个合成,然后使用默认的source-over模式合并它们。

 const canvas = document.getElementById( "canvas" ); const ctx = canvas.getContext( "2d" ); // we create an off-screen copy of the canvas to perform our clippings const copy = canvas.cloneNode(); const off = copy.getContext( "2d" ); // declares our shapes const circle = new Path2D(); circle.arc( 0, 0, 145, 0, Math.PI * 2 ); const blue_circle = new Path2D(); blue_circle.addPath( circle, { e: 260, f: 160 } ); const red_circle = new Path2D(); red_circle.addPath( circle, { e: 160, f: 310 } ); const yellow_circle = new Path2D(); yellow_circle.addPath( circle, { e: 340, f: 310 } ); // get common area of blue & red off.fill( blue_circle ); off.globalCompositeOperation = "source-in"; off.fill( red_circle ); // save to visible canvas ctx.drawImage( copy, 0, 0 ) // clear off.globalCompositeOperation = "source-over"; off.clearRect( 0, 0, 500, 500 ); // get common area of blue & yellow off.fill( blue_circle ); off.globalCompositeOperation = "source-in"; off.fill( yellow_circle ); // save to visible canvas ctx.drawImage( copy, 0, 0 ) // clear off.globalCompositeOperation = "source-over"; off.clearRect( 0, 0, 500, 500 ); // get common area of red & yellow off.fill( red_circle ); off.globalCompositeOperation = "source-in"; off.fill( yellow_circle ); // save to visible canvas ctx.drawImage( copy, 0, 0 ); // last pass to blend the colors off.globalCompositeOperation = "source-over"; off.clearRect( 0, 0, 500, 500 ); off.globalAlpha = 0.6; off.fillStyle = "blue"; off.fill( blue_circle ); off.fillStyle = "red"; off.fill( red_circle ); off.fillStyle = "yellow"; off.fill( yellow_circle ); // draw only where we did draw previously ctx.globalCompositeOperation = "source-in"; ctx.drawImage( copy, 0, 0 );
 canvas { background: white }
 <canvas id="canvas" width="500" height="500"></canvas>

改用线条:

 const canvas = document.getElementById( "canvas" ); const ctx = canvas.getContext( "2d" ); // we create an off-screen copy of the canvas to perform our clippings const copy = canvas.cloneNode(); const off = copy.getContext( "2d" ); off.lineWidth = 30; const bottom_left_top_center = new Path2D("M0,300L300,0"); const top_left_bottom_right = new Path2D("M0,0L300,300"); const bottom_left_bottom_right = new Path2D("M0,200L300,200"); off.stroke( bottom_left_top_center ); off.globalCompositeOperation = "source-in"; off.stroke( top_left_bottom_right ); // save to visible canvas ctx.drawImage( copy, 0, 0 ) // clear off.globalCompositeOperation = "source-over"; off.clearRect( 0, 0, 500, 500 ); off.stroke( bottom_left_top_center ); off.globalCompositeOperation = "source-in"; off.stroke( bottom_left_bottom_right ); // save to visible canvas ctx.drawImage( copy, 0, 0 ) // clear off.globalCompositeOperation = "source-over"; off.clearRect( 0, 0, 500, 500 ); off.stroke( top_left_bottom_right ); off.globalCompositeOperation = "source-in"; off.stroke( bottom_left_bottom_right ); // save to visible canvas ctx.drawImage( copy, 0, 0 )
 canvas { background: white }
 <canvas id="canvas" width="300" height="300"></canvas>

我认为主要思想是您不使用画布方法进行剪辑,而是自己保留形状数据并自己执行所需的计算,在画布上绘制结果或将其用作一种像素数据获取器。


如果您同意您的形状成为栅格数据,即只有新的“相交”形状的像素表示,一般的想法是:

  1. 将每个形状转换为像素数据,包括画布的所有空像素并将像素存储到数组中;
  2. 计算所有三个形状的边界框;
  3. 循环边界框区域的所有像素,将所有三个形状都存在的像素保存到新数组中;
  4. 将新的像素数组绘制到画布中。

如果您需要矢量数据,例如能够稍后缩放您的形状,它会变得有点复杂。

问题是,使用画布函数而不是像素数据来表达由交叉点产生的可能非常复杂的形状是一项艰巨的任务。

我可能会这样做:

  1. 将我的形状保留为 SVG 图像数据
  2. 在画布上绘制 svg 路径,使其可见。 新技术使它变得简单: https : //developer.mozilla.org/en-US/docs/Web/API/Path2D/Path2D
  3. 使用第三方库获取相交 svg 形状之间的新路径。 我没有深入研究,但我确信诸如 Raphael 或 Snap.js 之类的库将具有获取两个 svg 之间的交集数据的方法。
  4. 获取新的交叉点数据并将其存储为新的 SVG 图像数据,然后将其绘制在画布上。

很可能提到的库,比如 Raphael 可能有一些东西可以让人们以更简单的方式做到这一点。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM