簡體   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