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