Search code examples
javascriptcanvashtml5-canvas

Should canvas fill() method be called before or after closing the path()?


I am unable to understand the behavior of the HTML Canvas fill method. By definition, it should fill current path or given path. However, I notice that fill method's behavior is same irrespective of where I put it i.e. before or after closing my path using closePath method. It still ends up filling my square drawn using Canvas path exactly same way.

function draw(context) {
  context.fillStyle = "#FF1010";

  context.beginPath();
  context.moveTo(0, 0);
  context.lineTo(100, 0);
  context.lineTo(100, 100);
  context.lineTo(0, 100);
  context.lineTo(0, 0);
  context.closePath();
  
  // Where should this be?
  context.fill();
}

So, what's the correct way to use the fill method.


Solution

  • You don't need to call closePath() for filling the path, it's done automatically.
    Enclosed subpaths* do matter for stroking, for instance a closed rect won't render the same stroke as an unclosed quad of lineTo:

    const canvas = document.querySelector("canvas");
    const ctx = canvas.getContext("2d");
    const path = new Path2D();
    path.moveTo(20, 20);
    path.lineTo(70, 20);
    path.lineTo(70, 70);
    path.lineTo(20, 70);
    path.lineTo(20, 20);
    
    ctx.lineWidth = 10;
    ctx.stroke(path);
    // closed path on the right
    ctx.translate(80, 0);
    path.closePath();
    ctx.stroke(path);
    <canvas></canvas>

    But fill will treat both exactly the same:

    const canvas = document.querySelector("canvas");
    const ctx = canvas.getContext("2d");
    const path = new Path2D();
    path.moveTo(20, 20);
    path.lineTo(70, 20);
    path.lineTo(70, 70);
    path.lineTo(20, 70);
    // only 3 lineto on the left
    ctx.fill(path);
    // 4 lineto in the center
    ctx.translate(80, 0);
    path.lineTo(20, 20);
    ctx.fill(path); 
    // closed path on the right
    ctx.translate(80, 0);
    path.closePath();
    ctx.fill(path);
    <canvas></canvas>

    Also, to clear things up, since it seems that even answerers here are still confused, closePath() doesn't mean that your path declaration is over. It just means that the previous "sub-path" is enclosed; to make things easier than are, it's just a lineTo to the last moveTo point. If you keep adding path commands after that it will stil use that sub-path and will also start from that point.

    To start a new path declaration you call ctx.beginPath().

    .* a new subpath is created at each call to moveTo, closePath, rect and roundRect.