An demo of Combined use of `requestAnimationFrame` and `mask`

308 阅读1分钟

This demo comes from the Bindings/This page of svelte.dev.

Its final effect is as the following gif:
Nov-10-2021 17-08-17.gif

What did the demo do?

The svelte logo is exposed by a <canvas> element with mask css property and the color of the pixels within it are changed by requestAnimationFrame API.

Some notes

  • Define the actual size of <canvas> element which is bound to the canvas variable.

    <canvas width="{32}" height="{32}" bind:this="{canvas}" />
    
  • Exposed the svelte logo with mask property.

    /* For webkit-based browser compatibility such as chrome */
    -webkit-mask: url(svelte-logo-mask.svg) 50% 50% no-repeat;
    /* For Firefox!!  Better support!!*/
    mask: url(svelte-logo-mask.svg) 50% 50% no-repeat;
    
  • Setup the animation via requestAnimationFrame

    let frame = requestAnimationFrame(loop);
    
  • In the function loop, repeat the animation and change the color gracefully!

    ...
    for (let p = 0; p < imageData.data.length; p += 4) {
      const i = p / 4;
      const x = i % canvas.width;
      const y = (i / canvas.width) >>> 0;
    
      const r = 64 + (128 * x) / canvas.width + 64 * Math.sin(t / 1000);
      const g = 64 + (128 * y) / canvas.height + 64 * Math.cos(t / 1000);
      const b = 128;
    
      imageData.data[p + 0] = r;
      imageData.data[p + 1] = g;
      imageData.data[p + 2] = b;
      imageData.data[p + 3] = 255;
    }
    ...
    
  • To get a integer via logical shift >>> which is most efficient.

    const y = (i / canvas.width) >>> 0;
    
  • If a function is returned from onMount, it will be called when the component is unmounted.

    return () => {
      cancelAnimationFrame(frame);
    };