diff --git a/examples/style-renderer.html b/examples/style-renderer.html new file mode 100644 index 0000000000..aa33f0a455 --- /dev/null +++ b/examples/style-renderer.html @@ -0,0 +1,10 @@ +--- +layout: example.html +title: Style renderer +shortdesc: Example of a style with a custom renderer. +docs: > + A custom style renderer, a prerender event and different global composite operations are used to render the flag of a country as fill for the country shape. +tags: "vector, geojson, style, custom, renderer" +--- +
+
 
diff --git a/examples/style-renderer.js b/examples/style-renderer.js new file mode 100644 index 0000000000..bc857323f5 --- /dev/null +++ b/examples/style-renderer.js @@ -0,0 +1,76 @@ +import GeoJSON from '../src/ol/format/GeoJSON.js'; +import Map from '../src/ol/Map.js'; +import VectorLayer from '../src/ol/layer/Vector.js'; +import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; +import {Fill, Style} from '../src/ol/style.js'; +import {getBottomLeft, getHeight, getWidth} from '../src/ol/extent.js'; +import {toContext} from '../src/ol/render.js'; + +const polygonFill = new Fill(); +const style = new Style({ + renderer: function (pixelCoordinates, state) { + const context = state.context; + const geometry = state.geometry.clone(); + geometry.setCoordinates(pixelCoordinates); + const extent = geometry.getExtent(); + const width = getWidth(extent); + const height = getHeight(extent); + const flag = state.feature.get('flag'); + if (!flag || height < 1 || width < 1) { + return; + } + // Stitch out country shape from the blue canvas + context.globalCompositeOperation = 'destination-out'; + const renderContext = toContext(context, { + pixelRatio: 1, + }); + renderContext.setFillStrokeStyle(polygonFill); + renderContext.drawGeometry(geometry); + const bottomLeft = getBottomLeft(extent); + // Fill transparent country with the flag image + context.globalCompositeOperation = 'destination-over'; + const left = bottomLeft[0]; + const bottom = bottomLeft[1]; + context.drawImage(flag, 2, 12, 60, 40, left, bottom, width, height); + }, +}); + +const vectorLayer = new VectorLayer({ + source: new VectorSource({ + url: + 'https://openlayersbook.github.io/openlayers_book_samples/assets/data/countries.geojson', + format: new GeoJSON(), + }), + style: style, +}); + +// Fill the canvas blue as clip mask for flag images +vectorLayer.on('prerender', function (event) { + const context = event.context; + context.globalCompositeOperation = 'source-over'; + context.fillStyle = 'rgb(152,293,253)'; + context.fillRect(0, 0, context.canvas.width, context.canvas.height); +}); + +// Load country flags and set them as `flag` attribute on the country feature +vectorLayer.getSource().on('addfeature', function (event) { + const feature = event.feature; + const img = new Image(); + img.onload = function () { + feature.set('flag', img); + }; + img.src = + 'https://www.countryflags.io/' + + feature.get('iso_a2').toLowerCase() + + '/flat/64.png'; +}); + +new Map({ + layers: [vectorLayer], + target: 'map', + view: new View({ + center: [0, 0], + zoom: 1, + }), +});