diff --git a/examples/style-renderer.css b/examples/style-renderer.css new file mode 100644 index 0000000000..5f29be1fe5 --- /dev/null +++ b/examples/style-renderer.css @@ -0,0 +1,3 @@ +#map { + background: #75d0f0; +} diff --git a/examples/style-renderer.html b/examples/style-renderer.html new file mode 100644 index 0000000000..63593eca0f --- /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 and a clip path 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..1cbe71ba0e --- /dev/null +++ b/examples/style-renderer.js @@ -0,0 +1,75 @@ +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, Stroke, Style} from '../src/ol/style.js'; +import {getBottomLeft, getHeight, getWidth} from '../src/ol/extent.js'; +import {toContext} from '../src/ol/render.js'; + +const fill = new Fill(); +const stroke = new Stroke({ + color: 'rgba(255,255,255,0.8)', + width: 2, +}); +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.save(); + const renderContext = toContext(context, { + pixelRatio: 1, + }); + renderContext.setFillStrokeStyle(fill, stroke); + renderContext.drawGeometry(geometry); + context.clip(); + + // Fill transparent country with the flag image + const bottomLeft = getBottomLeft(extent); + const left = bottomLeft[0]; + const bottom = bottomLeft[1]; + context.drawImage(flag, 2, 12, 60, 40, left, bottom, width, height); + context.restore(); + }, +}); + +const vectorLayer = new VectorLayer({ + source: new VectorSource({ + url: + 'https://openlayersbook.github.io/openlayers_book_samples/assets/data/countries.geojson', + format: new GeoJSON(), + }), + style: style, +}); + +// 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, + }), +}); diff --git a/examples/vector-label-decluttering.html b/examples/vector-label-decluttering.html index 19ae8ab16a..c453b3a2d2 100644 --- a/examples/vector-label-decluttering.html +++ b/examples/vector-label-decluttering.html @@ -1,11 +1,11 @@ --- layout: example.html title: Vector Label Decluttering -shortdesc: Label decluttering with a custom renderer. +shortdesc: Label decluttering on polygons. resources: - https://cdn.polyfill.io/v2/polyfill.min.js?features=Set" docs: > - Decluttering is used to avoid overlapping labels. The `overflow: true` setting on the text style makes it so labels that do not fit within the bounds of a polygon are also included. + Decluttering is used to avoid overlapping labels. The `overflow: true` setting on the text style makes it so labels that do not fit within the bounds of a polygon are also considered for decluttering. tags: "vector, decluttering, labels" ---