CanvasKit - (Skia + WebAssembly)を使ってみる

## CanvasKit

[公式ページ](https://skia.org/user/modules/canvaskit)によると、CanvasKit(SkiaのWebAssemblyビルド版を含む)は、
新しいCanvasとSVGプラットフォームAPIをテストするためのPlaygroundを提供するとなっています。

### 改めてWebAssemblyとは?
[WebAssembly - Wikipedia](https://ja.wikipedia.org/wiki/WebAssembly)

> ブラウザ上でバイナリフォーマットの形で実行可能であることを特徴とする

とあり、C/C++, Rust, GO, Kotlin Nativeが現在対応している言語となっています。

###  :computer:環境構築
****
[npmパッケージ](https://www.npmjs.com/package/canvaskit-wasm) も提供されていますが、今回はサクッと手元で
確認する為に `unpkg.com` から提供されているCDNを利用します。

### :pencil: 実装
****

#### 簡単なサンプル
 `index.html` だけの線を描画するだけのドシンプルなサンプルを作ってみます。

```html:index.html
<!DOCTYPE html>
<html>
  <head>
    <title>CanvasKit Sample</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
  </head>
  <body>
    <div class="canvas-container">
      <canvas width="500" height="500" id="canvas">
    </div>
    <script src="https://unpkg.com/canvaskit-wasm@0.17.3/bin/canvaskit.js"></script>
    <script type="text/javascript" charset="utf-8">
      CanvasKitInit({
          locateFile: (file) => 'https://unpkg.com/canvaskit-wasm@0.17.3/bin/'+file,
      }).then((CanvasKit) => {
        const surface = CanvasKit.MakeCanvasSurface('canvas');
        if (!surface) {
          throw 'Could not make surface';
        }

        function drawFrame(canvas) {
          const paint = new CanvasKit.SkPaint();
          paint.setStrokeWidth(1.0);
          paint.setAntiAlias(true);
          paint.setColor(CanvasKit.RED);
          paint.setStyle(CanvasKit.PaintStyle.Stroke);

          const path = new CanvasKit.SkPath();
          path.moveTo(0, 0);
          path.lineTo(500, 500);

          canvas.drawPath(path, paint);
          path.delete();
          paint.delete();
        };
        surface.drawOnce(drawFrame);
      });
    </script>
  </body>
</html>
```
上記コードを実行した結果がこちら↓
<img width="300" alt="image.png (9.0 kB)" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299271/aa0c5474-2f78-19a9-399d-05f5e9c6d42c.png">

とりあえず動いている様子です :sparkles: 

#### Skottie (Lottie Animation Player) でアニメーション
次にSkiaがLottieファイルのアニメーション再生をサポートしているので、試してみます。
今回テスト用に使用したLottieファイルはこちらになります。
<img width="150" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299271/a02e614a-3223-c236-a648-73c3cc7b1f26.gif">

Skottieに関してはCanvasKitとは別の[npmパッケージ](https://www.npmjs.com/package/skottiekit-wasm)として公開されています。
先ほどの `index.html` も使用するCDNが異なります。

完成した `index.html` がこちら ↓

```html:index.html
<!DOCTYPE html>
<html>
  <head>
    <title>CanvasKit Sample</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
  </head>
  <body>
    <div class="canvas-container">
      <canvas width="500" height="500" id="canvas">
    </div>
    <script src="https://unpkg.com/skottiekit-wasm@0.1.0/bin/skottiekit.js"></script>
    <script type="text/javascript" charset="utf-8">
    const lottieUrl = "https://assets6.lottiefiles.com/private_files/lf30_4uTjNk.json";
    Promise.all([
      fetch(lottieUrl).then((res) => res.text()),
      SkottieKitInit({
        locateFile: (file) => 'https://unpkg.com/skottiekit-wasm@0.1.0/bin/'+file,
      })
    ]).then(([json, SkottieKit]) => {
      const animation = SkottieKit.MakeManagedAnimation(json);
      const duration = animation.duration() * 1000;
      const size = animation.size();
      const bounds = {fLeft: 0, fTop: 0, fRight: 500, fBottom: 500};

      const surface = SkottieKit.MakeCanvasSurface('canvas');
      if (!surface) {
        throw 'Could not make surface';
      }

      let firstFrame = Date.now();
      function drawFrame(canvas) {
        let seek = ((Date.now() - firstFrame) / duration) % 1.0;
        let damage = animation.seek(seek);

        if (damage.fRight > damage.fLeft && damage.fBottom > damage.fTop) {
          canvas.clear(SkottieKit.WHITE);
          animation.render(canvas, bounds);
        }
        surface.requestAnimationFrame(drawFrame);
      };
      surface.requestAnimationFrame(drawFrame);
    });
    </script>
  </body>
</html>
```
上手く動作できたらアニメーションがループして再生され続けます。
<img width="300" alt="image.png (45.7 kB)" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299271/472b7dd3-3986-560f-bb3c-6bae1889d6e3.png">

### :sparkles: 感想
****
Playgroundと言っている様に、Skiaの雰囲気をサクッと手元で確認するのには良さそうでした。
ただ、凝った事(Shader使ったり)しようとするとCDNのパッケージだけでは `SkRuntimeEffect` がundefinedになったりと
ドキュメントが不十分な感じはしましたが、Playgroundなのでそんなものな気もしました。
また機会があれば色々触ってみたいと思います。

### :link: 参考になったURL
****
- [WebAssemblyとは？〜実際にC言語をブラウザで動かす〜【2019年6月版】 - Qiita](https://qiita.com/umamichi/items/c62d18b7ed81fdba63c2)