はじめに
MapLibreとは
MapLibre Official WebSite
https://maplibre.org
- Web地図に関するプロダクトをOSSとして開発・メンテナンスしているOrganizationです
- ブラウザ・モバイル向けの地図ライブラリおよび地図配信に関するツール群があります
MapLibre User Group Japan (MUG-JP) とは
MUG-JP Official Web Site
https://mug-jp.org/
- MapLibreプロダクトの開発者によるユーザーコミュニティです
- ナレッジの共有やイベントの開催による普及活動を行なっています
v2で突如生えてきたaddProtocol()
関数
addProtocol()
の経緯などについては以下の記事が詳しいです。そういえば昔はmapbox://
というプロトコルが使えたっけ…。
MapLibre Styleでは、source
でタイル等のURLを定義しますが、その際のプレフィックスをprotocol
と呼びます(http/https...)。https://
ならもちろんデフォルトの挙動(単にデータをダウンロードする)となりますが、ここに独自のprotocolを定義するのがaddProtocol
という訳です。
addProtocol()
という言葉だけだと意味がわかりづらいので、ユーザーがタイルデータを自由に生成出来るcustom source
と理解するのが良いと思います。
addProtocolで定義するカスタムプロトコル
割となんでも出来て、ルールはたったひとつ=「タイルデータをreturnする」ことだけです。
以下の例では、クライアントサイドでオンメモリで生成したPNG画像をreturnしています(fetchせずcanvasで画像生成しているのがポイント)。
https://svelte-maplibre-gl.mierune.dev/examples/custom-protocol より引用
maplibregl.addProtocol('myprotocol', async (params) => {
const zxy = params.url.replace('myprotocol://', '');
const [z, x, y] = zxy.split('/').map((v) => parseInt(v, 10));
const png = await new Promise((resolve) => {
const canvas = document.createElement('canvas');
canvas.width = 512;
canvas.height = 512;
const context = canvas.getContext('2d')!;
// checkered pattern
context.fillStyle = (z + x - y) % 2 === 0 ? 'rgba(255, 255, 255, 0.4)' : 'rgba(0, 0, 0, 0.4)';
context.fillRect(0, 0, canvas.width, canvas.height);
context.fillStyle = 'white';
context.font = '32px sans-serif';
context.fillText(`${z}/${x}/${y}`, 32, 64);
// canvas to blob (png) to arraybuffer
canvas.toBlob(async (blob) => {
resolve(await blob!.arrayBuffer());
});
});
return { data: png };
});
また、以下の例ではベクトルタイルのバイナリをオンメモリで生成しています。
addProtocolを活用しているライブラリ群
余談:addProtocol()
が実装されたあたりにあった会話
筆者所属のMIERUNEがMapLibre Orgにスポンサーしたときに、MIERUNEがMapLibreをどう利用しているか的なインタビューがあり:
メンテナーたちも、現状のような使われ方は予想していなかったのかもしれませんね。addProtocol()
がユーザー定義のsourceの作成を可能としたことで、図らずもいわゆる「プラグイン機構」を提供するものとなったということでしょう。当初、関数のシグネチャもおよそサードパーティに利用させるような作りではなかったのも思い出されます(値を返すのがcallback(null, png, null, null)
という関数だった。v4で綺麗になった)。
余談:MapLibre Nativeではどうなっているのか
MapLibre Nativeでは、そもそもデータへのリクエストは全て自分で定義する必要があります。以下は筆者が開発しているchiitiler
のコードです。
データフェッチングは全てこの関数を通るので、プロトコルをチェックして条件分岐させています。
ここで、GL JSとNativeは違う仕組みで動いていることに注意が必要です。つまりaddProtocol
に過度に依存したstyleはNativeでは利用出来ないということです。