I'm using a big svg that contains flags of countries, eg
<symbol viewBox="0 0 640 480" id="flag-be">
<g fill-rule="evenodd" stroke-width="1pt">
<path d="M0 0h213.34v480H0z" />
<path fill="#ffd90c" d="M213.34 0h213.33v480H213.33z" />
<path fill="#f31830" d="M426.67 0h213.34v480H426.66z" />
</g>
</symbol>
It works great and I can simply svg use #flag-be and voila, got a my flag.
<svg class="icon flag-be"><use href="#flag-be"></use></svg>
However, I'd like to add a border around the flags (because some that have a lot of white looks strange without it), ideally something that can be set via css only
It works fine when I have each flag into separate svgs (using border), but I failed to make it work when I use several flags as part of a single svg containers (a graph)
What's the easiest? whould I add a a new element in each symbol for the border? What's the most flexible to style "used" symbols in a svg?
Neither <svg> nor <use> nor <g> elements are graphical elements. Trying to set a style altering the graphical appearance on them will only lead to the style being inherited by its children. So, if you set a stroke on <use>, it will be inherited by all the path elements, and you get a border around every flag field.
(A point to remember: Content cloned with a <use> element can inherit styles, but they cannot be targeted with CSS selectors.)
So why does setting a border work on the outermost <svg> element? Because that element is treated as part of the HTML namespace and rendered as if it was an ordinary <span>, while for its children in the SVG namespace the border property has no meaning.
In your use case, you need to add a graphical element surrounding the whole flag. Probably at the point of use, like this:
<svg ...>
...
<svg class="icon flag-be" width="24" height="16">
<use href="#flag-be" />
<rect width="100%" height="100%" style="fill:none;stroke:black;stroke-width:1" />
</svg>
...
</svg>
Note the inner <svg> element. Its purpose is to give a reference to the percentage width and height of the <rect>. Otherwise, they would be computed in relation to the outer <svg>.
Currently, width and height must be set as attributes on an inner <svg> element. SVG 2 defines them as presentation attributes that can be set with CSS, but some browsers still only allow that on outer <svg> elements.
Related
See reproduced example here - https://codepen.io/canovice/pen/eYRmYKR - command + P to print, I've taken this screenshot of the print/pdf output:
Problem: On web, both images are sharp. On print and save to PDF, the logo in the <img> tag remains sharp, whereas the logo in the <svg> using <svg:pattern>, <svg:image>, <svg:rect> with the fill attribute, is blurry.
Purpose: Our web app has many SVG graphs (think scatterplots) that use the team logos in place of the scatterplot dots. We want users to be able to print these graphs, and save these graphs to PDF, with sharp images. Here's a screenshot of the graph on web, with the sharp logos. When we save this as PDF, we get blurry logos.
We are using react.js and d3.js to build our web app and create our svg graphs, although we are hoping for a solution specific to the html & css of SVG elements.
Wrapping a raster graphic image inside a svg name does not make it a true scalable vector graphic. The method used is a "gradient fill with image" thus not as efficient as using true SVG objects with true colour gradient fills.
To get png in svg wrapping keep it simple
<div>
<svg width="2000" height="2000" >
<rect x="0" y="0" height="1000" width="1000" style="fill: #f0fff0"/>
<image x="30" y="00" width="160" height="160" xlink:href="103735.png" />
<image x="300" y="50" width="160" height="160" xlink:href="103735.png" />
</svg>
</div>
This is the example https://codesandbox.io/s/4xwv953mv0
There are three lines. The original one is hidden the second linked to it by id xlink:href="#line", the third links the second the same way.
Move the slider, the lines will go up in the Chrome, and only one will go up in the Firefox.
If it is a Firefox bug what to do? Is there a way to update SVG with Vue?
Yes. This is a known Firefox bug. Firefox bug report here and here.
There is a simple fix here though. Just change your second use so that it points to the <line> directly, rather than at the <use>.
<use
id="Svg"
xlink:href="#line"
transform="translate(40,10)"
></use>
As an aside. I recommend that you put your line in a <defs> section, rather than hiding it with display:none. This is what <defs> is for, and using display:none can have unintended consequences in some cases.
<defs>
<line
id="line"
x1="0"
y1="0"
x2="100"
:y2="value"
vector-effect="non-scaling-stroke"
/>
</defs>
I've enbedded d3's force directed graph layout into extjs tabs so that each time a new tab gets added a new graph svg gets generated.
No Problemo so far.
Now I intended to turn the graph into a directed one (by adding a marker and tell the lines to use it)
Each generated svg elements is following this pattern:
<svg width="100%" height="100%">
<defs><marker id="end-arrow" viewBox="0 -5 10 10" refX="6" markerWidth="3" markerHeight="3" orient="auto"><path d="M0,-5L10,0L0,5" fill="#ccc"></path></marker>
</defs>
<g transform="translate(4,0) scale(1)"><line class="link" sig="30.84" style="stroke-width: 3;" x1="538" y1="347" x2="409" y2="467" marker-end="url(#end-arrow)"></line>
...
</g>
</svg>
With Crome everything works just fine.
So I arrived at the concusion that the structur and
the way I generate the svgs should be more or less correct.
But with Firefox the Markers will only show for the first svg. (the first tab)
All other svgs won't show any Arrowheads.
"Inspect Elements" tells me the Markers are there and that the lines are refering to them.
And this is where I'm running out of Ideas where or what to look for. :(
You have multiple non-distinct IDs within the same html or svg document. This is invalid, different UAs respond differently but as you're not allowed to do this, it doesn't really matter that they are inconsistent.
No matter what I try, I can't get this SVG gradient to work properly in the most recent Safari (5.1.7) on Windows:
<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" viewBox="0 0 1920 200">
<linearGradient id="g186" gradientUnits="userSpaceOnUse" x1="0%" y1="0%" x2="0" y2="200">
<stop stop-color="#0A306A" offset="0"/><stop stop-color="#030C1B" offset="1"/>
</linearGradient>
<rect x="0" y="0" width="1920" height="200" fill="url(#g186)" />
</svg>`
JSFiddle:
http://jsfiddle.net/wumnb/1/ (Note that the browser may throw an XSS warning because of the base64-encoded SVG)
When I include -webkit-background-size: 100% 200px; with and/or without the -webkit-, it re-sizes the SVG, but it looks significantly lighter than every other browser; almost as if it was cropping a full-page version of the SVG from the top to 200px from the top.
I've tried both answers from the other two questions I could find, but neither is working.
It turns out that preserveAspectRatio="none" needs to be preserveAspectRatio="xMidYMax meet" with viewbox set to the wanted dimensions. Sadly, this doesn't allow for percentages, but it's better than nothing.
W3 documentation for preserveAspectRatio.
EDIT: Upon playing with this more, I've discovered that background position is really weird in Safari. The xM(in|id|ax)yM(in|id|ax) part of the preserveAspectRatio seem to determine where the SVG will go on the page, rather than do what's described on W3.
It appears (to me at least) that xMidYMax is the equivalent of background-position: center bottom; and xMinyMin is the equivalent of background-position: center top;
I have a PNG file with lots of icons on it. I want to use it in my SVG. I use the svg:image tag:
<image xlink:href="icons.png" height="50px" width="50px"></image>
This renders the whole image. How can I specify the portion of the file to be rendered? (I need an SVG-equivalent of CSS's background-position attribute)
Update
I suspect preserveAspectRatio attribute to be what I need, but can not figure out how to use it with <image>. See this example.
You can use preserveAspectRatio to achieve this affect in a limited way. But you are limited by the positioning options that preserveAspectRatio provides. So as long as your sprite has a maximum of 3x3 images or are positioned at the corners or sides, it would work.
The are a couple of other ways I can think of to achieve the same effect in a more flexible way.
Use the clip or clip-path style properties along with careful positioning of the image on the page
Embed the image inside another <svg> element and use viewBox to select the part of the sprite you want.
The following example demonstrates the three main techniques above.
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="8cm" height="8cm" viewBox="0 0 400 400" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<desc>Testing image elements</desc>
<!-- Outline the drawing area in blue -->
<rect fill="none" stroke="blue"
x="1" y="1" width="398" height="398"/>
<!-- Use preserveAspectRatio to show the top 64 pixels of the image (Stack Overflow logo) -->
<image x="100px" y="100px" width="238px" height="64px" xlink:href="http://cdn.sstatic.net/stackoverflow/img/sprites.png"
preserveAspectRatio="xMinYMin slice"/>
<!-- Use a CSS clip rectangle to show a small facebook logo from the sprite. Logo is at 150,1000 with dimensions 19x19.
Positioned at 100,200 in the SVG (-50+150, -800+1000). Could also use a clip-path for this. -->
<image x="-50px" y="-800px" width="238px" height="1073px" xlink:href="http://cdn.sstatic.net/stackoverflow/img/sprites.png"
clip="rect(200 100 219 119)" />
<!-- Use a svg viewBox to show the facebook logo from the sprite.
By setting our viewBox to the bounds of the logo, the renderer will scale it to fit the specified width and height.
Which in this case is 19x19 - the same size as the sprite. -->
<svg x="100px" y="300px" width="19px" height="19px" viewBox="150 1000 19 19" version="1.1">
<image x="0px" y="0px" width="238px" height="1073px" xlink:href="http://cdn.sstatic.net/stackoverflow/img/sprites.png" />
</svg>
</svg>