简体   繁体   中英

Merging two shapes inside html canvas

I'm writing a freehand drawing webapp using the HTML Canvas element. So far, I can draw shapes onto the sceeen that look like the following images.

I have stored all the points of the shapes into a JS array. For instance:

[
 [
  [118, 171],
  [118, 170],
  [118, 167],
  ...
 ],
 [
  [236, 131],
  [236, 133],
  [236, 135],
  ...
 ]
]

I'm now looking for a way to merge certain shapes, imagine that I would like to merge the two shapes in the following picture, here's how it would look like.

I think I have to redraw to the canvas but filter out all the points that are inside another shape.

The first idea that I had was to find a solution to check if a specific point was contained inside another shape and if it's the case, skip it. However, that would probably not work since moveTo / lineTo / stroke would create a line between the last independant point before a shape and the first independant after a shape.

I've looked up compositing operations that might be able to help, but haven't found a way to implement it yet.

How could I approach this feature?

Input

输入

Output

输出

The following code is not a complete solution. It uses Path2D objects (still marked as an "experimental technology" by MDN) and the isPointInPath() canvas function.

 // Canvas boilerplate const canvas = document.querySelector('#mycanvas'); const ctx = canvas.getContext('2d'); // Create our shapes const shape1 = [[100, 100], [70, 200], [150, 250], [300, 250], [300, 100], [150, 50]]; const shape2 = [[60, 60], [60, 160], [110, 210], [260, 210], [260, 60], [110, 10]]; // Create Path2D objects from our shapes let p1 = new Path2D(); p1.moveTo(...shape1[0]); for (let i = 1; i < shape1.length; i++) { p1.lineTo(...shape1[i]); } p1.closePath(); let p2 = new Path2D(); p2.moveTo(...shape2[0]); for (let i = 1; i < shape2.length; i++) { p2.lineTo(...shape2[i]); } p2.closePath(); // Draw the shapes onb the canvas ctx.fillStyle = 'white'; ctx.lineWidth = 4; ctx.strokeStyle = 'green'; ctx.stroke(p1); ctx.strokeStyle = 'blue'; ctx.stroke(p2); // Just for this demo, fill the shapes to make them look joined together ctx.fill(p2); ctx.fill(p1); // Discover whether coordinate points are inside/outside the other shape let inside = [], outside = []; for (let i = 0; i < shape2.length; i++) { if (ctx.isPointInPath(p1, ...shape2[i])) inside.push(shape2[i]); else outside.push(shape2[i]); } for (let i = 0; i < shape1.length; i++) { if (ctx.isPointInPath(p2, ...shape1[i])) inside.push(shape1[i]); else outside.push(shape1[i]); } // Display coordinates inside ctx.fillStyle = 'red'; for (let i = 0; i < inside.length; i++) { ctx.beginPath(); ctx.moveTo(...inside[i]); ctx.arc(...inside[i], 5, 0, 2 * Math.PI); ctx.fill(); } //... and outside ctx.fillStyle = 'black'; for (let i = 0; i < outside.length; i++) { ctx.beginPath(); ctx.moveTo(...outside[i]); ctx.arc(...outside[i], 5, 0, 2 * Math.PI); ctx.fill(); }
 <canvas id="mycanvas"></canvas>

To calculate a third shape which combines the coordinates of a path outlining the merged shape you need to work out which lines in each shape intersect, and where, then combine those new coordinates with your existing outside coordinates in the right order. Best of luck!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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