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.
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.
Related
I have an link which has the svg file with the format of svg .
svgfilelink
And this link has the following content :
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20px" height="20px" viewBox="0 0 20 20" version="1.1">
<title>Rectangle Copy 14</title>
<defs>
<linearGradient x1="5.7671933%" y1="50.1613046%" x2="99.3732272%" y2="50.1613046%" id="linearGradient-1">
<stop stop-color="#59D08F" offset="0%"/>
<stop stop-color="#26C2DC" offset="100%"/>
</linearGradient>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="06-Shapes-Properties" transform="translate(-1166.000000, -354.000000)" stroke="url(#linearGradient-1)" stroke-width="2">
<rect id="Rectangle-Copy-14" x="1167" y="355" width="18" height="18"/>
</g>
</g>
As of now I'm adding this link as src in img tag .
But I need this link as svg format.
I have tried few methods. But didn't help.
Is there any possible ways to convert the url into svg tag in JAVASCRIPT?
I don't know if this is the right way to do but you can directly fetch that svg and render it to the DOM using innerHTML or something like dangerouslySetInnerHTML with react
let svgUrl = 'https://raw.githubusercontent.com/rahuldkjain/github-profile-readme-generator/master/src/images/icons/Social/hackerrank.svg'
function getTheSvg(url) {
return fetch(url).then(res => res.text());
}
getTheSvg(svgUrl).then(res => {
let svgDiv = document.querySelector('.svg')
svgDiv.innerHTML = res
})
svg {
height: 200px
}
<div class='svg'><div>
If you used create-react-app, it already uses #svgr/webpack package, so you can do this, which will cause the image to load inline as React components containing the SVG elements directly, instead of by a link:
import { ReactComponent as RectangleIcon } from './rectangle.svg';
export const MyComponent = () => {
return <RectangleIcon />
}
If you are not using create-react-app so not using svgr yet, you can add it to your project (see docs)
Trying to make an svg rectangle that moves when button pushed. Right now I just want the x to be modified by a function.
function modX()
{
document.getElementById("rectangle").transform = 'translate(295 115)';
}
var x = 20;
var y = 20;
modX();
<svg width="1000" height="1000" >
<rect id="rectangle" x="0" y="20" width="100" height="100"
style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)"></rect>
</svg>
I'm fairly new to code so please avoid css or jquery.
you can change its x by using javaScript document.getElementById("rectangle").setAttribute('x', X_value)
set the X_value to the value you want it to change.
I need to add SVG objects to specific locations inside an SVG object that's appended to the DOM.
But whenever I do that I see nothing rendered on the screen. I can see the SVG objects are added (in Elements tab of DevTools) but they're not rendered. They're pure SVG (not wrapped around an HTML element like a DIV).
I've tried loading SVGs with ajax and adding them, tried to do with Snap, tried to have these elements inside a <defs> tag, find them with Snap and then add them to the main Snap object. Nothing seems to work. The objects are always added but not rendered.
Is that even possible?
The SVG
<svg width="400" height="300" style="background: gray">
<defs>
<circle id="redc" cx="50" cy="50" r="50" style="fill: red" />
<circle id="yelc" cx="40" cy="40" r="40" style="fill: yellow" />
</defs>
<circle id="bluc" cx="200" cy="200" r="50" style="fill: blue" />
</svg>
JavaScript
const s = Snap("#root");
Snap.load('images/all.svg', function(data){
var all = data;
// append the all.svg node. cool
s.append( all.node );
// get the red circle definition
var redc = all.select('#redc');
s.append(redc.node); // doesn't work
});
with foreign object:
Snap.load('images/all.svg', function(data){
var all = data;
// append the all.svg node. cool
s.append( all.node );
// get the red circle definition
var redc = all.select('#redc');
// foreign object
var foreign = document.createElementNS('http://www.w3.org/2000/svg',"foreignObject");
foreign.setAttribute('width', 500);
foreign.setAttribute('height', 150);
foreign.appendChild(redc);
// add the foreign object - doesn't work
s.append( foreign );
});
It doesn't work because you're appending the circle outside of the <svg> tree i.e. directly under #root which is probably some kind of HTML element such as a <div>
The foreignObject problem is basically the same. Not sure why you're trying to add a circle as a child of a foreignObject (that won't work as you'd need an svg element to be its parent). I've used an html element instead.
const s = Snap("#root");
var svg = '<svg width="400" height="300" style="background: gray"><defs><circle id="redc" cx="50" cy="50" r="50" style="fill: red" /><circle id="yelc" cx="40" cy="40" r="40" style="fill: yellow" /></defs><circle id="bluc" cx="200" cy="200" r="50" style="fill: blue" /></svg>';
var all = Snap.parse(svg);
// append the all.svg node. cool
s.append( all.node );
// get the red circle definition
var redc = all.select('#redc');
all.node.append(redc.node); // append as a child of the svg node
// foreign object
var foreign = document.createElementNS('http://www.w3.org/2000/svg',"foreignObject");
foreign.setAttribute('width', 500);
foreign.setAttribute('height', 150);
foreign.setAttribute('fill', 'pink');
var p = document.createElement('p');
foreign.appendChild(p);
var text = document.createTextNode("Hello World");
p.appendChild(text);
// add the foreign object to the correct part of the tree
all.node.append( foreign );
<script src="http://snapsvg.io/assets/js/snap.svg-min.js"></script>
<div id="root"></div>
In jQuery you can simply creating an element by providing a string, like so:
var newElement = $('<div></div>');
How can I do the same thing in Snap SVG? I have a string like
<rect x="100" y="100" transform="matrix(-0.7071 0.7071 -0.7071 -0.7071 1825.4047 1024.3746)" fill="#7EC242" width="230.02" height="56.723" stroke="#64bc46"/>
And I need an Element I can append to an already existing Snap document. I tried fragments, but they don't have all functions I need to manipulate the element afterwards.
I believe you can do it with parse (I removed the transform so the code could work in the small SO snippet window):
var s = Snap("#svg");
var string = '<rect x="100" y="100" fill="#7EC242" width="230.02" height="56.723" stroke="#64bc46"/>'
var rect = Snap.parse(string);
s.append(rect);
<script src="http://cdn.jsdelivr.net/snap.svg/0.1.0/snap.svg-min.js"></script>
<svg id="svg" width="400" height="200">
</svg>
If I have inline SVG, including an element which has been scaled...
<g transform="scale(sX,sY)">
<rect id="myElement" x="107" y="32" width="245" height="31" stroke="#C6C3C6" stroke-width="1px" />
</g>
... or which is in a <svg> element with a viewBox attribute:
<svg viewBox="20 20 5000 1230">
<g transform="scale(sX,sY)">
<rect id="myElement" x="107" y="32" width="245" height="31" stroke="#C6C3C6" stroke-width="1px" />
</g>
<svg>
... how can I programmatically find the new scaled width in pixels of myElement - without manually detecting the scaling and doing the math? So far myElement.getBBox().width returns 245 without accounting for the scaling.
please check this fiddle http://jsfiddle.net/T723E/. Click on the rectangles and note the firebug console.
Here i have hard coded a number .3 which is 300px width of div containing svg node / 1000 user units.
After seeing the bounty, this is the function i have return to get the scaled width without much (with no maths i'm not sure.)maths.Use matrix.d for getting scaled height
var svg = document.getElementById('svg');
function getTransformedWidth(el){
var matrix = el.getTransformToElement(svg);
return matrix.a*el.width.animVal.value;
}
var ele = document.getElementById('myElement_with_scale')
console.log("scale width----", getTransformedWidth(ele))
Please look this fiddle for complete code http://jsfiddle.net/b4KXr/
Have you investigated the parameter you can use with getBBox()?
http://raphaeljs.com/reference.html#Element.getBBox