Why some rectangles are disappearing when there is a rectangle that covers the whole area?

103 views Asked by At

I'm facing a problem with css paint worklet and am wondering whether it's a browser bug or there's something that i'm doing wrong. In a worklet i'm drawing a few rectangles. If one of them covers the whole area, others are starting to disappear when i'm changing zoom level. But when i remove the context.fillRect(0, 0, width, height) everything works like a charm.

Here's sandbox code that i've prepared to better illustrate the problem: https://codesandbox.io/s/magical-villani-py8x2

with background

enter image description here

1

There are 1 answers

0
Kaiido On

That indeed looks like a bug in Chrome "experimental" implementation, you might want to let them know on their issue tracker, since that should work.

Now, while you are not doing anything bad per se, note that if instead of the non-standard zoom we do use the transform property, then the bug would not occur:

(()=> {

  if( !CSS.paintWorklet ) {
    return console.error('CSS Paint API is not supported in this browser, you may have to enable it from chrome://flags/#enable-experimental-web-platform-features');
  }
  const worklet_script = document.querySelector('[type="paint-worklet"]').textContent;
  const worklet_blob = new Blob([worklet_script], { type: 'text/javascript' });
  CSS.paintWorklet.addModule(URL.createObjectURL(worklet_blob));
  
  window.addEventListener("DOMContentLoaded", () => {
  const slider = document.getElementById("slider");
  slider.addEventListener("input", () => {
    const el = document.querySelector(".content");
    el.style.transform = `scale(${slider.value},${slider.value})`;
  });
});

})();
.content {
  background: paint(sandbox);
  border: 1px solid black;
  height: 200px;
  width: 200px;
  transform-origin: top left;
}
<input type="range" id="slider" min="0.5" max="4" value="1" step="0.1" />
<div class="content"></div>
<script type="paint-worklet">
class SandboxPaintWorklet {
  paint(context, geometry, properties) {
    const { width, height } = geometry;

    // background
    context.fillStyle = "#8866aa";
    context.fillRect(0, 0, width, height);

    context.fillStyle = "#000000";
    context.beginPath();
    // vertical line
    context.fillRect((width * 3) / 4, 0, 1, height);

    // horizontal lines
    const distance = Math.ceil(height / 20);

    for (let i = 0; i < 20; ++i) {
      context.fillRect(0, i * distance, width / 2, 1);
    }
  }
}

registerPaint("sandbox", SandboxPaintWorklet);
</script>

And even with zoom, if instead of that many fillRect, if we do fill a single sub-path by using rect() instead, then that would also work.

(()=> {

  if( !CSS.paintWorklet ) {
    return console.error('CSS Paint API is not supported in this browser, you may have to enable it from chrome://flags/#enable-experimental-web-platform-features');
  }
  const worklet_script = document.querySelector('[type="paint-worklet"]').textContent;
  const worklet_blob = new Blob([worklet_script], { type: 'text/javascript' });
  CSS.paintWorklet.addModule(URL.createObjectURL(worklet_blob));
  
  window.addEventListener("DOMContentLoaded", () => {
  const slider = document.getElementById("slider");
  slider.addEventListener("input", () => {
    const el = document.querySelector(".content");
    el.style.zoom = slider.value;
  });
});

})();
.content {
  background: paint(sandbox);
  border: 1px solid black;
  height: 200px;
  width: 200px;
}
<input type="range" id="slider" min="0.5" max="4" value="1" step="0.1" />
<div class="content"></div>
<script type="paint-worklet">
class SandboxPaintWorklet {
  paint(context, geometry, properties) {
    const { width, height } = geometry;

    // background
    context.fillStyle = "#8866aa";
    context.fillRect(0, 0, width, height);

    context.fillStyle = "#000000";
    context.beginPath();
    // vertical line
    context.rect((width * 3) / 4, 0, 1, height);

    // horizontal lines
    const distance = Math.ceil(height / 20);

    for (let i = 0; i < 20; ++i) {
      context.rect(0, i * distance, width / 2, 1);
    }
    context.fill();
  }
}

registerPaint("sandbox", SandboxPaintWorklet);
</script>