Reputation: 1937
Is there a way of displaying images with a geoJson mask in Leaflet/another map library? I took "choropleth map of US States" example and I'd like to display a different background image in each state. How can I achieve it?
Here's my code https://jsfiddle.net/d37zg8f9/, as you can see the images overflow from each state. In a perfect world something like that can be achieved by following HTML:
<svg>
<mask id="mask">
<path d=".."></path>
</mask>
<image mask="url(#mask)" href=".."></image>
</svg>
But I'm not sure if there's a way of injecting that into Leaflet.
Upvotes: 1
Views: 780
Reputation: 2998
https://jsfiddle.net/9rzt2uoe/29
You can use the fill
property in CSS to fill SVG paths with SVG patterns.
We need an SVG to hold a bunch of patterns that each contain an image:
<body>
<div id='map'></div>
<svg id='patterns' width="0" height="0">
<defs id='defs'>
</defs>
</svg>
</body>
In onEachFeature
, instead of adding image overlays on the map, images are added as patterns in defs
in the patterns
SVG:
let i = 300;
const svgPatternsDefs = document.getElementById('defs');
function onEachFeature(feature, layer) {
const imageUrl = `https://picsum.photos/${i++}`;
const imageBounds = layer.getBounds();
const imageOverlay = L.imageOverlay(imageUrl, imageBounds);
//imageOverlay.addTo(map);
const imageId = `picture-${i}`;
defs.innerHTML += `
<pattern id='${imageId}' width="1" height="1" viewBox="0 0 100 100" preserveAspectRatio="none">
<image xlink:href='${imageUrl}' width="100" height="100" preserveAspectRatio="none"></image>
</pattern>
`;
Promise.resolve().then(() => { // defers execution
layer.getElement().style.fill = `url(#${imageId})`;
});
}
layer.getElement()
returns undefined
until the layers get added to the map. Code execution can be deferred with Promise.resolve().then
const geoJson = L.geoJson(statesData, {
onEachFeature,
style : {
"fillOpacity" : 1
}
}).addTo(map);
fillOpacity
is 0.2 by default and should be set to 1 for images to be shown correctly.
Upvotes: 1