Scope of inline-svg elements' id='x' and <use xlink:href='#x' /> - html

When having multiple inline svg in my document I have noticed that using <use xlink:href="#id"/> will reference the first defined element with id="id", even when defined in another inline svg.
Somehow I was assuming the id/xlink:href scope was just the svg but it seems it is the whole document - which actually makes sense when thinking about it.
Example (red square in second svg should be green):
svg {
border: 1px solid gray;
}
<html><head></head><body>
<svg width="50" height="50" viewBox="0 0 50 50">
<defs>
<rect id="foo" width="25" height="25" fill="red" />
</defs>
<use xlink:href="#foo" />
</svg>
<svg width="50" height="50" viewBox="0 0 50 50">
<defs>
<rect id="foo" width="25" height="25" fill="green" />
<rect id="bar" width="25" height="25" fill="blue" />
</defs>
<use xlink:href="#bar" x=25 />
<use xlink:href="#foo" /> <!-- Not green but red! -->
</svg>
</body></html>
Is there a way to have <use/> elements only reference elements from the same <svg> somehow? Or would I have to create valid, document wide unique IDs?

Related

Alignment of nested SVG's

I want to achieve a layout of several SVG's as illustrated below.
The gray box is the top-level SVG containing the other elements. The width and height is known.
The orange boxes contain the red boxes and need to retain the same distance from each other. Similar to how justify-content: space-around aligns items.
The red boxes also retain their distance in the same way (but vertically).
I've been trying to adjust the positioning with transform-origin but it does not seem to work. Instead the offset is always calculated from the top-left of each element, which pushes the elements out of view. This is a very basic snippet, but it's all I have sadly.
<svg width="400" height="400" style="background:#ccc;">
<g transform="translate(10, 10)">
<svg width="50" height="50">
<rect width="50" height="50" fill="red" />
</svg>
<svg width="50" height="50">
<rect width="50" height="50" fill="red" />
</svg>
<svg width="50" height="50">
<rect width="50" height="50" fill="red" />
</svg>
</g>
<g transform="translate(200, 10)">
<svg width="50" height="50">
<rect width="50" height="50" fill="red" />
</svg>
<svg width="50" height="50">
<rect width="50" height="50" fill="red" />
</svg>
<svg width="50" height="50">
<rect width="50" height="50" fill="red" />
</svg>
</g>
<g transform="translate(360, 10)">
<svg width="50" height="50">
<rect width="50" height="50" fill="red" />
</svg>
<svg width="50" height="50">
<rect width="50" height="50" fill="red" />
</svg>
<svg width="50" height="50">
<rect width="50" height="50" fill="red" />
</svg>
</g>
</svg>
Is there a way to align these containers this way without knowing the size of the red boxes?
Every solution I end up with uses some calculation where I would need to subtract half the width and height of the red boxes.
As pointed out in a comment #enxaneta :
Instead of using all those nested svg elements you can put a rect in
the defs. the rect would be centered around the point 0,0
In SVG, element positions are relative to the top left corner of the canvas.
If you specify the same x=40 coordinates for several rectangles, then they will be vertically aligned.
In order not to write for each rectangle the values of its coordinates, as well as the values of width and height, you need to place one instance in the <defs> section and then clone it using the <use> tag.
In this case, you need to specify the coordinates x,y for each copy:
<use xlink:href="#rect" x="40" y="62.5" />
To get three columns you need to wrap one column in a <g> group tag and clone it with <use>
<use xlink:href="#column" x="150" y="0" />
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="450" height="400" viewBox="0 0 450 400" style="background:#ccc;">
<defs>
<rect id="rect" width="50" height="50" fill="red" x="0" y="0" />
</defs>
<g id="column" >
<rect x="30" y="0" width="70" height="400" fill="#C89F33" />
<use xlink:href="#rect" x="40" y="62.5" />
<use xlink:href="#rect" x="40" y="175" />
<use xlink:href="#rect" x="40" y="287.5" />
</g>
<use xlink:href="#column" x="150" y="0" />
<use xlink:href="#column" x="300" y="0" />
</svg>

Change image color in svg element

The goal is to show image but with another color inside svg.
I tried -webkit-mask-image with background-color, but this combination does not work in svg. Here is the example:
<div class="dashboard-buttons">
<svg width="367" height="243.5" viewBox="252.5 60.5 367 243.5">
<g>
<rect width="46" height="46" rx="4" ry="4" transform="translate(-23, -23)" style="fill:white" x="560" y="224"></rect>
<a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#element3" href="#element3" onclick="window.location.href = '#element3';">
<image height="32" width="32" transform="translate(-16, -16)" x="560" y="224" style="background-color: Red; -webkit-mask-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuM4zml1AAAACqSURBVFhH7ZYhDsJAFESHBMkBOCYGyQV6BQ6BQ0EwWByiuwj0Fk5AgO00+XJpCd20gpnkqfZnXrJmoCiVx+rmcWyD/2zCGXM7yZvK4c2S2InDiRIzO8uXZNkHgsM2HjC10zxJFXWwjsDEzvsnUfANVz7JpS93j+JXgSyEEs9RBRokIAEJSEACEpDA+AIcpa/UhyHg2n6A02jJabSjyH5Qms4SC1uGyt8GqAEZtGBDEZcerAAAAABJRU5ErkJggg==');width: 32px; height: 32px;"></image>
</a>
<a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#element3"><text filter="url(#fillbackground)" x="560" y="257">out</text></a>
</g>
</svg>
</div>
If you remove svg tags from it then this sample works and the color changed.
Do you know how to change image color inside svg correctly?
EDIT:
The following code works in Chrome, but not in Firefox:
<div class="wrapper">
<svg width="200" height="300" class="svg">
<defs>
<mask id="mask">
<image xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuM4zml1AAAACqSURBVFhH7ZYhDsJAFESHBMkBOCYGyQV6BQ6BQ0EwWByiuwj0Fk5AgO00+XJpCd20gpnkqfZnXrJmoCiVx+rmcWyD/2zCGXM7yZvK4c2S2InDiRIzO8uXZNkHgsM2HjC10zxJFXWwjsDEzvsnUfANVz7JpS93j+JXgSyEEs9RBRokIAEJSEACEpDA+AIcpa/UhyHg2n6A02jJabSjyH5Qms4SC1uGyt8GqAEZtGBDEZcerAAAAABJRU5ErkJggg==">
</image>
</mask>
</defs>
<rect width="50" height="50" style="fill:blue;" x="0" y="0"
mask="url(#mask)"></rect>
</svg>
</div>
Can't see your example, but:
<rect x="10" y="10" width="100" height="100" stroke="blue" fill="purple"
fill-opacity="0.5" stroke-opacity="0.8"/>
Use the fill option!
EDIT:
Now I can see your code.
If you insert an image as PNG:
data:image/png
Then I doubt you can change the color with HTML directive. PNG are bitmaps and not SVG, you would have to edit the PNG itself to achieve that.

SVG <image /> inside <rect /> not displayed [duplicate]

Is it possible to set a background-image for an SVG <path> element?
For instance, if I set the element class="wall", the CSS style .wall {fill: red;} works, but .wall{background-image: url(wall.jpg)} does not, neither .wall {background-color: red;}.
You can do it by making the background into a pattern:
<defs>
<pattern id="img1" patternUnits="userSpaceOnUse" width="100" height="100">
<image href="wall.jpg" x="0" y="0" width="100" height="100" />
</pattern>
</defs>
Adjust the width and height according to your image, then reference it from the path like this:
<path d="M5,50
l0,100 l100,0 l0,-100 l-100,0
M215,100
a50,50 0 1 1 -100,0 50,50 0 1 1 100,0
M265,50
l50,100 l-100,0 l50,-100
z"
fill="url(#img1)" />
Working example

Multiple perspectives into a single SVG

Is it possible to have a multiple different views into single SVG, or even just simulate that sort of effect with some clever use of groups? I wish to show different parts of a potentially very large SVG, but I'd rather avoid rendering it multiple times. Is there some sort of simple way of doing this?
for standalone SVGs there is the <view/> element which you can use to show only portions of your graphics. try this in a standalone file.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100" width="100" height="100">
<view id="circleView" viewBox="0 0 100 100"/>
<view id="rectView" viewBox="100 0 100 100"/>
<a xlink:href="#rectView">
<circle cx="50" cy="50" r="45" fill="blue"/>
</a>
<a xlink:href="#rectView">
<rect x="105" y="5" width="90" height="90" fill="royalblue" stroke="#53c"></rect>
</a>
</svg>
just click on the cirlce to see the rect and on the rect to see the circle.
this also works if you reference your svg via <img>
<img src="your.svg#circleView"/>
<img src="your.svg#rectView"/>
i found this to be not working for inlined SVG. Here you can use a similar aproach. You can just change the viewBox of your SVG. In contrast to the above, viewBoxes can even be animated!
<svg viewBox="0 0 460 360" width="200" height="200">
<polygon id="triangle" points="100,10,450,350,10,350" fill="#52c" />
<circle id="circle" cx="50" cy="50" r="45" fill="#c52" />
<rect id="rect" x="255" y="155" width="200" height="200" fill="#5c2" />
<animate attributeName="viewBox" to="250 150 210 210" dur="0.5s" begin="circle.click" fill="freeze" />
<animate attributeName="viewBox" to="0 0 100 100" dur="0.5s" begin="triangle.click" fill="freeze" />
<animate attributeName="viewBox" to="0 0 460 360" dur="0.5s" begin="rect.click" fill="freeze" />
</svg>
<br/>click on any of he shapes!
of course you can also just set the viewBox by script...
if you want to reference different parts of your SVG, you might use the <use> - Element as suggested in the other answers.
It's pretty simple to do. You just use the <use> element as Robert suggests. Here is a working example.
svg {
border: solid 1px black;
}
svg#original {
width: 450px;
}
<svg viewBox="0 0 450 300" id="original">
<circle cx="225" cy="150" r="150" fill="orange"/>
<circle cx="175" cy="110" r="25" fill="black"/>
<circle cx="275" cy="110" r="25" fill="black"/>
<circle cx="225" cy="70" r="150" fill="none" stroke="black" stroke-width="20" stroke-dasharray="0 145 180 1000"/>
</svg>
<br/>
<!-- part of the original at the same scale -->
<svg width="150" height="150">
<use xlink:href="#original" x="-50" y="0" width="450" height="300"/>
</svg>
<!-- part of the original at 0.5x scale -->
<svg width="150" height="150">
<use xlink:href="#original" x="0" y="0" width="450" height="300" transform="scale(0.5)"/>
</svg>
<!-- part of the original at 3x scale (and using a different method to achieve the scaling) -->
<svg width="150" height="150">
<use xlink:href="#original" x="-450" y="-255" width="1350" height="900"/>
</svg>

SVG align rect to bottom-right of parent element

i'm trying to draw a rect in SVG (300x300 px) and align 4 smaller rects in each corner of the parent Rect (10x10 px), but every small child rect has the full size of the parent rect.
<svg width="300" height="300">
<svg height="10" width="10" />
<svg height="10" width="10" />
<svg height="10" width="10" />
<svg height="10" width="10" />
</svg>
You can view my results here: http://jsfiddle.net/8tY3b/
If I set the width or height of the inner SVG Elements to 10px it works with every edge except the bottom right one.
Is there a way to align a child element to the bottom right of his parent element?
Do you want to embed svg elements or draw rectangles? In case you're satisfied with the latter, here you go:
<?xml version="1.0" encoding="utf-8"?>
<!-- SO: http://stackoverflow.com/questions/15495978/svg-circled-text-on-textpath-center-align -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
width="15cm" height="15cm"
viewBox="0 0 300 300"
preserveAspectRatio="none"
style="background-color:white; border: solid 1px black;"
>
<rect fill="green" stroke="blue" stroke-width="2" height="10" width="10" x="0" y="0"/>
<rect fill="green" stroke="blue" stroke-width="2" height="10" width="10" x="290" y="0"/>
<rect fill="green" stroke="blue" stroke-width="2" height="10" width="10" x="0" y="290"/>
<rect fill="green" stroke="blue" stroke-width="2" height="10" width="10" x="290" y="290"/>
</svg>
The value none for the attribute preserveAspectRatio allows for arbitrary scaling.