One of the use elements is created dynamically, one is created statically. I have written a jsfiddle.
https://jsfiddle.net/rhedin/r0dbf6uy/6/
<!doctype html>
<body>
<svg
id="svg_box"
width="200px"
height="100px"
viewBox="0 0 200 100"
style="background-color:pink"
>
<defs>
<g id="b">
<path d="m 4.23,7.7400001 0,-7.14000002 C 4.23,0.18000008 3.96,7.6293944e-8 3.39,7.6293944e-8 l -2.22,0 C 0.39000002,7.6293944e-8 1.9073486e-8,0.36000008 1.9073486e-8,1.0500001 c 0,0.75 0.420000000926514,1.02 1.349999980926514,1.02 0.21,0 0.45,0.03 0.66,0.03 L 2.01,17.1 c -0.12,0 -0.21,0 -0.3,0 C 0.51000002,17.1 1.9073486e-8,17.28 1.9073486e-8,18.12 1.9073486e-8,18.81 0.39000002,19.17 1.17,19.17 l 2.67,0 c 0.45,0 0.6,-0.24 0.6,-0.75 l 0,-1.17 c 0.99,1.47 2.52,2.19 4.56,2.19 3.93,0 6.93,-3.09 6.93,-6.9 0,-3.8699999 -2.94,-6.8999999 -6.87,-6.8999999 -2.07,0 -3.72,0.72 -4.83,2.1 z M 8.79,17.13 c -2.73,0 -4.62,-1.98 -4.62,-4.68 0,-2.7299999 1.92,-4.6799999 4.62,-4.6799999 2.73,0 4.62,2.01 4.62,4.6799999 0,2.79 -1.89,4.68 -4.62,4.68 z" />
</g>
</defs>
<use x="130px" y="10px" xlink:href="#b" />
</svg>
<script>
var svgElt = document.getElementById('svg_box');
var newUse = document.createElementNS("http://www.w3.org/2000/svg", 'use');
newUse.setAttribute('x', '150px');
newUse.setAttribute('y', '10px');
newUse.setAttribute('xlink:href', '#b');
svgElt.appendChild(newUse);
</script>
</body>
Two both appear the same in Chrome's debugger. Why does only one show up?
Thanks, Rick
You can't set an xlink:href attribute using setAttribute, you need to use setAttributeNS
var svgElt = document.getElementById('svg_box');
var newUse = document.createElementNS("http://www.w3.org/2000/svg", 'use');
newUse.setAttribute('x', '150px');
newUse.setAttribute('y', '10px');
newUse.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#b');
svgElt.appendChild(newUse);
<!doctype html>
<body>
<svg
id="svg_box"
width="200px"
height="100px"
viewBox="0 0 200 100"
style="background-color:pink"
>
<defs>
<g id="b">
<path d="m 4.23,7.7400001 0,-7.14000002 C 4.23,0.18000008 3.96,7.6293944e-8 3.39,7.6293944e-8 l -2.22,0 C 0.39000002,7.6293944e-8 1.9073486e-8,0.36000008 1.9073486e-8,1.0500001 c 0,0.75 0.420000000926514,1.02 1.349999980926514,1.02 0.21,0 0.45,0.03 0.66,0.03 L 2.01,17.1 c -0.12,0 -0.21,0 -0.3,0 C 0.51000002,17.1 1.9073486e-8,17.28 1.9073486e-8,18.12 1.9073486e-8,18.81 0.39000002,19.17 1.17,19.17 l 2.67,0 c 0.45,0 0.6,-0.24 0.6,-0.75 l 0,-1.17 c 0.99,1.47 2.52,2.19 4.56,2.19 3.93,0 6.93,-3.09 6.93,-6.9 0,-3.8699999 -2.94,-6.8999999 -6.87,-6.8999999 -2.07,0 -3.72,0.72 -4.83,2.1 z M 8.79,17.13 c -2.73,0 -4.62,-1.98 -4.62,-4.68 0,-2.7299999 1.92,-4.6799999 4.62,-4.6799999 2.73,0 4.62,2.01 4.62,4.6799999 0,2.79 -1.89,4.68 -4.62,4.68 z" />
</g>
</defs>
<use x="130px" y="10px" xlink:href="#b" />
</svg>
</body>
I want to create an svg that will be easily scaled on whatever width I'll give it. In that svg I have a circle and path with relative paths so I want it to be easily scaleable.
But for some reason the position of x,y are not right.
You can see the image below, the circle has (x,y)=(0,0)
but it is set in the middle.
I assume "viewBox" is causing problems.
jsfiddle link:
https://jsfiddle.net/tzookb/69z2wepo/174297/
code:
const ExclamationIcon = props => (
<svg {...props} viewBox="0 0 140 140">
<circle fill="#f66868" cx="70" cy="70" r="70" />
<g transform="translate(58,30)">
<path fill="white" d="M 11,56.7 L 9,56.7 L 4.2,13.2 C 4,11.4 4,10 4,9 C 4,7 4.5,4.9 5.6,3.5 C 7,2.2 8.3,1.5 10,1.5 C 11.7,1.5 13,2.2 14.4,3.5 C 15.5,4.9 16,7 16,9 C 16,10 16,11.4 15.8,13.2 z M 10,64 A 6,6 0 1,1 10,76 A 6,6 0 1,1 10,64 z"/>
</g>
</svg>
);
class Hello extends React.Component {
render() {
return (
<div>
asdas
<svg className="main">
<rect x="20" y="20" width="100" height="40" fill="red" />
<ExclamationIcon width="30" x="0" y="0" />
</svg>
</div>
);
}
}
ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);
Looks like this issue goes away if the height is set on the inner svg. I'm guessing that if the height is not set it automatically takes up all the available height and centres itself. I wish I had a better explanation but this completely stumped me.
JS Fiddle
const ExclamationIcon = props => (
<svg {...props} viewBox="0 0 140 140">
<circle fill="#f66868" cx="70" cy="70" r="70" />
<g transform="translate(58,30)">
<path fill="white" d="M 11,56.7 L 9,56.7 L 4.2,13.2 C 4,11.4 4,10 4,9 C 4,7 4.5,4.9 5.6,3.5 C 7,2.2 8.3,1.5 10,1.5 C 11.7,1.5 13,2.2 14.4,3.5 C 15.5,4.9 16,7 16,9 C 16,10 16,11.4 15.8,13.2 z M 10,64 A 6,6 0 1,1 10,76 A 6,6 0 1,1 10,64 z"/>
</g>
</svg>
);
class Hello extends React.Component {
render() {
return (
<div>
asdas
<svg className="main">
<rect x="20" y="20" width="100" height="40" fill="red" />
<ExclamationIcon width="30" height="30" x="0" y="0" />
</svg>
</div>
);
}
}
ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);
I did some searching but I have to admit, I have 0 experience with SVG, I've seen a bunch of modern libraries, such as Raphael, PaperJS, KineticJS, EaselJS but I have no idea of what would fit the goal here, maybe even CSS keyframes would do the trick.
Pointers to this problem would be greatly appreciated.
Goal
On the browser, I want to animate svg1 into svg2, using transition type ease-out
Constraints
Any javascript library, if required at all
Should be able to every element to the other element of same ID
morph shapes, paths, fill*, stroke*, cx, cy, rc, ry
Should work on current Firefox and Chrome, IE 10 would be nice to have
Should work in new mobiles such as iphone 5, nexus 4 and 7
Decent performance, even on mobiles
Indifferent if it renders as <svg> or <canvas>
svg1:
<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg">
<!-- Created with SVG-edit - http://svg-edit.googlecode.com/ -->
<defs>
<linearGradient id="svg_6">
<stop stop-color="#828236" offset="0"/>
<stop stop-color="#7d7dc9" offset="0.99219"/>
</linearGradient>
<linearGradient id="svg_7" x1="0" y1="0" x2="1" y2="1">
<stop stop-color="#828236" offset="0"/>
<stop stop-color="#7d7dc9" offset="0.99219"/>
</linearGradient>
<linearGradient y2="1" x2="1" y1="0" x1="0" id="svg_1">
<stop offset="0" stop-color="#828236"/>
<stop offset="0.99219" stop-color="#7d7dc9"/>
</linearGradient>
</defs>
<g>
<title>Layer 1</title>
<ellipse ry="145" rx="116" id="svg_2" cy="201" cx="317" fill-opacity="0.36" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="5" stroke="#000000" fill="url(#svg_7)"/>
<ellipse ry="21" rx="10" id="svg_5" cy="137" cx="274" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="5" stroke="#000000" fill="#0cd60c"/>
<ellipse ry="31" rx="17" id="svg_9" cy="114" cx="346" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="5" stroke="#000000" fill="#0cd60c"/>
<path id="svg_14" d="m235,239c55.66666,-1.33333 133.33334,-71.66667 167,-4l-167,4z" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="5" stroke="#000000" fill="none"/>
</g>
</svg>
svg2:
<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg">
<!-- Created with SVG-edit - http://svg-edit.googlecode.com/ -->
<defs>
<linearGradient id="svg_6">
<stop offset="0" stop-color="#828236"/>
<stop offset="0.99219" stop-color="#7d7dc9"/>
</linearGradient>
<linearGradient y2="1" x2="1" y1="0" x1="0" id="svg_7">
<stop offset="0" stop-color="#828236"/>
<stop offset="0.99219" stop-color="#7d7dc9"/>
</linearGradient>
<linearGradient id="svg_1" x1="0" y1="0" x2="1" y2="1">
<stop stop-color="#828236" offset="0"/>
<stop stop-color="#7d7dc9" offset="0.99219"/>
</linearGradient>
</defs>
<g>
<title>Layer 1</title>
<ellipse id="svg_2" fill="url(#svg_7)" stroke="#000000" stroke-width="5" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="null" fill-opacity="0.36" cx="317" cy="201" rx="116" ry="145"/>
<ellipse id="svg_5" stroke="#000000" fill="#0cd60c" stroke-width="5" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="null" cx="277.5" cy="132.5" rx="13.5" ry="25.5"/>
<ellipse id="svg_9" stroke="#000000" fill="#0cd60c" stroke-width="5" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="null" cx="349.5" cy="110" rx="20.5" ry="35"/>
<path id="svg_14" fill="none" stroke="#000000" stroke-width="5" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="null" d="m235,240c21.66666,81.66669 114.33334,96.33331 167,-4l-167,4z" />
</g>
</svg>
ps you can visualize here, by simply pasting the codes in the area.
I have no code to show, I didn't want to start off wrong. My intuition tells me there is a 50% chance that the best solution don't involve navigating those nodes one by one diffing then!
Have to mention that 2015 have brought us several pretty nice libraries for svg morph:
https://alexk111.github.io/SVG-Morpheus/
http://greensock.com/morphSVG (probably the best of the best, but you
have to buy their license)
https://github.com/gorangajic/react-svg-morph (for react)
As far as I can see you only want to morph paths
This is a nice tutorial: SVG Essentials/Animating and Scripting SVG
W3C spec for SVG Paths: w3.org/TR/SVG/paths
W3C spec for animation: w3.org/TR/SVG/animate
Here's an example: carto.net/svg/samples/path_morphing
paraphrasing:
Currently you have to use the same number of vertices in both path-elements, and they have to be of the same type and appear in the same order in the other path-description. You should also orient both polygons in the same direction (left-right and right-left would produce unwanted results).
So you can do it (see the link below for an example) but you need to plan it out so that you create shape A's path and shape B's path in the exact same way with identical curve types, points, etc.
I created one shape in illustrator
i duplicated that shape.
I modified the duplicate into a new shape, careful not to add vertices or change from bezier to linear curve type etc
fyi to confirm point count you can select the path, then go path>simplify and it will show you current points on that path...
I save that svg file, then copy/paste those paths into another svg with the animation information.
NOTE: the paths are placed within an element in the svg file that corresponds to the layer name that it's on in illustrator. If you keep both shapes on different layers in illustrator and name them clearly it will help keep your svg files organized.
NOTE #2: If you create your shape and it's very simple, ie only straight lines, it will likely get saved as a _polygon instead of a _path which I personally found difficult to animate, so I recommend adding a bezier handle to at least a single point(and the identical corresponding point in the second shape).
Indeed, there are quite a few libraries that allow svg morphing, as Darwin mentioned.
Some extras I've found were: snap.svg, KUTE.js, GSAP. Svg.js has a plugin for svg morph and I don't believe velocity.js has support for this yet.
If you can define the morphing as a list of changes instead of second SVG, you could use d3 http://d3js.org/ framework
It has a bit steep learning curve, but it gives you a lot of power. If you want something easier I suggest Raphael http://raphaeljs.com/ - capabilities are similiar, but it's easier to start.
Looking at a pure SVG option (ie. no Javascript) and building on the previous answers, here's a working example that might reduce the hairpulling for others.
<svg height="120px" width="120px" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
<path>
<animate
dur="10s"
repeatCount="indefinite"
attributeName="d"
calcMode="spline"
keySplines="0.4 0 0.2 1; 0.4 0 0.2 1"
fill="freeze"
values="
M 336,0
c -97.2,0 -176,78.8 -176,176
c 0,18.7 2.9,36.8 8.3,53.7
c 0,0 0,0 -161.3,161.3
c -4.5,4.5 -7,10.6 -7,17
c 0,0 0,0 0,80
c 0,13.3 10.7,24 24,24
c 0,0 0,0 80,0
c 13.3,0 24,-10.7 24,-24
c 0,0 0,0 0,-40
c 0,0 0,0 40,0
c 13.3,0 24,-10.7 24,-24
c 0,0 0,0 0,-40
c 0,0 0,0 40,0
c 6.4,0 12.5,-2.5 17,-7
c 0,0 0,0 33.3,-33.3
c 16.9,5.4 35,8.3 53.7,8.3
c 97.2,0 176,-78.8 176,-176
C 512,78.8 433.2,0 336,0
Z
M 376,176.5
c -22.4,0 -40.5,-18.1 -40.5,-40.5
c 0,-10.5 4,-20 10.5,-27.2
c 7.4,-8.2 18.1,-13.3 30,-13.3
c 22.4,0 40.5,18.1 40.5,40.5
c 0,22.4 -18.1,40.5 -40.5,40.5
Z;
M 256,0
c -45,0 -85.8,15.8 -115.6,41.5
c -30.2,26.1 -49,62.4 -49,102.5
c 0,0 0,0 0,48
c 0,0 0,0 -18.3,0
c -35.3,0 -73.1,35.3 -73.1,64
c 0,0 0,0 0,192
c 0,35.3 32.8,64 73.1,64
c 0,0 0,0 78.9,0
c 0,0 0,0 104,0
c 0,0 0,0 107,0
c 0,0 0,0 75.9,0
c 40.3,0 73.1,-28.7 73.1,-64
c 0,0 0,0 0,-192
c 0,-35.3 -32.8,-64 -73.1,-64
c 0,0 0,0 -18.3,0
c 0,0 0,0 0,-48
c 0,-39.2 -17.9,-74.7 -47,-100.7
C 343.7,16.6 302.1,0 256,0
Z
M 164.6,192
c 0,0 0,0 0,-48
c 0,-44.2 40.9,-80 91.4,-80
c 50.5,0 91.4,35.8 91.4,80
c 0,0 0,0 0,48
c 0,0 0,0 24,0
Z;
M 336,0
c -97.2,0 -176,78.8 -176,176
c 0,18.7 2.9,36.8 8.3,53.7
c 0,0 0,0 -161.3,161.3
c -4.5,4.5 -7,10.6 -7,17
c 0,0 0,0 0,80
c 0,13.3 10.7,24 24,24
c 0,0 0,0 80,0
c 13.3,0 24,-10.7 24,-24
c 0,0 0,0 0,-40
c 0,0 0,0 40,0
c 13.3,0 24,-10.7 24,-24
c 0,0 0,0 0,-40
c 0,0 0,0 40,0
c 6.4,0 12.5,-2.5 17,-7
c 0,0 0,0 33.3,-33.3
c 16.9,5.4 35,8.3 53.7,8.3
c 97.2,0 176,-78.8 176,-176
C 512,78.8 433.2,0 336,0
Z
M 376,176.5
c -22.4,0 -40.5,-18.1 -40.5,-40.5
c 0,-10.5 4,-20 10.5,-27.2
c 7.4,-8.2 18.1,-13.3 30,-13.3
c 22.4,0 40.5,18.1 40.5,40.5
c 0,22.4 -18.1,40.5 -40.5,40.5
Z;
"/>
</path>
</svg>