I'm trying to display and an external image inside an svg and then change it on button click. I can't get the background to show nor can I get it to change.
here is my fiddle:
https://jsfiddle.net/bsp9601z/
<head><meta http-equiv="X-UA-Compatible" content="IE=edge">
</head>
<div id="slider"></div>
<button onclick="go()">change background</button>
<g id="backgroundImage">
<image width="100%" height="100%" xlink:href="http://www.menucool.com/slider/jsImgSlider/images/image-slider-2.jpg" /></g>
<svg width="792pt" height="612pt" viewBox="0 0 792 612" enable-background="new 0 0 792 612"
version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" >
</svg>
</svg>
function go(){
var im = document.getElementById('backgroundImage');
im.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', 'http://demo.elmanawy.info/moraco/layout1/assets/images/portfolio/8.jpg');
im.setAttributeNS('http://www.w3.org/1999/xlink','width', "100%");
im.setAttributeNS('http://www.w3.org/1999/xlink','height', "100%");
}
You are missing <svg> tags and selecting <g> rather than <image>
<button onclick="go()">change background</button>
<svg>
<g id="backgroundImage">
<image width="100%" height="100%" xlink:href="http://www.menucool.com/slider/jsImgSlider/images/image-slider-2.jpg" />
</g>
</svg>
<script>
function go() {
var im = document.getElementById('backgroundImage').querySelector("image");
im.setAttributeNS('http://www.w3.org/1999/xlink'
, 'xlink:href'
, 'http://demo.elmanawy.info/moraco/layout1/assets/images/portfolio/8.jpg');
}
</script>
Related
I have SVG file that i created it in photoshop. I would like to use it in my html page with clip-path property. I am trying to implement it as using clip-path:url(#mysvg); and paste the svg code to my html page. But i does not work. How can i do that?
My purpose is like this with css:
Here is the .svg file:
https://svgshare.com/i/dfw.svg
Here is the svg code
<!--IMAGE-->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 814 506" >
<image id="image" class="image__svg-image" width="100%" height="100%" clip-path="url(#mask)" x="-100px" xlink:href="https://res.cloudinary.com/alvarosaburido/image/upload/v1589435086/blog/The%20Magic%20of%20SVG%20Clip-path/pic_yo5eyq.png" />
</svg>
<!--MY SVG FILE-->
<svg xmlns="http://www.w3.org/2000/svg" width="1920" height="1920" viewBox="0 0 1920 1920">
<metadata><?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c142 79.160924, 2017/07/13-01:06:39 ">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""/>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?></metadata>
<defs>
<style>
.cls-1 {
fill: #fff;
fill-rule: evenodd;
}
</style>
</defs>
<path id="rect1" class="cls-1" d="M133,333.637L1426.05,171.265a157.557,157.557,0,0,1,175.99,136.647l157.93,1256.5L466.929,1726.79a157.574,157.574,0,0,1-176-136.65Z"/>
</svg>
In this example the viewBox of the <svg> is 100 in width and the image also takes up 100% of the width. So, no matter the actual width of the image it will always fill the entire SVG.
The <clipPath> fits in the size of the viewBox of the <svg> that holds the image. I know the width is 100, so I made the clippath 70 in height and width plus the extra height that the rotation takes up. This matches kind of the height of the images (unknown at this point).
I replaced the content of the <clipPath>. It is more "transparent" what the clip path does and easier to manipulate.
<!--IMAGE-->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="300">
<image width="100%" href="https://res.cloudinary.com/alvarosaburido/image/upload/v1589435086/blog/The%20Magic%20of%20SVG%20Clip-path/pic_yo5eyq.png" clip-path="url(#mask)" />
</svg>
<!--MY SVG FILE-->
<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
<defs>
<clipPath id="mask" transform="translate(15 0) rotate(-10 60 0)">
<rect width="50" height="50" />
<rect x="20" y="20" width="50" height="50" />
<rect x="20" width="50" height="50" rx="10" />
<rect y="20" width="50" height="50" rx="10" />
</clipPath>
</defs>
</svg>
Update
OP asks if the original path can be used as a clip-path. It can, but the viewBox needs to be modified accordingly. So, if the viewbox 0 0 2300 1800 is used the path fits the image.
<!--IMAGE-->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2300 1800" width="300">
<image width="100%" href="https://res.cloudinary.com/alvarosaburido/image/upload/v1589435086/blog/The%20Magic%20of%20SVG%20Clip-path/pic_yo5eyq.png" clip-path="url(#mask)" />
</svg>
<!--MY SVG FILE-->
<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
<defs>
<clipPath id="mask" transform="translate(350 0)">
<path id="rect1" class="cls-1" d="M133,333.637L1426.05,171.265a157.557,157.557,0,0,1,175.99,136.647l157.93,1256.5L466.929,1726.79a157.574,157.574,0,0,1-176-136.65Z"/>
</clipPath>
</defs>
</svg>
Update
To "path" or not to "path", that is the question. This third example is a better solution. The path is simpler and there are not that many child elements in <clipPath>.
<!--IMAGE-->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 11 11" width="300">
<image width="100%" href="https://res.cloudinary.com/alvarosaburido/image/upload/v1589435086/blog/The%20Magic%20of%20SVG%20Clip-path/pic_yo5eyq.png" clip-path="url(#mask)" />
</svg>
<!--MY SVG FILE-->
<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
<defs>
<clipPath id="mask" transform="translate(2 0) rotate(-10 7 0)">
<path d="M 0 0 L 6 0 A 1 1 90 0 1 7 1 L 7 7 L 1 7 A 1 1 90 0 1 0 6 Z"/>
</clipPath>
</defs>
</svg>
Update
This fourth example is using the original path, BUT defined in a <clipPath> and used as an external reference in CSS. The external SVG file have the following content:
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="mask" transform="translate(350 0)">
<path id="rect1" class="cls-1" d="M133,333.637L1426.05,171.265a157.557,157.557,0,0,1,175.99,136.647l157.93,1256.5L466.929,1726.79a157.574,157.574,0,0,1-176-136.65Z"/>
</clipPath>
</defs>
</svg>
But for this example I replace the URL (like https://svgshare.com/i/dfw.svg#rect) to the SVG file with a data URI.
svg>image {
clip-path: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxkZWZzPgogICAgPGNsaXBQYXRoIGlkPSJtYXNrIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgzNTAgMCkiPgogICAgICA8cGF0aCBpZD0icmVjdDEiIGNsYXNzPSJjbHMtMSIgZD0iTTEzMywzMzMuNjM3TDE0MjYuMDUsMTcxLjI2NWExNTcuNTU3LDE1Ny41NTcsMCwwLDEsMTc1Ljk5LDEzNi42NDdsMTU3LjkzLDEyNTYuNUw0NjYuOTI5LDE3MjYuNzlhMTU3LjU3NCwxNTcuNTc0LDAsMCwxLTE3Ni0xMzYuNjVaIi8+CiAgICA8L2NsaXBQYXRoPgogIDwvZGVmcz4KPC9zdmc+#mask');
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2300 1800" width="300">
<image width="100%" href="https://res.cloudinary.com/alvarosaburido/image/upload/v1589435086/blog/The%20Magic%20of%20SVG%20Clip-path/pic_yo5eyq.png" />
</svg>
<svg>
<!--SOME SVG CODE HERE-->
<g id="bg"> <!--More svg code-->
</g>
</svg>
<!--Imports-->
<script src="script.js"></script>
<link rel="stylesheet" href="st.css">
</html>
CSS:
#bg{
height:100%;
}
When i use javascript to change the height:
document.getElementById("bg").style.height = "500px"
nothing happens, and, when i try to print the height in screen, it's returns nothing:
alert(document.getElementById("bg").style.height)
what can i do to change the height with javascript.
if you need to give a width and a height to an element inside an svg element you have to use a <symbol> with a viewBox instead of a group. Next you have to use the <symbol>and you can give a width and a height to the <use> element
svg{border:solid}
<svg viewBox="0 0 200 100" width="300">
<symbol id="c" viewBox="0 0 20 20">
<circle cx="10" cy="10" r="5"/>
</symbol>
<use xlink:href="#c" x="10" y="10" width="40" height="40" />
</svg>
Let's say I have the following html context, which I don't have access to its creation :
<div id="outer">
<div id="chart-div">
<svg id="chart"></svg>
</div>
<div id="legend-div">
<svg id="legend"></svg>
</div>
</div>
What I'm trying to do is export this SVG to an image using canvg library, the problem here is that they are separated and so I get two canvas, and canvg library accepts a SVG definition string as input.
How can I modify the html elements above so that they are only one SVG? Using Javascript as this is a browser extension.
I have tried just switching the DIVs tags to SVG but it just broke everything and the SVG became blank
This is my solution to your problem: I make the outer div display:none, I'm creating another svg element (you may do it dynamicaly) end inside the #new svg I'm using the #chart and the #legend. I hope it helps.
svg{border:1px solid;}
#outer {display:none}
#outer div{position:absolute; width:500px;}
<div id="outer">
<div id="chart-div">
<svg id="chart" viewBox="0 0 300 150">
<circle stroke="gold" fill="none" cx="100" cy="75" stroke-width="40" stroke-dasharray="124.85" stroke-dashoffset="20" r="20" />
</svg>
</div>
<div id="legend-div">
<svg id="legend" viewBox="0 0 300 150">
<rect fill="skyBlue" x="200" y="100" width="80" height ="30" />
</svg>
</div>
</div>
<svg id="new" viewBox="0 0 300 150" width="500">
<use xlink:href="#chart" />
<use xlink:href="#legend" />
</svg>
This is a Javascript solution for merging two svg accessibles in the document through DOM manipulation.
var svgNS = "http://www.w3.org/2000/svg";
var outer = document.getElementById('outer');
// get chart content
var chart = document.getElementById('chart-div');
var chartSvg = chart.getElementsByTagName('svg')[0];
var chartContent = Array.from(chartSvg.childNodes);
// get legend content
var legend = document.getElementById('legend-div');
var legendSvg = legend.getElementsByTagName('svg')[0];
var legendContent = Array.from(legendSvg.childNodes);
// create a merged-div where we are going to merge the svgs
var merged = document.createElement('div');
merged.setAttribute('id', 'merged-div');
outer.appendChild(merged);
// createElementNS for svg
var mergedSvg = document.createElementNS(svgNS, 'svg');
mergedSvg.setAttribute('id', 'merged');
// keep the viewBox of the chart
mergedSvg.setAttribute('viewBox', chartSvg.getAttribute('viewBox'));
merged.appendChild(mergedSvg);
// adding the content of both svgs
for (let i = 0; i < chartContent.length; i++) {
mergedSvg.appendChild(chartContent[i]);
}
for (let i = 0; i < legendContent.length; i++) {
mergedSvg.appendChild(legendContent[i]);
}
// the unmerged svgs can be removed
chart.remove();
legend.remove();
<div id="outer">
<div id="chart-div">
<svg id="chart" viewBox="0 0 300 150">
<circle stroke="gold" fill="none" cx="100" cy="75" stroke-width="40" stroke-dasharray="124.85" stroke-dashoffset="20" r="20" />
</svg>
</div>
<div id="legend-div">
<svg id="legend" viewBox="0 0 300 150">
<rect fill="skyBlue" x="200" y="100" width="80" height ="30" />
</svg>
</div>
</div>
Resulting markup:
<div id="outer">
<div id="merged-div">
<svg id="merged" viewBox="0 0 300 150">
<circle stroke="gold" fill="none" cx="100" cy="75" stroke-width="40" stroke-dasharray="124.85" stroke-dashoffset="20" r="20"></circle>
<rect fill="skyBlue" x="200" y="100" width="80" height="30"></rect>
</svg>
</div>
</div>
I have an HTML file, that has a link to export all the <svg> inside to one .SVG. That's perfect, it's what I need and the community helped me a lot.
Now I have a problem that all the SVG inside the file, are clogged on top of each other.
I need them to keep the same 'display' they have on the webpage. I tried using internal, inline and external style... But nothing worked.
The X and Y I have in the <svg> is executed when I open the .SVG file in any program, but it doesn't affect anything on the HTML document.
I'm using the svg-converter.js to get all the .svg inside the <img> and convert to <svg>.
For some reason, inside that JS, something don't let me group all the <svg> inside another <svg>, only inside <div>. I have no idea if that is somehow causing the problem of the style not being exported.
Here is the working link.
Any help will be much appreciated.
Ps: I'd love to know why my question is downvoted.
You need to use x and y attributes to arrange your inner <svg> elements inside your root <svg> element.
Something like this (I've replaced the SVG contents with circles for brevity):
<svg xmlns="http://www.w3.org/3000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="100%" height="100%" viewBox="0 0 1224 1224">
<svg x="0" y="0" width="50%" height="50%" viewBox="0 0 612 612">
<circle fill="#7AB344" cx="306" cy="306" r="250"/>
</svg>
<svg x="50%" y="0" width="50%" height="50%" viewBox="0 0 612 612">
<circle fill="#8DD4F0" cx="306" cy="306" r="250"/>
</svg>
<svg x="0" y="50%" width="50%" height="50%" viewBox="0 0 612 612">
<circle fill="orange" cx="306" cy="306" r="250"/>
</svg>
<svg x="50%" y="50%" width="50%" height="50%" viewBox="0 0 612 612">
<circle fill="rebeccapurple" cx="306" cy="306" r="250"/>
</svg>
</svg>
THIS IS THE FINAL WORKING CODE:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/3000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<head>
<meta charset="UTF-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://brand.express/projects/teste/svg-converter.js"></script>
</head>
<body>
<main id="content">
<div id="mySVG" style="width:100%;padding:0;margin:0;">
<img src='img/leafers-sapling.svg' class='svg-convert' x="0" y="0" width="286px">
<img src='img/aqualine-sapling.svg' class='svg-convert' x="286px" y="0" width="286px">
<img src='img/leafers-sapling.svg' class='svg-convert' x="572px" y="0" width="286px">
<img src='img/aqualine-sapling.svg' class='svg-convert' x="858px" y="0" width="286px">
</div>
</main>
<script>
//transforma os .svg para <svg>
jQuery(document).ready(function($) {
$('.svg-convert').svgConvert({
onComplete: function() {
exportSVG(document.getElementById('mySVG'));
},
svgCleanupAttr: []
});
});
</script>
<script>
var exportSVG = function(divContainer) {
var svgContainer = document.createElementNS("http://www.w3.org/1999/xhtml", "svg");
svgContainer.setAttribute('width','1200px');
$('#mySVG').find("svg").clone().appendTo(svgContainer);
var svgData = svgContainer.outerHTML;
var a = document.createElement('a');
a.href = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(svgData);
a.download = 'finalSVG.svg';
a.innerHTML = 'download the .SVG file';
document.body.appendChild(a);
};
</script>
</body>
</html>
I'm trying to use only certain group of elements from external SVG file(icons.svg) and use the selected group to create another SVG tag. The reason for trying to have it this way is that I don't want to have separate SVG file for every single icon as there will be tons of them eventually.
I prefer using D3 and currently my HTML code is following (which doesn't work):
<!DOCTYPE html>
<meta charset="utf-8">
<head><script src="https://d3js.org/d3.v3.js"></script></head>
<body>
<script>
d3.xml("icons.svg").mimeType("image/svg+xml").get(function(error, xml) {
if (error) throw error;
iconSvg = xml.getElementsByTagName("svg")[0];
sel = d3.select(iconSvg).selectAll("#icon2");
var newSvg = d3.select("body").append("svg")
.attr({"id":"newicon", "width":50, "height":50
}).append(sel);
});
</script>
The "icons.svg" file content is following:
<?xml version="1.0" encoding="utf-8"?>
<svg width="100%" version="1.1" id="icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
<g id="icon1" width="16" height="16" >
<circle cx="7.5" cy="7.5" r="6.0" stroke="black" stroke-width="1" fill="#00AD5A" />
</g>
<g id="icon2" width="16" height="16" >
<circle cx="7.5" cy="7.5" r="6.0" stroke="black" stroke-width="1" fill="#FF0000" />
</g>
<g id="icon3" width="16" height="16" >
<circle cx="7.5" cy="7.5" r="6.0" stroke="black" stroke-width="1" fill="#FF00FF" />
</g>
</svg>
I'd be thankful for any help!
I found one solution to the problem. I changed lines
sel = d3.select(iconSvg).selectAll("#icon2");
to this:
sel = d3.select(iconSvg).select("#icon2").html();
and
var newSvg = d3.select("body").append("svg")
.attr({"id":"newicon", "width":50, "height":50
}).append(sel);
to this:
var newSvg = d3.select("body").append("svg")
.attr({"id":"newicon", "width":50, "height":50
}).append("g").html(sel);
and the end result is what I want.