deck.glは、WebGLを活用して地図やデータ視覚化を行う強力なツールです。 TileLayerを使うことでXYZ形式の地図タイルを簡単に表示できますが、地図タイルの最大ズームレベル以上に拡大して表示する標準機能はありません。
この記事では、地理院タイルを用いた地図表示で、ズームレベル18以上に拡大するための方法を紹介します。
背景・課題
私たちが作成した「 文化財マップ 」では、地理院タイルを使用して衛星画像を表示しています。
地理院タイルは最大ズームレベル18までしか提供されていませんが、今回の要件ではそれ以上に拡大表示を行う必要がありました。 例えば、特定の建物や施設の表示を行う際、1棟1棟の区別をするにはズームレベル19や20での表示が必要です。 この問題を解決するため、TileLayerの拡張によって拡大表示を実現します。
元のコード(deck.gl + React)
import DeckGL from '@deck.gl/react';
import { TileLayer } from "@deck.gl/geo-layers";
import { BitmapLayer } from "@deck.gl/layers";
export const Map = () => {
const tileLayer = new TileLayer({
id: "TileLayer",
data: CHIRIIN_URL,
minZoom: 5,
maxZoom: 20, // z=19, 20のタイルは存在しない
tileSize: 256,
renderSubLayers: props => new BitmapLayer(props, {
data: undefined,
image: props.data,
bounds: (({ west, south, east, north }: any) => [west, south, east, north])(props.tile.bbox),
}),
});
return (
<DeckGL layers={[tileLayer]} />
)
}
どのように拡大表示するか
deck.glでは、zoomOffsetというプロパティを利用してタイルのズームレベルを調整することができます。通常、zoomレベルに応じて適切な解像度のタイルが読み込まれますが、zoomOffsetを使うことでその挙動を変更できます。
- zoomOffset = 0:標準のズームレベル(例えばzoom 10の時にz=10のタイルを読み込み)
- zoomOffset = 1:1段階高い解像度のタイルを使用(z=11のタイルを使用し、zoom 10で表示)
- zoomOffset = -1:低解像度のタイルを使用(z=9のタイルをzoom 10で表示)
これを利用し、zoom 18以上の拡大表示を以下のように設定します:
- zoomが18以下 → zoomOffset = 0
- 18 < zoom <= 19 → zoomOffset = -1
- 19 < zoom → zoomOffset = -2
実装手順:TileLayerのカスタマイズ
実際のコードでTileLayerをどのように拡張するかを見ていきます。 ここでは、deck.glのTileLayerをオーバーライドし、ズームレベルに応じたzoomOffsetを自動的に調整するクラスを作成します。
import DeckGL from '@deck.gl/react';
import { TileLayer } from "@deck.gl/geo-layers";
import { BitmapLayer } from "@deck.gl/layers";
class ZoomRangeTileLayer extends TileLayer {
static layerName = "ZoomRangeTileLayer";
updateState({ props, oldProps, context, changeFlags }: UpdateParameters<this>) {
if (changeFlags.viewportChanged) {
if (context.viewport.zoom > 19) {
props = { ...props, minZoom: 20, maxZoom: 20, zoomOffset: -2 };
} else if (context.viewport.zoom > 18) {
props = { ...props, minZoom: 19, maxZoom: 19, zoomOffset: -1 };
} else {
props = { ...props, minZoom: 5, maxZoom: 18, zoomOffset: 0 };
}
}
super.updateState({ props, oldProps, context, changeFlags });
}
}
export const Map = () => {
const layer = new ZoomRangeTileLayer({
id: "ZoomRangeTileLayer",
data: CHIRIIN_URL,
minZoom: 5,
maxZoom: 18,// Initial stateに応じる
tileSize: 256,
renderSubLayers: props => new BitmapLayer(props, {
data: undefined,
image: props.data,
bounds: (({ west, south, east, north }: any) => [west, south, east, north])(props.tile.bbox),
}),
});
return (
<DeckGL layers={[layer]} />
)
}
コード解説
TileLayerを継承し、updateStateメソッドでズームレベルに応じたzoomOffsetを設定しています。このメソッドではcontext.viewport.zoomを使用して現在のズームレベルを取得し、それに応じてプロパティを変更しています。
また、deck.glにおいてズームレベルは18, 19, 20などの整数ではなく、連続的に小数で与えられます。そのためズームレベルの条件分岐は不等号で表しています。
終わりに
TileLayerのカスタマイズによって、地理院タイルのズームレベル18以上の拡大表示を実現しました。
今回のコードでは、特定のズームレベルに対する条件分岐を導入しましたが、今後は動的にズームレベルを管理するさらなる拡張が可能です。 deck.glを使った高度な地図表示を検討している方にとって、この記事がお役に立てば幸いです。
今回のコードを利用して作成した 文化財マップ もよろしくお願いします。