user2039981
user2039981

Reputation:

HTML5 Canvas - Drawing overlapping polygons

So, I have a polygon drawing function like this:

Polygon.prototype.draw = function(ctx) {
    ctx.save();
    ctx.beginPath();
    var v = this.vertices[0]
    ctx.moveTo(this.position.x + v.x, this.position.y + v.y);
    var i = this.vertices.length;
    while (i--) {
        v = this.vertices[i]
        ctx.lineTo(this.position.x + v.x, this.position.y + v.y);
    }
    ctx.strokeStyle = "#000";
    ctx.stroke();
    ctx.closePath()
    ctx.restore();
}

This is how two polygons that overlap will be drawn:

Bad

But I want them, if they overlap, to be drawn like this:

Good

Note that I stroke the polygons, so I want to maintain the canvas background image too.

Also, I want to make it work for more than 2 polygons too.

Any good ways to do this?

FIDDLE: http://jsfiddle.net/k0cef75t/

Upvotes: 2

Views: 568

Answers (1)

markE
markE

Reputation: 105015

Here's one way using Compositing.

Use destination-out compositing to "erase" the center of the combined polygons:

  • create a temporary offscreen canvas
  • stroke the polygons with double lineWidth
  • set globalCompositeOperation="destination-out"
  • fill the polygons (this will "erase" the inside of the polygons--leaving just the outer stroke)
  • drawImage the temporary canvas on the on-screen canvas

enter image description here

Example code and a Demo: http://jsfiddle.net/m1erickson/8vrj8r2g/

onscreenContext.drawImage(strokeCombinedShapes(shapes), 40, 30);

function strokeCombinedShapes(shapes){

    // ctx1 is the context of the off-screen canvas
    ctx1.clearRect(0,0,canvas.width,canvas.height);
    ctx1.save();

    // stroke the polygons
    for(var i=0;i<shapes.length;i++){
        var pts=shapes[i];
        ctx1.beginPath();
        ctx1.moveTo(pts[0].x,pts[0].y);
        for(var j=1;j<pts.length;j++){
            ctx1.lineTo(pts[j].x,pts[j].y);
        }
        ctx1.closePath();
        ctx1.lineWidth=2;
        ctx1.stroke();
    }

    // set all new drawings to "erase" current drawings
    ctx1.globalCompositeOperation="destination-out";

    // fill the polygons
    // this causes the insides of the polygons to be "erased"
    for(var i=0;i<shapes.length;i++){
        var pts=shapes[i];
        ctx1.beginPath();
        ctx1.moveTo(pts[0].x,pts[0].y);
        for(var j=1;j<pts.length;j++){
            ctx1.lineTo(pts[j].x,pts[j].y);
        }
        ctx1.closePath();
        ctx1.fill();
    }
    ctx1.restore();
    return(canvas1);
}

Upvotes: 1

Related Questions