I have some SVG files whereby one includes the other by using <use /> elements. To merge all those files into one resulting one, I have written some code that transforms ./main.svg from below:
#file: ./svg/shared.svg
<svg>
<image xlink:href="../img/bg.png" id="bg" />
</svg>
#file: ./svg/index.svg
<svg id="index">
<use xlink:href="./shared.svg#bg" />
</svg>
#file: ./main.svg
<svg>
<use xlink:href="./svg/index.svg#index" />
</svg>
into:
<svg>
<defs>
<svg id="svg-index">
<defs>
<image xlink:href="./img/bg.png" id="img-bg" />
</defs>
<use xlink:href="#img-bg" />
</svg>
</defs>
<use xlink:href="#svg-index" />
</svg>
So basically all urls and Ids are resolved and referenced nodes are imported. The script works fine, in Firefox and the result works as well in Inkscape. BUT in chromium the images do not show up. They are loaded, what I can see from the networking tab.
If I modify the images' xlink:href (inspector panel) by adding a little #qwertz at the end of one image, all of them show up, so that seams to be browser related, since the result works in FF and Inkscape.
Any Idea how to fix that?
UPDATE
One thing that may have some effect here is whether the manipulated SVG is already inserted into the dom or not. So this code makes the images appear:
setTimeout(function () {
[...document.querySelectorAll('image')].forEach(
img => img.setAttribute('xlink:href',
img.getAttribute('xlink:href')
)
);
}, 0)
But that feels really hackish and I am really interested in a »cleaner« solution here…
Related
I'm trying to hack together a sprite sheet from a set of icons. I know almost nothing about SVG. I can get the simple icons to work, but an icon with a clip path isn't displaying properly. From what I can tell it seems like it's not using the clip path.
The sprite works in jsfilddle and it works if I just load the svg on it's own and include a < use > statement in the SVG. But if I have a separate < use > it doesn't work.
All my testing has been done in Chrome (50.0.2661.94)
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<clipPath id="folder-clip-0">
<path d="..." />
</clipPath>
<symbol id="folder" viewBox="0 0 32 32">
<g class="container" data-width="32" data-height="27" transform="translate(0 2)">
<path d="..." class="..." />
<path class="..." d="..." />
<path clip-path="url(#folder-clip-0)" d="..." class="..." />
</g>
</symbol>
</defs>
</svg>
I'm using it like so:
<svg>
<use
xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="/img/path/sprite.svg#folder">
</use>
</svg>
When I use the separate statement it looks like this:
But it should look like this:
The color difference is not relevant, it's just the background when the image was taken.
Edit:
I just discovered that if I dump the whole sprite sheet into the page HTML and reference it locally instead of an external file it works. So I don't know what's wrong with my external reference.
e.g.
<svg>
<use xlinkHref={"/img/path/not/work/sprite.svg#folder"}></use>
</svg>
vs.
<svg>
<symbol id="folder"></symbol>
</svg>
<svg>
<use xlinkHref={"#folder"}></use>
</svg>
This works for me as a fallback, but I'd rather have an external SVG file instead of embedding it in my HTML.
Edit 2:
If the SVG sprite sheet is embeded in the HTML directly using the external link shows the icon correctly.
This seems to be a browser support issue. Using the external reference works as expected in Firefox. Chrome doesn't handle clip paths and some other functions in external references. There's an outstanding bug report filed. Safari also doesn't support it.
Related StackOverflow ticket: Why can't I reference an SVG linear gradient defined in an external file (paint server)?
Open bugs:
https://code.google.com/p/chromium/issues/detail?id=109212
https://bugs.webkit.org/show_bug.cgi?id=105904
The following attempt to make a rectangle with a pattern fill doesn't seem to work in Safari 6.1, Firefox 30, or Chrome 36, even though the W3 spec seems to say that a I can use a non-local IRI reference, including a relative one, like fill="url(localURL.svg#MyId)".
test.html
<html>
<head>
<style>
.patterned { fill: url("patterns.svg#polkadot");
stroke: lime; stroke-width: 5px}
</style>
</head>
<body>
<svg width="500" height="500">
<rect class="patterned" height="27" width="58">
</svg>
</body>
</html>
patterns.svg
<svg xml:space="preserve" width="225" height="110" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<pattern id="polkadot" patternunits="userSpaceOnUse" x="0" y="0" width="20" height="20">
<circle r="10" cx=12 cy=10 fill="purple">
</pattern>
</defs>
</svg>
Safari and Chrome show a black-filled green-outlined rectangle. Firefox shows an empty or white-filled green-outlined rectangle. None of them show the pattern of purple circles.
I'm trying this approach because I couldn't get an SVG fill pattern to work on Safari in the Backbone+JQuery+D3 project I'm working on using the most common method, an inline defs with fill="url(#MyId)". I couldn't get that approach to fail as a simple test case -- I thought I had, but that turned out to be a different Safari bug with an obvious workaround. At least that approach worked in some browsers.
You've a load of syntax errors in your patterns.svg file. Missing " characters round attribute values, an unclosed circle element, patternunits instead of patternUnits.
SVG standalone must be valid XML, it's not as forgiving as html and it's case sensitive on attribute names too. If you loaded the patterns.svg file directly, browsers would tell you all these things.
With all this fixed (as below) this works in Firefox. I'm not sure Chrome/Webkit have implemented this yet.
<svg xml:space="preserve" width="225" height="110" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<pattern id="polkadot" patternUnits="userSpaceOnUse" x="0" y="0" width="20" height="20">
<circle r="10" cx="12" cy="10" fill="purple"/>
</pattern>
</defs>
</svg>
I'm trying to hack together a sprite sheet from a set of icons. I know almost nothing about SVG. I can get the simple icons to work, but an icon with a clip path isn't displaying properly. From what I can tell it seems like it's not using the clip path.
The sprite works in jsfilddle and it works if I just load the svg on it's own and include a < use > statement in the SVG. But if I have a separate < use > it doesn't work.
All my testing has been done in Chrome (50.0.2661.94)
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<clipPath id="folder-clip-0">
<path d="..." />
</clipPath>
<symbol id="folder" viewBox="0 0 32 32">
<g class="container" data-width="32" data-height="27" transform="translate(0 2)">
<path d="..." class="..." />
<path class="..." d="..." />
<path clip-path="url(#folder-clip-0)" d="..." class="..." />
</g>
</symbol>
</defs>
</svg>
I'm using it like so:
<svg>
<use
xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="/img/path/sprite.svg#folder">
</use>
</svg>
When I use the separate statement it looks like this:
But it should look like this:
The color difference is not relevant, it's just the background when the image was taken.
Edit:
I just discovered that if I dump the whole sprite sheet into the page HTML and reference it locally instead of an external file it works. So I don't know what's wrong with my external reference.
e.g.
<svg>
<use xlinkHref={"/img/path/not/work/sprite.svg#folder"}></use>
</svg>
vs.
<svg>
<symbol id="folder"></symbol>
</svg>
<svg>
<use xlinkHref={"#folder"}></use>
</svg>
This works for me as a fallback, but I'd rather have an external SVG file instead of embedding it in my HTML.
Edit 2:
If the SVG sprite sheet is embeded in the HTML directly using the external link shows the icon correctly.
This seems to be a browser support issue. Using the external reference works as expected in Firefox. Chrome doesn't handle clip paths and some other functions in external references. There's an outstanding bug report filed. Safari also doesn't support it.
Related StackOverflow ticket: Why can't I reference an SVG linear gradient defined in an external file (paint server)?
Open bugs:
https://code.google.com/p/chromium/issues/detail?id=109212
https://bugs.webkit.org/show_bug.cgi?id=105904
Suppose you have multiple SVG tags where in each you define a different clip path with the same ID.
<svg id="svg1" width="200" height="200">
<defs>
<clipPath id="nodeclipper">
<rect width="100" height="100" x="0" y="0" />
</clipPath>
</defs>
</svg>
<svg id="svg2" width="200" height="200">
<defs>
<clipPath id="nodeclipper">
<circle cx="20" cy="0" r="40" />
</clipPath>
</defs>
</svg>
I also made a JSFiddle. What is the expected behaviour? I thought that an element could only reference definitions inside its own SVG tag, but that doesn't seem to be the case:
Chrome 26: Uses circle clip path two times.
Firefox 17: Uses rect clip path two times.
Safari 6: Renders one rect and one circle clip path as expected.
It gets weird when you hide one of the SVG tags because Chrome and Safari then drop the clip-path entirely.
I know it works when the clipPaths have different IDs but is it supposed to be that way? As far as I see the spec doesn't contain information about the issue.
What you are doing is invalid per http://www.w3.org/TR/SVG/struct.html#IDAttribute this references http://www.w3.org/TR/2008/REC-xml-20081126/ which addresses this specific issue directly...
Values of type ID MUST match the Name production. A name MUST NOT appear more than once in an XML document as a value of this type; i.e., ID values MUST uniquely identify the elements which bear them.
I'm needing to mask an image with an SVG element. I have a very detailed inline SVG element on my page, that I would like to use as a mask for an image that will be loaded. My SVG is drawn with a <path>. I would like to something similar to this example http://jsfiddle.net/pjgalbraith/cnLHE/. *I do notice that this example does not work in Chrome or IE9 for me though, only FF.
This is my basic structure.
<div>
<svg width="500" height="500">
<mask id="myMask'>
<g>
<path/>
</g>
</mask>
</svg>
<img src="http://myImage.jpg" style="mask:url(#myMask);">
</div>
I've tried adding a <mask> tag inside the SVG wrapping the group <g>, that did not work.
This makes my SVG graphic completely transparent though, so I assume it's trying to work, and the SVG is acting as a mask, but the image is not masked at all, just overlays the position. Does the <img> need to be inside of the <svg> or something like that?
Does anyone have SVG experience and would know how to do this? Every example I see uses simple rect or svg graphics to mask, but no paths. Maybe that's why? Thanks
You can get it to work pretty much everywhere if you put the image inside the svg, like this:
<svg width="220" height="220">
<mask maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox" id="m1">
<linearGradient id="g" gradientUnits="objectBoundingBox" y2="0.5" x2="1" y1="0.5" x1="0">
<stop stop-color="white" offset="0"/>
<stop stop-color="white" stop-opacity="0" offset="1"/>
</linearGradient>
<rect id="svg_1" height="1" width="1" y="0" x="0" stroke-width="0" fill="url(#g)"/>
</mask>
<image xlink:href="http://upload.wikimedia.org/wikipedia/en/thumb/0/08/DioHolyDiver.jpg/220px-DioHolyDiver.jpg" width="100%" height="100%" class="target"/>
</svg>
Here's the updated fiddle showing this: http://jsfiddle.net/cnLHE/34/
To answer the question about having paths in a mask, that's just fine and is supported by all svg-capable browsers AFAIK.