Search code examples
htmlcanvasborderstroke

Prevent stroke border from overflowing path


strokeRect (0, 0, canvasWidth, canvasHeight); draws a full rectangle but the line width is cut in half, here is an example:

<canvas></canvas>

<script>
    var canvas = document.getElementsByTagName ("canvas");

    var lineWidth = 10;

    var canvasHeight = canvas[0].height;
    var canvasWidth = canvas[0].width;

    var ctx = canvas[0].getContext ("2d");

    ctx.lineWidth = lineWidth;

    ctx.strokeRect (0, 0, canvasWidth, canvasHeight);
</script>

screenshot of problem

I can fix that but isn't elegant:

<canvas></canvas>

<script>
    var canvas = document.getElementsByTagName ("canvas");

    var lineWidth = 10;

    var canvasHeight = canvas[0].height - lineWidth;
    var canvasWidth = canvas[0].width - lineWidth;

    var ctx = canvas[0].getContext ("2d");

    ctx.lineWidth = lineWidth;

    lineWidth /= 2;

    ctx.strokeRect (lineWidth, lineWidth, canvasWidth, canvasHeight);
</script>

screenshot of inelegant solution

Is there a native method to do that ? Something like the "box-sizing" css3 attribute:

canvas {
    box-sizing: border-box;
}

Thanks.


Solution

  • Strokes in HTML5 Canvas—as in Adobe Illustrator or SVG—are always centered on the path that they are stroking. Long ago I proposed a new SVG property that sounds like what you want, but this functionality is in neither SVG nor Canvas. Your stroke is behaving as it is supposed to.

    However, you can work around this by using clipping region, clipping to the same as the path you are about to stroke and doubling your nominal lineWidth:

    function clippedRectStroke( ctx, x, y, w, h ){
      ctx.save();
      ctx.beginPath();
      ctx.moveTo(x,y);
      ctx.lineTo(x,y+h);
      ctx.lineTo(x+w,y+h);
      ctx.lineTo(x+w,y);
      ctx.clip();
      ctx.lineWidth *= 2;
      ctx.strokeRect(x,y,w,h);
      ctx.restore(); 
    };
    

    Working demo here: http://jsfiddle.net/Dvz9Y/2/