一般的に、GIS サービスから取得したタイル地図を使用して地図を描画する場合、行政区画の形状が必要な場合は、デザインに必要な形状で切り取られたタイル地図を取得できます。ただし、提供されたサービスでこの形状を変更することができない場合、フロントエンドで地図を切り取って加工する必要があるかもしれません。
通常、行政区画の形状は、GIS サービスから取得するか、静的な GeoJSON リソースを使用して面要素データを取得することができます。必要な形状を切り取るために、面要素データを使用しますが、OpenLayers にはこれを完了するための組み込みの API はありません。その場合は、canvas のglobalCompositeOperationを使用する必要があります。
まず、レイヤーが WebGL レイヤーではないことを確認し、切り取り対象としての基本レイヤーbaseLayer
を定義する必要があります。
import { Tile } from 'ol/layer'
import { XYZ } from 'ol/source'
const baseLayer = new Tile({
source: new XYZ({
url: `sourceUrl`,
}),
})
もちろん、このレイヤーはタイル地図である必要はありませんが、ほとんどのビジネスではそれが主要なものです。
GIS サービスから切り取り範囲を取得#
次に、切り取りの面要素データを使用してVector
レイヤーを作成し、そのソースのaddFeature
イベントをバインドして基本レイヤーの可視範囲をclipLayer
と一致させる必要があります。
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import EsriJson from 'ol/format/EsriJSON';
const clipLayer = new VectorLayer({
source: new VectorSource({
url: `提供面要素服务地址`,
format: new EsriJson() // ここでGISサービスがEsriJson形式であるため、GeoJsonやその他の形式の場合は対応するフォーマットを使用します
});
});
clipLayer.getSource().on('addfeature', ()=> {
baseLayer.setExtent(clipLayer.getSource().getExtent());
});
これにより、基本レイヤーは切り取り範囲内のタイルのみをロードするようになります。次に、境界を切り取る必要があります。
ここで、レイヤーのpostrender
イベントを使用します。これは、タイルのレンダリングが完了したが、フェードインがロードされていない状態で発生するイベントです。このイベントを使用して、canvas のglobalCompositeOperation
を設定することで、切り取り効果を得ることができます。
baseLayer.on('postrender', (evt) => {
if (!evt.context || !('save' in evt.context)) return
const vecCtx = getVectorContext(evt)
evt.context.globalCompositeOperation = 'destination-in'
clipLayer.getSource().forEachFeature((feature) => {
vecCtx.drawFeature(feature, style)
})
evt.context.globalCompositeOperation = 'source-over'
})
globalCompositeOperation
がdestination-in
に設定されている場合、canvas はキャンバスの内容と重なる部分のみを描画し、他の部分は透明に保ちます。同時に、getVectorContext(evt)
またはbaseLayer
を使用して要素を再描画することで、切り取り後のタイル地図を取得できます。
静的なコンテンツから切り取り範囲を取得#
ファイルから取得する場合は、VectorLayer
の構築パラメータの url を features に変更し、フォーマットを使用してファイルから features を読み取るだけです。
const clipLayer = new VectorLayer({
source: new VectorSource({
features: [new EsriJson().readFeatures(require('パス'))],//フォーマットはサービスと同じです
});
});