Mapbox GL JSで、地理院地図の「自分で作る色別標高図」を実装してみる試みです。
自分で作る色別標高図とは
今年、地理院地図に追加された、自由に色を設定して色別標高図を作ることができるすごい機能です。
【地理院地図改良(その2)】自由に標高を色分けして、土地の高低差をわかりやすく表示できるようになりました。意外なところに地形の凸凹が潜んでいるかもしれません。オリジナルの地図を作って、新しい発見をしてみよう!https://t.co/CoGLjpTvxl pic.twitter.com/cJ7ir0RSRU
— 地理院地図 (@gsi_cyberjapan) 2018年3月8日
Leaflet.jsのTileLayerを拡張して、canvas上で標高に応じた色をつけるように実装されています。
同じことをMapbox GL JSで実現することを考えます。
ですが、現時点では色別標高図を作る機能はないため、自分で実装してみます。
地理院標高タイル
まず、地理院標高タイルをMapbox GL JSで扱えるようにします。
これは以前、Mapbox GL JSで地理院標高タイルという記事を書きました。
Relief Layer
hillshadeのように、色別標高図をRelief Layerとして追加できるようにします。
WebGLで標高に応じた色をつける
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D u_image;
uniform sampler2D u_table;
varying vec2 v_pos;
uniform float u_color_len;
uniform float u_opacity;
float getElevation(sampler2D u_tex, vec2 coord, float bias) {
// Convert encoded elevation value to meters
vec4 data = texture2D(u_tex, coord) * 255.0;
return (data.r + data.g * 256.0 + data.b * 256.0 * 256.0) / 4.0;
}
float getIndex(float el) {
float prev;
for (float i = 0.0; i < 128.0; i++){
if (i >= u_color_len) return u_color_len;
float v = getElevation(u_table, vec2((i + 0.5) / u_color_len, 1), 0.0);
if (v >= el){
if (i == 0.0) return i;
return i + (el - prev) / (v - prev);
}
prev = v;
}
}
void main() {
float v = getElevation(u_image, v_pos, 0.0);
float i = getIndex(v);
vec4 color = texture2D(u_table, vec2(i / u_color_len, 0), 0.0);
gl_FragColor = v > 0.0 ? vec4(color.rgb, u_opacity) : vec4(0.0, 0.0, 0.0, 0.0);
}
ざっくりと説明すると、
- WebGLで標高値
getElevation
に応じた階級getIndex
を計算する - 設定色のTextureから、階級に応じた色を取得して返す
という感じです。
区分の標高値と設定色をTexture u_table
として渡すところがポイントでしょうか。
このフラグメントシェーダーを実行するために、いろいろとコードを書きます。
https://github.com/tattii/mapbox-gl-js/pull/2
参考: Data-driven Raster Layer with Mapbox GL
Example
https://tattii.github.io/terrain-japan/relief/#9.06/35.511/139.1993map.addLayer({
"id": "relief",
"source": "gsi-dem",
"type": "relief",
"paint": {
"relief-opacity": 0.7,
"relief-gradation": true,
"relief-colors": [
0, "#2db4b4",
100, "#71b42d",
300, "#b4a72d",
1000, "#b4562d",
2000, "#b4491b",
4000, "#b43d09",
null, "#b43d09"
]
}
}, 'waterway-river-canal-shadow');
relief-colors
で標高と色を指定します。この設定例で、自分で作る色別標高図の初期状態と同じです。
WIP: 自由に色を設定する
簡易的に、dat.guiを使ってリアルタイムに色の編集をできるようにしました。
https://tattii.github.io/terrain-japan/relief/color.html#8.85/35.352/139.1404
標高の編集や区分数を増やすことができるようなアプリケーションとして作成中です...。
Mapbox GL JSで実装してみて
描画が速いため、リアルタイムに色の編集をできるのが良いところです。
また、Mapbox GL JSの陰影起伏hillshade
は重ねても暗くなりません。
一方、Mapbox GL JSをforkして独自の拡張をしているため、本体のバージョンアップについていくのは大変です。
まとめ
WebGLは難しいです。綺麗な色別標高図を作るのも難しいです。
地理院地図にある、URLでの共有や断面図といった機能も実装してみたいです。