SVG Positioning - svg

I'm having a play with SVG and am having a few problems with positioning. I have a series of shapes which are contained in the g group tag. I was hoping to use it like a container, so I could set its x position and then all the elements in that group would also move. But that doesn't seem to be possible.
How do most people go about positioning a group of elements which you wish to move in tandem?
Is there any concept of relative positioning? e.g. relative to its parent

Everything in the g element is positioned relative to the current transform matrix.
To move the content, just put the transformation in the g element:
<g transform="translate(20,2.5) rotate(10)">
<rect x="0" y="0" width="60" height="10"/>
</g>
Links: Example from the SVG 1.1 spec

There is a shorter alternative to the previous answer. SVG Elements can also be grouped by nesting svg elements:
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<svg x="10">
<rect x="10" y="10" height="100" width="100" style="stroke:#ff0000;fill: #0000ff"/>
</svg>
<svg x="200">
<rect x="10" y="10" height="100" width="100" style="stroke:#009900;fill: #00cc00"/>
</svg>
</svg>
The two rectangles are identical (apart from the colors), but the parent svg elements have different x values.
See http://tutorials.jenkov.com/svg/svg-element.html.

As mentioned in the other comment, the transform attribute on the g element is what you want. Use transform="translate(x,y)" to move the g around and things within the g will move in relation to the g.

There are two ways to group multiple SVG shapes and position the group:
The first to use <g> with transform attribute as Aaron wrote. But you can't just use a x attribute on the <g> element.
The other way is to use nested <svg> element.
<svg id="parent">
<svg id="group1" x="10">
<!-- some shapes -->
</svg>
</svg>
In this way, the #group1 svg is nested in #parent, and the x=10 is relative to the parent svg. However, you can't use transform attribute on <svg> element, which is quite the contrary of <g> element.

I know this is old but neither an <svg> group tag nor a <g> fixed the issue I was facing. I needed to adjust the y position of a <g> tag which also had animation on it.
The solution was to use both the <svg> and <g> tag together:
<svg y="1190" x="235">
<g class="light-1">
<path />
</g>
</svg>

Related

Width and height have no effect on <use> when referencing inline images

I'm trying to inline some images into an SVG that uses xlink:href references pointed to fully qualified local paths. For reasons why see this GitHub issue. The example python does a reasonable job, but it will inline the same image many times in a single SVG which is not optimal.
So I tried a similar approach that converts something like this:
<svg xmlns="http://www.w3.org/2000/svg">
<image x="0" y="-144" width="101px" height="101px" xlink:href="/path/to/file.png" />
<image x="0" y="-144" width="101px" height="101px" xlink:href="/path/to/file.png" />
</svg>
To this
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<image id="file.png_1" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgA..." />
</defs>
<use x="0" y="+144" width="101px" height="101px" href="#file.png_1" />
<use x="0" y="-144" width="101px" height="101px" href="#file.png_1" />
</svg>
The problem
The way this renders (Safari and Chrome), it seems that width and height have no effect on the <use>.
I can get the desired result to render identically to the original if I move the width and height onto the <defs><image/></defs>. But doing this makes the assumption that no SVG will EVER use the same image twice with different sizes.
Despite reading the SVG 1.1 Standard, I'm still no further forward on understanding how to size a <use> element without explicitly sizing it on the referenced <image> element.
In a comment the OP is asking for an example:
#enxaneta could you show a very short worked example as an answer.
In the next example I'm putting an image in a symbol. The image has a width and a height. Also the symbol has a viewBox. In this case the viewBox of the symbol has the same size as the image.
I'm using the symbol with use.The use element has a x and y attributes for the upper left corner. Also the use has a width and a height. Please observe that I'm preserving the same aspect ratio as the symbol's viewBox.
<svg viewBox="0 0 65 50">
<symbol id="i" viewBox="0 0 22 9.8">
<image width="22" height="9.8" href="https://assets.codepen.io/222579/bone300.svg"/>
</symbol>
<use href="#i" x="10" y="7" width="44" height="19.6" />
</svg>
According to the SVG specification width and height are ignored on a use element unless that use element points to a symbol or an svg element.
The width and height properties on the ‘use’ element override the values for the corresponding properties on a referenced ‘svg’ or ‘symbol’ element when determining the used value for that property on the instance root element.
So wrapping the image in a symbol element and then pointing the use to the symbol should work.

Responsive SVG sprites

I am building an icon system for a site and moving away from png and font-icon sprites to SVG.
I need it to work across all major browsers (IE9+) and ideally want to use fragment identifiers or, as a second best alternative, inline. I've done extensive research, and there isn't a great deal out there, and from what I have read SVG sprites aren't particularly responsive.
For fragment identifiers, using img tag, I have to set the width/height to the same size as the viewbox. Increasing the dimensions on the img tag ends up revealing some of the next sprite. I'd like to be able to use percentage values so the sprite fragment fills the parent container.
I just want confirmation that this isn't possible, I can't find anything that suggests I am wrong to think this.
This is very much possible and is relatively easy to accomplish. SVG's are vector graphics and therefore, if done correctly, will be the most responsive graphics on your website.
Set your SVG file up as expected but put each sprite into a <g> tag with its own identifier.
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<g class="sprite" id="circle">
<ellipse cy="50" cx="50" ry="45" rx="45" stroke-width="5" stroke="#00ff00" fill="#00ff00" fill-opacity="0.75" />
</g>
<g class="sprite" id="square">
<rect y="5" x="5" width="90" height="90" stroke-width="5" stroke="#ff0000" fill="#ff0000" fill-opacity="0.75" />
</g>
<g class="sprite" id="triangle">
<path d="M20,7 L92,50 L6,93 z" stroke-width="5" stroke="#0000ff" fill="#0000ff" fill-opacity="0.75" />
</g>
</svg>
Add some CSS to say only the rargeted one needs to be displayed
<defs>
<style><![CDATA[
.sprite { display: none; }
.sprite:target { display: inline; }
]]></style>
</defs>
Then you can just call these out whenever required using an img tag or background element etc.
You can find the fully explained writeup here:
How to Use SVG Image Sprites

Can you combine multiple svgs with different viewBoxes and customize each in Polymer?

I have multiple svgs that I'd like to use in my application and was hoping to put them in a single custom-svg element to reference individually by id, however, the viewBoxes are different. One svg is defined as
<iron-iconset-svg name="club-icon" size="512">
<svg>
<defs>
<g id="club-icon">
<path d="bunch of numbers"></path>
</g>
</defs>
</svg>
</iron-iconset-svg>
The other svg is defined as
<iron-iconset-svg name="club-icon" size="300">
<svg>
<defs>
<g id="book-icon">
<path d="bunch of numbers"></path>
</g>
</defs>
</svg>
</iron-iconset-svg>
Is there a way for each custom icon to define its own viewBox, or must every svg defined within a single iconset share the same properties. For now I have multiple custom element html files, but each custom element is an http request (which I'm trying to minimize).
It can be done using symbols.
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="beaker" viewBox="214.7 0 182.6 792">
<!-- <path>s and whatever other shapes in here -->
</symbol>
<symbol id="shape-icon-2" viewBox="0 26 100 48">
<!-- <path>s and whatever other shapes in here -->
</symbol>
</svg>
See this article on CSS tricks for a further explanation.
https://css-tricks.com/svg-symbol-good-choice-icons/
you might try a transform scale on you g element?
<g id="book-icon" transform="scale(1.71)">
1.71 = 512/300
or if you are using gulp/grunt, you could resize the SVGs to be the same using svg-scaler or the like

Enforce relative links to defs in SVG

I'm trying to draw multiple SVGs on a single page and the ids in the defs section of each SVG are clashing. I'd like each one to refer only the mask in their own defs. Currently they all use the mask that has a matching id on the first svg on the page. No svg knows about the others so they would have to rely on a random number generator to pick ids that (hopefully) are different.
Is that possible or do they need unique ids if the SVGs are loaded into the same webpage. They are created on the fly by d3.
<svg>
<defs>
<mask id="temperatureMask">
<rect width="100%" height="100%" fill="#ffffff">
</mask>
</defs>
<rect mask="#temperaureMask">…etc
</svg>
<svg>
<defs>
<mask id="temperatureMask">
<rect width="100%" height="50%" fill="#dddddd">
</mask>
</defs>
<rect mask="#temperaureMask">…etc
</svg>
The ids on a page must be unique. That includes any inline SVGs. You will need to alter your d3 script like you suggest to add a unique number etc to the ids.

clipPath in multiple SVG tags

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.

Resources