Search code examples
javascripthtml5-canvas

why changing fillStyle in canvas 2D changes the color of previously drawn rectangles?


I have the following code that first draws 3 small yellow rectangles and then draws a big blue one. I change fillStyle property before the last drawing. As a result, all rectangles are blue. If the last drawing is not performed (ctx.fill is commented out in the second loop), then I see 3 yellow rectangles.

const get = id => document.getElementById(id);

const canv = get('canv');
const [w, h] = [canv.width, canv.height];
const ctx = canv.getContext("2d");

ctx.fillStyle = 'yellow';
for (let x = 0; x < 3; x++) {
  ctx.rect(10*x, 100, 3, 3);
  ctx.fill();
}

ctx.fillStyle = 'blue';
for (let x = 0; x < 1; x++) {
  ctx.rect(10*x + 100, 100, 5, 5);
  ctx.fill();
}
* {
  margin: 0px;
  padding: 0px;
  box-sizing: border-box;
}

body {
  background-color: #020408;
  color: #ccc;
}
<canvas id="canv" width="200" height="200" style="border: solid 1px grey"></canvas>


Solution

  • This concerns the current default path of the canvas. There is only one. As you do not close one path and begin another, the entire path (i.e. both sets of rectangles) is rendered in blue.

    Just the first part of the path looks like

    const get = id => document.getElementById(id);
    
    const canv = get('canv');
    const [w, h] = [canv.width, canv.height];
    const ctx = canv.getContext("2d");
    
    ctx.fillStyle = 'yellow';
    for (let x = 0; x < 3; x++) {
      ctx.rect(10*x, 100, 3, 3);
      ctx.fill();
    }
    * {
      margin: 0px;
      padding: 0px;
      box-sizing: border-box;
    }
    
    body {
      background-color: #020408;
      color: #ccc;
    }
    <canvas id="canv" width="200" height="200" style="border: solid 1px grey"></canvas>

    Adding beginPath solves the problem.

    const get = id => document.getElementById(id);
    
    const canv = get('canv');
    const [w, h] = [canv.width, canv.height];
    const ctx = canv.getContext("2d");
    
    ctx.fillStyle = 'yellow';
    for (let x = 0; x < 3; x++) {
      ctx.rect(10*x, 100, 3, 3);
      ctx.fill();
    }
    ctx.beginPath();
    ctx.fillStyle = 'blue';
    for (let x = 0; x < 1; x++) {
      ctx.rect(10*x + 100, 100, 5, 5);
      ctx.fill();
    }
    * {
      margin: 0px;
      padding: 0px;
      box-sizing: border-box;
    }
    
    body {
      background-color: #020408;
      color: #ccc;
    }
    <canvas id="canv" width="200" height="200" style="border: solid 1px grey"></canvas>