🦜

mapbox-gl-js上でParrotをPartyさせる方法3選

2022/12/25に公開

mapbox-gl-jsは素晴らしい地図ライブラリですが、残念ながらParty Parrotはサポートされていないようです。 本記事ではネット上で色々検索して見つけたParrotをPartyさせる方法を3つ紹介します。

NG例: GIFをそのまま描画する

このようにloadImage関数でGIFファイルを渡してやると、エラーは起こらないですが、ParrotがPartyしてくれません 😢 コードはこちら

  map.on('load', () => {
    map.loadImage('partyparrot.gif',
      (e, image) => {
        map.addImage('parrot', image);
        map.addSource('point', {
          'type': 'geojson',
          'data': {
          'type': 'FeatureCollection',
          'features': [{
            'type': 'Feature',
            'geometry': {
            'type': 'Point',
            'coordinates': [139.763906, 35.6811649]
          }}]
        }});
        map.addLayer({ 'id': 'points', 'type': 'symbol', 'source': 'point', 'layout': { 'icon-image': 'parrot', 'icon-size': 0.25 } });
    });
  });

1. 動画にする

GIFファイルをezgif.comでwebm形式に変換してmapgox-gl-jsにvideoアセットとしてロードしてみました。mp4だと背景を透過にできないのでwebm形式にしました。コードはこちら

  • メリット
    • コード的には簡単?
  • デメリット
    • GIFをwebm形式に変換するのが面倒
    • ビデオリソースの矩形座標(coordinates)を正確に知るのが難しい。ちょっと縦長になってる?w
    • ズームインするとアニメーションのサイズがスケーリングする?
  map.on('load', () => {
    map.addSource('video', {
      'type': 'video',
      'urls': [
        'partyparrot.webm',
      ],
      'coordinates': [
        [139.763906, 35.6811649],
        [139.764906, 35.6811649],
        [139.764906, 35.6801649],
        [139.763906, 35.6801649],
      ]
    });
    map.addLayer({
      'id': 'video',
      'type': 'raster',
      'source': 'video'
    });
  });

2. background-imageを使う

StackOverflowで見つけた方法で、CSSのbackgroup-imageプロパティでGIFアニメーションを差し込んでやります。コードはこちら

  • メリット
    • GIFアニメーションサイズが指定したピクセルで固定される
    • コード的には一番シンプル?
  • デメリット
    • Parrotを追加するたびにdivが増えていく
  map.on('load', () => {
    var el = document.createElement('div');
    el.className = 'marker';
    el.setAttribute('style', 'background-image: url(partyparrot.gif); width: 32px; height: 32px; background-size: 32px 32px;');

    new mapboxgl.Marker(el)
      .setLngLat([139.763906, 35.6811649])
      .addTo(map);
  });

3. Canvasを使う

mapbox-gl-jsはCanvasベースのアニメーションをレンダリングする機能があるので、giflerというGIFをCanvasにレンダリングするJSライブラリを使ってアニメーションさせてやります。コードはこちら

  • メリット
    • プログラマティックに停止・再開したり再生速度を調節できる
  • デメリット
    • コード的量が多い
    • 少し負荷が大きそう
  const size = 128;

  const parrot = {
    width: size,
    height: size,
    data: new Uint8Array(size * size * 4),
    onAdd: function () {
      const canvas = document.createElement('canvas');
      canvas.width = this.width;
      canvas.height = this.height;
      this.context = canvas.getContext('2d');
      this.parrot = gifler('partyparrot.gif');
      this.parrot.animate(canvas);
    },
    render: function () {
      this.data = this.context.getImageData(0, 0, this.width, this.height).data;
      map.triggerRepaint();
      return true;
    }
  };

  map.on('load', () => {
    map.addImage('parrot', parrot, { pixelRatio: 2 });
    map.addSource('parrot-point', {
      'type': 'geojson',
      'data': {
        'type': 'FeatureCollection',
        'features': [
          {
            'type': 'Feature',
            'geometry': {
            'type': 'Point',
            'coordinates': [139.763906, 35.6811649]
            }
          }
        ]
      }
    });
    map.addLayer({
      'id': 'layer-with-parrot',
      'type': 'symbol',
      'source': 'parrot-point',
      'layout': {
      'icon-image': 'parrot'
    }
  });

まとめ

mapbox-gl-js上でPartyParrotを動かす方法を紹介しました。3つの方法は一長一短がありますが、個人的には以下の結論です。

  • 普通にGIFを表示したいだけなら2.background-imageを使う
  • リッチに動かしたい場合は3. Canvasを使う

この他にいい方法を知っている人があったら、コメントで教えてくれると嬉しいです。

GitHubで編集を提案

Discussion