背景
MapLibre GL JS を使って地図描画をしていると、複雑な条件を使って何かを描画したいことにちょくちょく直面。悲しいことに、MapLibre GL JSのドキュメントを見てもイマイチ使い方が分からないことも多々💦
ということで、それぞれ使い方を試しつつ、まとめてみました。
MapLibre GL JS の細かい書き方については記載していないので、ご了承ください。
事例
その前に、単純なケース
通常、GeoJSONのプロパティ値が以下のようなデータであった場合、
{ "properties": { "data": 20 } }
その値に応じて円の色を変えるといったときは、このように記述する。
"circle-color": [
"step",
["get", "data"], // properties の data の値を取得
"#ffffff", 5, // 5 まで白
"#ffe100", 10, // 10 まで黄色
"#76ff00", 15, // 15 まで緑
"#00fffa", 20, // 20 まで水色
"#7700ff" // 20 以上 紫
],
オブジェクトの値を取得
データが上記のように単純だと話は早いが、そうもいかないケースもある。
以下のように階層構造を持つオブジェクトになっている場合。
{ "properties": { "data": { "2020": 20, "2021": 15, "2022": 10, "2023": 5 } } }
このようなケースでは、以下のように get
を繰り返すことで値を取得することができる。
"circle-color": [
"step",
["get", "2020", ["get", "data"]], // get を何度も繰り返す
"#ffffff", 5,
<略>
],
["get", "data"]
で まずは { "2020": 20, .... }
をオブジェクトとして取得して、そのオブジェクトから、再度 ["get", "2020"]
で値を取り出している。
分かれば単純だけど、いきなりこのケースに直面すると、結構思考が停止する(した)。
See the Pen maplibre template by humo (@humo-tech) on CodePen.
配列の値を取得(at)
オブジェクトとくれば、配列。
{ "properties": { "data": [ 20, 15, 10, 5 ] } }
配列の取得に使うのは at
。
["get", "data"]
で まずは [ 20, 15, 10, 5 ]
を配列として取得して、その配列からのN番目の値を ["at", 2]
といった形で取得する。
"circle-color": [
"step",
["at", 2, ["get", "data"]], // at で 配列の値を取得
"#ffffff", 5,
<略>
],
See the Pen maplibre expressions (object) by humo (@humo-tech) on CodePen.
配列がproperties に直接書かれている場合(properties)
そんなケースないかもしれないけれど「propertiesに配列が直接定義されている場合」って、値取れるんだろうか?と思って実験してみた。
{ "properties": [ 20, 15, 10, 5 ] }
結論としては、以下の方法で取れました(知らなかった)。
["get", "2", ["properties"]
properties
は「プロパティをオブジェクトで返してくれる」。配列で返ってきてくれれば at
で取得するのだけれど、オブジェクトで返ってくるので、get
で取得。
何かほかにも方法知ってる方いれば、教えてくださいm__m
文字列の整形 (format)
地図上に文字を表示したい場合に、ちょっと工夫を加えるケース。
通常は、こんな感じで記述
{ "properties": { "name": "東京", "density": 6409.29 } }
{
"text-field": ["get", "name"]
}
{
"text-field": ["concat",
["get", "name"],
"\n",
["get", "density"]
]
}
See the Pen maplibre expressions (concat) by humo (@humo-tech) on CodePen.
それでも十分色々表現できるけれど、2つの項目(この場合 name と density)でフォントサイズ変えたり、色変えたりといったこともしたいケースが出てくる。
そんなときに役立つのが format
。
"text-field":[
"format",
["get", "name"], {"text-color": "#000"}, // name は黒で表記
"\n", // 改行を繋げて
["get", "density"], {"text-color": "#f00", "font-scale": 0.8}, // density は 赤文字で少し小さめに
]
See the Pen maplibre expressions (concat) by humo (@humo-tech) on CodePen.
数値の整形 (number-format)
上の例で、3桁カンマが欲しいな、小数第1位まででいいな、と思うケースでは、number-format
で整形ができる。
[ "number-format", // number-format を使うと、3桁カンマが入る
[ "get", "density" ],
{ "min-fraction-digits": 1, "max-fraction-digits": 1 } // min/max-fraction-digits で桁数調整
],
なお、{ "min-fraction-digits": 3 }
のように指定すると、データが 29.12
だった場合に 29.120
とゼロ埋め表示してくれるみたいです。
See the Pen maplibre expressions (format) by humo (@humo-tech) on CodePen.
代替データ(coalesce)
symbol
機能で、マップ上に画像を表示する際に、あらかじめ用意した画像以外を呼び出してしまったときの fallback として、coalesce
の機能が使えます。
なお、発音難しいこの coalesce
は(こあれす?)、 与えられた値を順番に評価していって、最初にnullじゃない値が返ってきたものを使用してくれる ものになります。
properties: { "image": 'kitten1' }
coalesce
を使わない普通の書き方↓。この場合、存在しない画像は何も表示されない。
"icon-image": ["get", "image"]
coalesce
を使ってフォールバック画像を表示する書き方↓。こう書くと、存在しない画像を指定してしまった場合にダミーの画像を替わりに表示してくれます。
"icon-image": [
"coalesce",
["image", ["get", "image"]],
"dummy"
]
なお、ここで突如出てくる image
は、画像があるかどうかを判定して、あれば画像パスを、なければ null を返してくれるものとなっています。このことにより「存在しない画像(null)の替わりにdummy画像を表示する」という動きをしてくれます。
以下の例で石川県あたりにある「ダミー」画像は、そのようにして表示されたものになっています。
See the Pen maplibre expressions (coalesce) by humo (@humo-tech) on CodePen.
ポリゴン内判定(within)
「特定のポリゴン内にあるかどうか」の判定をしてくれるもの。
これを使うと「ポリゴン内にあるもの」と「そうでないもの」でスタイルを分けることができるようになる。
'circle-color': [
'case',
['within', areaPolygon],
'#f0f',
'#0ff'
],
areaPolygon の値
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"coordinates": [
[
[
139.44336833463933,
35.989952696688704
],
[
139.5366426753509,
35.57883425456254
],
[
140.02011467470146,
35.588948481200916
],
[
140.29838312448936,
35.90185508166421
],
[
139.6268078713709,
36.12442624848467
],
[
139.44336833463933,
35.989952696688704
]
]
],
"type": "Polygon"
}
}
]
}
See the Pen maplibre expressions (at (Array)) by humo (@humo-tech) on CodePen.
例はあげないですけれど、地名表記の言語設定に within
を用いれば、例えば「北方領土の地名は必ず日本語で表示する」ということも、できたりします(日本語表記の定義があることは前提)。
変数(let/var)
properties から計算で求めた値を、何度も使いまわしたいときに、let/var を使うことができます。
MapLibre公式サイトからの抜粋になりますが、こんな感じです。
'fill-color': [
// 人口(population)と面積(sq-km)から 人口密度(density)を計算
'let',
'density',
['/', ['get', 'population'], ['get', 'sq-km']],
[
'interpolate', ['linear'], ['zoom'],
// zoomレベル8まで
8,
[
'interpolate',
['linear'],
['var', 'density'], // 人口密度の値で色を変える
274,
['to-color', '#edf8e9'],
1551,
['to-color', '#006d2c']
],
// zoomレベル10まで
10,
[
'interpolate',
['linear'],
['var', 'density'], // 人口密度の値で色を変える
274,
['to-color', '#eff3ff'],
1551,
['to-color', '#08519c']
]
]
],
距離(distance)
MapLibre GL JS では、未サポートだった、、、。
(MapBox GL JS ver3 ではサポートされた)
距離に応じた着色とかができるんだと期待しています。
まとめ
MapLibre GL JS の Expressionを色々試してみました。
知らなかった機能もチラホラ。
何かのお役に立てば幸いです。