enpitsulin

enpitsulin

这个人很懒,没有留下什么🤡
twitter
github
bilibili
nintendo switch
mastodon

Clipping Layers in Openlayers

Generally, when using ol to draw maps, the tile map obtained from the GIS service can be designed and cut into administrative boundaries as needed. However, when the provided service is not easy to modify the shape, the front-end may need to crop and process the map.

Usually, administrative boundaries can be obtained through GIS services or by using static GeoJSON resources to obtain a polygon feature data. We can use the polygon feature data to cut out the desired shape, but OpenLayers does not have a ready-made API to accomplish this. In this case, we need to use the globalCompositeOperation of the canvas to achieve it.

First, make sure that your layer is not a WebGL layer, and then we need to define the base layer baseLayer as the target to be clipped.

import { Tile } from 'ol/layer'
import { XYZ } from 'ol/source'
const baseLayer = new Tile({
  source: new XYZ({
    url: `sourceUrl`,
  }),
})

Of course, this layer does not necessarily have to be a tile map, but in most cases, it is the main one.

Obtaining the Clipping Range from the GIS Service#

Then, you need to create a Vector layer with the clipping polygon feature data and bind the addFeature event of its source to make the visible extent of the base layer consistent with the 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: `provide polygon feature service address`,
    format: new EsriJson() // Here, if the GIS service is in EsriJson format, use the corresponding format if it is GeoJson or other formats
  });
});

clipLayer.getSource().on('addfeature', ()=> {
  baseLayer.setExtent(clipLayer.getSource().getExtent());
});

In this way, the base layer will only load the tiles within the clipping range, and then we need to clip the boundaries.

Here, we need to use the postrender event of the layer, which is triggered after the tile rendering is completed but before the fade-in effect is applied. By setting the globalCompositeOperation of the canvas at this time, we can achieve the clipping effect.

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'
})

When globalCompositeOperation is set to destination-in, the canvas will only draw the content that overlaps with the canvas content, and the rest will remain transparent. At the same time, by redrawing the features using getVectorContext(evt) or baseLayer, we can obtain the tile map after clipping.

Obtaining the Clipping Range from Static Content#

To obtain the clipping range from a file, you just need to replace the url in the constructor parameter of VectorLayer with features, and use the format to read the features from the file.

const clipLayer = new VectorLayer({
  source: new VectorSource({
    features: [new EsriJson().readFeatures(require('path'))],// Use the same format as the service
  });
});
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.