enpitsulin

enpitsulin

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

Clipping Layers in Openlayers

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

Generally, the administrative division shape can be obtained through the GIS service 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 complete it.

First, make sure that your layer is not a WebGL layer, and then we need to define a 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 patch map, but most of the business is based on this.

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, because the GIS service is in EsriJson format, if it is GeoJson or other formats, use the corresponding format
  });
});

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

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

Here, we need to use the postrender event of the layer, which is an event that occurs 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 patch map after cropping.

Obtaining the Clipping Range from Static Content#

To obtain it from a file, just replace the url in the VectorLayer constructor parameter 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'))],//format is the same as the service
  });
});
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.