一般的に、GIS サービスから取得したタイルマップを使用して地図を描画する場合、行政区域の形状がデザインに合わせて切り抜かれていることがあります。ただし、提供されたサービスでこの形状を変更することができない場合、フロントエンドで地図を切り抜いて加工する必要があります。
通常、行政区域の形状は GIS サービスから取得するか、静的な GeoJSON リソースから面要素データを取得することができます。必要な形状を切り抜くために、面要素データを使用しますが、OpenLayers にはこれを完了するための組み込みの API はありません。この場合、globalCompositeOperationを使用するためにキャンバスを使用する必要があります。
まず、レイヤーが WebGL レイヤーではないことを確認し、切り抜く対象となる基本レイヤーbaseLayer
を定義する必要があります。
import { Tile } from 'ol/layer'
import { XYZ } from 'ol/source'
const baseLayer = new Tile({
source: new XYZ({
url: `sourceUrl`,
}),
})
もちろん、このレイヤーはタイルマップである必要はありませんが、ほとんどのビジネスではそれが主要なものです。
切り抜き範囲の取得#
次に、切り抜く面要素データを使用して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
イベントを使用します。これは、タイルのレンダリングが完了したがフェードインされていない状態で発生するイベントです。このイベントを使用して、キャンバスの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
に設定すると、キャンバスはキャンバスの内容と重なる部分のみを描画し、他の部分は透明になります。同時に、getVectorContext(evt)
またはbaseLayer
を使用して要素を再描画することで、切り抜かれたタイルマップを取得できます。
静的なコンテンツから切り抜き範囲を取得#
ファイルから取得する場合、VectorLayer
の構築パラメーターの url を features に変更し、ファイルから features を読み取るために format を使用します。
const clipLayer = new VectorLayer({
source: new VectorSource({
features: [new EsriJson().readFeatures(require('パス'))],//formatはサービスと同じです
});
});