描画の改善
画面がカクつく
MapLibreの描画に関して、案外特殊なケースなのか、情報がなかったため共有します。泥縄的で最適解ではありませんが、参考までに。
(追記:MapLibreが改善されてこの問題は解消しました。)
はんけトケのピンをドラッグできるようにしたときのことです。画面が妙にカクつくことに気づきました。フルスクリーンにしたとき特に顕著です。原因はすぐに判明。ピンそのものではなく、ピンにくっついて動く範囲円のせいでした。
円の描きかた
MapLibreはGeoJSONを読み込み、地図上に描くことができます。はんけトケは範囲円を円形のGeoJSONとして用意し、位置・半径が変化するたびに内容を更新する仕組みにしていました。
単なる円とはいえ、見かけの大きさは地図上の緯度やビューに応じて変わるし、パンやズームにも同期せねばならないので、こうして地図上の図形としてMapLibreに描いてもらっていたのです。ラクで確実、公式コード例にもある標準的な方法です。
ところが。
MapLibreのクセ
どんなに小さく単純でも、GeoJSONを更新すると、そのたびMapLibreは画面全体を再描画します。内容が変わる以上、レンダリングし直すのは当然かもしれません。
ただ、これがやけに重い。内部の処理は知りませんが、表面的な現象としては、どうやら全体の表示面積(ウインドウの大きさ)に比例して重くなるようです。
もっとも、GeoJSONの内容なんて静的なのが一般で、この現象はふつうは問題になりません。が、範囲円をグリグリ動かし、その都度GeoJSONを高速に書き換えまくる(必要以上にしない工夫はしている)はんけトケでは大問題。
いろいろ調べたり試したりしたものの、GeoJSONが表示に組み込まれている以上、回避のしようがないようです。
deck.glを導入
かくなるうえは、MapLibreとは別口で地図に円を描くしかありません。がんばれば自前で実装できるかもしれませんが、円ひとつのためにがんばりたくありません。そこで、「deck.gl」を導入してみることにしました。deck.glには、「MapLibreと同期する独自のレイヤーを追加」する機能があるらしいのです。
結果、うまくいきました。deck.glで描く円はスムーズに動きます。ミソは、deck.glを「インターリーブ」ではなく「オーバーレイ」モードで組み込むこと。
オーバーレイモードでは、MapLibreのキャンバスの上に、deck.glのキャンバスが文字どおり単純に被さります。キャンバスが別なのだから、deck.gl側でいくら円を更新してもMapLibre側に再描画の必要はないわけですね。ちなみに、deck.glでの円描画にはGeoJSONではなくScatterplotを使いました。
MapLibreの制御下にあるピン(マーカー)は、もともと独立したDIV要素なので、z-indexをいじっていちばん上に表示します。
ただし……
良好な結果ですが、ごくまれに、何かの拍子にdeck.glのレイヤー座標がずれてしまうことがあります。ビューのリサイズにまつわるバグかなと思いつつ(ウインドウをリサイズすると直ったりする)、今のところ明確な再現性がなく対処不能。deck.glの今後の更新で自然に直るかもしれませんが、あまりたびたび起こるようなら表示リセットボタンでも用意したほうがいいのかも。しばらく様子を見ます。
レイヤーも見直す
たかだか円を描くだけで面倒なことになったものです。しかし、手をかけただけの値打ちはありました。
これを機に、MapLibre自体のレイヤー構成も見直しました。もともとレイヤー数が少なく済むようエクスプレッションを工夫しつつ、地図を情報で色分けしたりしていました。それをやめ、シンプルに地図タイルだけを表示するようにしたのです。
特に、マウスオーバーでハイライトするような、再描画が頻繁にかかるエクスプレッションは絶対避けることにしました。ありふれた仕掛けで一見問題なさそうでも、しょぼいPCで広い画面に映してみると、やっぱりカクカクするからです。
多少カクついても色分けによる便利さが勝る局面もあるでしょう。しかし、はんけトケでは軽快さ・手ざわりのよさが最優先。MapLibreの描画処理が改善されたり、ちまたの機器の性能がもっと底上げされたら再考したいと思います。
用語・注釈
- GeoJSON
- 経緯度を座標系とする点・線・面を定義できる、JSON形式の地理情報データ。
- WebGL
- GPUを駆動する、ウェブ標準のグラフィックスライブラリー。
MapLibreはこれを利用して高速描画を実現している。 - deck.glについて
- 機能豊富でサイズの大きなライブラリーを、円ひとつ描くためだけに導入するのはむろん非効率。必要な機能のみビルドし直せば多少ましになるが、その部分と方法がわからない。前向きに、せっかく導入したからにはもっと活用しよう、と考えてはいる。
- エクスプレッション
- MapLibreの地図表示スタイルを制御するための構文。
補遺
MapLibre自身の改善
GeoJSONの更新が不当に遅い件は、MapLibre GL JSのGitHubでも問題に挙げられていました。
やはりGeoJSON内容の変更に伴い、本来不要な場合でも地図タイルがいちいち再生成・再描画されていた模様。他にもちょこちょこ無駄があるようです。
この問題はやがて修正され、2025年末頃リリースのv.5.14に反映されました。
(だいぶ遅れて気づいて)試してみたところ、確かにまともな速度になりました。というわけではんけトケは現在、deck.glをやめて元どおりMapLibreのGeoJSON機能で範囲円を描いています。ロードすべきファイルが減り、妙な副作用がなくなり、保守も少しラクになりました。この記事はもはや無意味ですが、はんけトケの歴史と実装方針を示すために残しておきます。