1

I have created 2 shapes, circle and rectangle, one on top of the other to resemble a key lock. I then try to apply a stroke but its stroking both shapes. What I want it to do is just stroke the merged pattern and not any of the intersections.

context.beginPath();
context.fillStyle = "#ccc";
context.arc(115, 550, 12, 0, 2 * Math.PI, false);
context.moveTo(105, 555);
context.fillStyle = "#999";
context.rect(105, 555, 20, 30);
context.fill();
context.stroke();
context.closePath();

If I try to draw the rect first, then the arc on top there are extra line paths when you stroke, its like I have to close Path and then draw it again.

fes
  • 2,465
  • 11
  • 40
  • 56

3 Answers3

0

You can use compositing and temporary canvas. Something like that:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var tempCanvas = document.getElementById('tempCanvas');
var tempContext = tempCanvas.getContext('2d');
tempContext.save();
// clear temp context
tempContext.clearRect(0, 0, canvas.width, canvas.height);

// draw all rects with strokes
tempContext.beginPath();
tempContext.strokeStyle='red';
tempContext.lineWidth=3;
tempContext.arc(100, 100, 60, 0, 2 * Math.PI, false);
tempContext.rect(20,150,100,200); 
tempContext.stroke();

// set compositing to erase existing drawings 
// where the new drawings are drawn

tempContext.globalCompositeOperation='destination-out';

// fill all rects
// This "erases" all but the outline stroke
tempContext.beginPath();
tempContext.fillStyle='blue';
tempContext.arc(100, 100, 60, 0, 2 * Math.PI, false);
tempContext.rect(20,150,100,200);
tempContext.fill();


// draw outlines from tempcanvas into canvas
ctx.drawImage(tempCanvas, 0, 0);

// draw into canvas
ctx.beginPath();
ctx.fillStyle='green';
ctx.globalAlpha = 0.2;
ctx.rect(20,150,100,200);
ctx.arc(100, 100, 60, 0, 2 * Math.PI, false);
ctx.fill();

tempContext.restore();

And a jsfiddle: https://jsfiddle.net/EvaF/8to68dtd/2/

EvaF
  • 1
  • 1
0

You can't use a rect and a whole circle if you want the path to do without the intersecting part.

Instead you have to draw only part of the circle and only part of the rectangle. This should do it for you:

context.beginPath();
context.fillStyle = "#ccc";
context.arc(115, 550, 12, 2.5, 2.2 * Math.PI, false);
context.moveTo(105+20, 555);
context.fillStyle = "#999";
// instead of a rect, we really want three lines
context.lineTo(105+20,555+30);
context.lineTo(105,555+30);
context.lineTo(105,555);

context.fill();
context.stroke();
context.closePath();
Simon Sarris
  • 62,212
  • 13
  • 141
  • 171
  • I see, so theres no way to merge the shapes? You have to just draw what you want. Cheers. – fes Apr 08 '11 at 14:18
  • There are technically other ways to achieve the same effect. You could fill a Rect and a Circle with black, and then on top of them fill a 2-pixel smaller rect and circle. That would achieve the same effect (I think) without any use of paths at all. But if you want to use paths, you cant just intersect them, you have to draw the precise thing. – Simon Sarris Apr 08 '11 at 17:30
0

While working on my own irregular shape answer, I discovered a lab project by Professor Cloud that solved my problem.

This page, SVG-to-Canvas, parses an SVG graphic to Canvas code. So if you have an application like Illustrator with which you can draw and save the graphic as SVG, then you can parse the usable canvas codes and just plug them in.