deck.glで特定の地物を画面内に自動的に収める。
この記事はdeck.gl Advent Calendar 2021 参加記事です。
概要
特定の地物やマーカ群などが画面内にちょうど収まるようにカメラ(viewState)を自動的に設定する方法です。
サンプルコード
都道府県をクリックするとその県が画面内に収まる位置へカメラが移動します。
解説
WebMercatorViewportを使うと、特定の範囲(bounding box)が画面にちょうど収まる緯度経度とズームレベルを算出することができます。
ここでは、turf.jsを使ってクリックされた都道府県のbounding boxを取得し、その値を WebMercatorViewport にわたすことで、クリックされた都道府県がちょうと画面内に収まるようにviewStateを更新しています。
ポイントとしては WebMercatorViewport のインスタンスを生成する際に、deck.glの描画領域のサイズ(width.height)をオプションで指定することです。描画領域のサイズが正しく指定されていないと、正しい値を計算できません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
// WebMercatorViewportを読み込み import DeckGL, { WebMercatorViewport } from "deck.gl"; //turf.jsのbbox関数を読み込み import bbox from "@turf/bbox"; //地物クリック時にviewStateを更新する const clickHandler = (e) => { //クリックされた地物(都道府県)のgeometoryを取得する const geo = e.object.geometry; //turf.jsを使ってgeometryからバウンディボックスを算出する const [minLng, minLat, maxLng, maxLat] = bbox(geo); //座標変換を行うオブジェクトを生成する const viewportWebMercator = new WebMercatorViewport({ width: document.querySelector("#deckgl-wrapper").clientWidth, height: document.querySelector("#deckgl-wrapper").clientHeight }); //指定されたバウンディボックスが画面内に丁度収まる緯度経度とズームレベルを算出する const { longitude, latitude, zoom } = viewportWebMercator.fitBounds( [ [minLng, minLat], [maxLng, maxLat] ], { padding: 0 //地物を画面内に収める際に余白を設定する } ); //viewStateを更新しカメラを地物が収まる位置へ移動する setViewState((v) => { return { ...v, //current viewState latitude: latitude, longitude: longitude, zoom: zoom, transitionDuration: 1000, transitionInterpolator: new FlyToInterpolator() }; }); }; return ( <DeckGL layers={renderLayers({ onClick: clickHandler //geojson layerのonClickプロパティに渡す })} /> ); |