Animate SVG element after changing it on the fly - javascript
Internet Explorer does not support beginElement for SVG animations, so I am looking for a workaround. My aim is to string together a series of animations, under user control. Below is a demo that shows two animations to simulate stages in blowing up a balloon. If you click on the smaller balloon after its first animation
In Chrome, Firefox and Opera: it jumps to the final stage of the second animation ()
In Safari: it shows the start of the animation but never animates
In Internet Explorer: I don't get any animation at all
Is there a cross-platform technique I can use to create a sequence of animations, where the user must intervene between each animation?
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500px" height="500px" viewBox="0 0 250 250">
<defs>
<path id="one"
d="M 0 95 l 30 0 A 20 15 30 1 1 30 105 l -30 0 z"
fill="blue">
<animate
attributeName="d"
attributeType="XML"
from="M 0 95 l 30 0 A 20 15 30 1 1 30 105 l -30 0 z"
to="M 0 95 l 30 0 A 25 20 0 1 1 30 105 l -30 0 z"
dur="1s"
fill="freeze" />
</path>
<path id="two"
d="M 0 95 l 30 0 A 25 20 0 1 1 30 105 l -30 0 z"
fill="blue">
<animate
attributeName="d"
attributeType="XML"
from="M 0 95 l 30 0 A 25 20 0 1 1 30 105 l -30 0 z"
to="M 0 95 l 30 0 A 50 40 0 1 1 30 105 l -30 0 z"
dur="1s"
fill="freeze" />
</path>
</defs>
<use id="a" xlink:href="#one"/>
<use xlink:href="#two" transform="rotate(180 125 125)"/>
</svg>
<script>
var xlinkNS = "http://www.w3.org/1999/xlink"
var use = document.querySelector("#a")
use.onmouseup = inflate
function inflate() {
use.setAttributeNS(xlinkNS, "xlink:href", "#two")
}
</script>
jsFiddle
Intenet Explorer doesn't support SMIL animation at all.
The usual recommended workaround for IE is to use the Fakesmile library which adds SMIL support to IE. It supports beginElement().
I would strongly recommend Snap.svg
Edit: SVG is powerful and complex. Snap.svg gives you a ton of control over your svg animations whether they're created dynamically or with a tool like Adobe Illustrator or Sketch. It's a cross-browser solution written by the same person that wrote Raphael (another svg animation library)
It makes things really easy and is quite awesome to use. So instead of fiddling around with what you've got I would strongly recommend getting your hands on Snap.svg. At least follow the link and check it out. Very cool!
Related
SVG make a clip-path to scale and relocate as its container scales
I have this svg: <svg viewBox="0 0 280 280" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <clipPath id="clipPath"> <path d="M 10 10 q 49 41 100 0 c -14 46 -14 40 50 50 c -24 -1 -50 -6 -40 40 c -14 -44 -53 -73 -99 -51 Z"/> </clipPath> </defs> <rect x="5" y="5" width="190" height="90" fill="#770000" clip-path="url(#clipPath)"/> </svg> I can't use CSS styles here, just SVG. And I need to scale and relocate the clipPath as the rect scales or moves. I tried adding this to the clipPath definition <clipPath id="clipPath" width="190" height="90" x="5" y="5"> with no result. Tried adding these parameters to the path too. No result both times. Also tried reducing the dimensions of the rect the clipPath will truncate instead of readjusting, same thing if I change the X,Y position. Any hint on how to solve this?
Drawing a box with two sides as an Arc in javascript/svg
I am trying to make a shape like this and i managed to get this sofar But i cant get the right arc to go outwards instead of inwards. I cant find any help online how to do this. I tried rotation and playing around with the rx,ry but no luck. Here is the JSFiddle to it JsFiddle <svg height="200" width="300"> <g stroke="none" fill="blue"> <path d=" M 150 0 a 1 1 0 0 0 0 100 l -100 0 a 1 1 0 0 0 0 -100 l 100 0 Z "/> </g> </svg>
On the first arc, you simply need to flip the sweep-flag to "clockwise": https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d#elliptical_arc_curve <svg height="200" width="300"> <g stroke="none" fill="blue"> <path d=" M 150 0 a 1 1 0 0 1 0 100 l -100 0 a 1 1 0 0 0 0 -100 l 100 0 Z "/> </g> </svg>
Drawing a partial circle using SVG arcs
I want to draw a partial arc using SVG. According to the docs, the centre of the circle is calculated automatically. But my arc overflows the circle. It is easier to demonstrate it with a picture: <svg width="500px" height="500px" viewBox="0 0 100 100" style="border: navy solid 1px;"> <g transform="translate(10 10) scale(0.5 0.5)"> <path d="M0 50 A1 1 0 0 1 100 50 Z" fill="blue"></path> <path d="M0 50 A1 1 0 0 1 50 0 Z" fill="purple" opacity="0.7"></path> </g> </svg> Here is the link to the codepen link.
You can draw arcs before blue circle (as I draw red one) or make redrawing of circle segment (the last line - I made it green to emphasize but must be blue). So combination of circle arc + segment gives moon crescent form <path d="M50 50 L50 0 A1 1 0 0 1 100 50 Z" fill="red" opacity="0.7"></path> <path d="M0 50 A1 1 0 0 1 100 50 Z" fill="blue"></path> <path d="M0 50 A1 1 0 0 1 50 0 Z" fill="purple" opacity="0.7"></path> <path d="M50 0 A50 50 0 0 0 0 50 Z" fill="green"></path>
SVG stroke-dashoffset not working
I've been having some issue getting the path of my SVG to animate using stroke-dasharray in conjunction with stroke-dashoffset. The path length was calculated with Js. Below I have included a JsFiddle showing exactly what I am trying to accomplish. I have searched and searched, and a lot of the examples I came across did not work for me. At this point I am concluding that I am missing something, but I am at my wits end trying to figure out what that is. <div> <svg x="0px" y="0px" width="312px" height="312px" viewBox="0 0 512 512"> <g> <path class="pathOne" d="M320,128c52.562,0,95.375,42.438,96,94.813c-0.25,1.938-0.438,3.875-0.5,5.875l-0.812,23.5l22.25,7.75 C462.688,268.906,480,293.062,480,320c0,35.312-28.688,64-64,64H96c-35.281,0-64-28.688-64-64c0-34.938,28.188-63.438,63-64 c1.5,0.219,3.063,0.406,4.625,0.5l24.313,1.594l8-22.969C140.938,209.313,165.063,192,192,192c3.125,0,6.563,0.375,11.188,1.188 l22.406,4.031l11.156-19.844C253.875,146.938,285.75,128,320,128 M320,96c-47.938,0-89.219,26.688-111.156,65.688 C203.375,160.719,197.781,160,192,160c-41.938,0-77.219,27.063-90.281,64.563C99.813,224.438,97.969,224,96,224c-53,0-96,43-96,96 s43,96,96,96h320c53,0,96-43,96-96c0-41.938-27.062-77.25-64.562-90.313C447.5,227.75,448,225.938,448,224 C448,153.313,390.688,96,320,96L320,96z" fill="#333333"/> </g> </svg> </div> svg { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); } path.pathOne { stroke-dasharray: 2566; stroke-dataoffset: 2566; animation: cloud 5s linear alternate infinite; } #keyframes cloud { from { stroke-dashoffset: 2566; } to { stroke-dashoffset: 0; } } https://jsfiddle.net/maisonm/9c3baxh5/
Your grafic does not show the stroke of a path, but a filled path without a stroke. Here is a illustration of your path data as you could see them in the svg editor Inkscape: That is the path you could animate. Was that what you wanted? In that case, define a stroke and remove the fill: path.pathOne { fill: none; stroke: black; stroke-width: 3; stroke-dasharray: 2566; stroke-dataoffset: 2566; animation: cloud 5s linear alternate infinite; } #keyframes cloud { from { stroke-dashoffset: 2566; } to { stroke-dashoffset: 0; } } <svg x="0px" y="0px" width="250px" height="250px" viewBox="0 0 512 512"> <g> <path class="pathOne" d="M320,128c52.562,0,95.375,42.438,96,94.813c-0.25,1.938-0.438,3.875-0.5,5.875l-0.812,23.5l22.25,7.75 C462.688,268.906,480,293.062,480,320c0,35.312-28.688,64-64,64H96c-35.281,0-64-28.688-64-64c0-34.938,28.188-63.438,63-64 c1.5,0.219,3.063,0.406,4.625,0.5l24.313,1.594l8-22.969C140.938,209.313,165.063,192,192,192c3.125,0,6.563,0.375,11.188,1.188 l22.406,4.031l11.156-19.844C253.875,146.938,285.75,128,320,128 M320,96c-47.938,0-89.219,26.688-111.156,65.688 C203.375,160.719,197.781,160,192,160c-41.938,0-77.219,27.063-90.281,64.563C99.813,224.438,97.969,224,96,224c-53,0-96,43-96,96 s43,96,96,96h320c53,0,96-43,96-96c0-41.938-27.062-77.25-64.562-90.313C447.5,227.75,448,225.938,448,224 C448,153.313,390.688,96,320,96L320,96z" fill="#333333"/> </g> </svg> Note that both subpaths are dashed on their own, resulting in the impression that there are two animations. But that is not what is happening, it's simply that the dash and the offset are applied to each subpath separately. Since the path length is computed for the total of both subpaths, you see a time lag before the animation repeats. But maybe what you were aiming for was this?
Handwriting solution When an SVG shape has a double path with different distances between the paths and the shape at the points of change of direction, then it is better to use the technique - Handwriting to animate drawing the paths. Its essence is to animate the middle line, which is wide enough to cover the widest parts of the original shape. This middle line must be drawn in a vector editor and saved as path Next, animate this path by drawing a line from maximum to zero . Add this element to the mask and apply a mask to the original shape of the cloud outline. <animate attributeName="stroke-dasharray" begin="svg1.click" dur="4s" values="1281,0;0,1281" fill="freeze" /> where 1281 maximum centerline length The length of the animated mask changes to reveal the original outline of the cloud. At the same time, creating the illusion of drawing lines with different widths and shapes. <svg id="svg1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="312" height="312" viewBox="0 0 512 512" > <defs> <mask id="msk"> <rect width="100%" height="100%" fill="white" /> <!-- middle line --> <path stroke="#111" stroke-dashoffset="700" stroke-width="45" fill="none" d="m262.3 400c56 0.2 111.3 0 168 0 14.8 0 28.2-10.8 39.1-20.7 9-8.2 15.8-19.2 19.9-30.7 5.2-14.5 9.1-31 5.4-46-4.8-19.1-18.9-35.5-33.7-48.3-7.8-6.7-24.3-4.1-27.6-13.8-5.7-16.5-1.3-35.8-7.7-52.2-7.1-18.4-17.9-36.4-33-49.1-18.4-15.4-42-27.5-66-29.1-24.1-1.7-49.5 6.8-69.8 19.9-16.9 10.9-21.1 35.5-39.1 46-12.4 6.2-27.9-0.8-41.4 2.3-13 3-26.9 6.5-36.8 15.3-13.2 11.7-14.3 25-26.1 46-3.1 5.6-12.9 0.2-19.2 1.5-15.4 3.2-31.9 5.9-44.5 15.3-15.3 11.5-27.7 28.5-33 46.8-4 14-4.3 30.7 2.3 43.7 12.1 24 35.3 50.8 62.1 51.4 65.1 1.5 120.7 1.3 181 1.5z"> <!-- A mask animation with a wide line that reveals the outlines of the cloud --> <animate id="an" attributeName="stroke-dasharray" begin="svg1.click" dur="8s" values="1281,0;0,1281" fill="freeze" repeatCount="1" /> </path> </mask> </defs> <!-- Cloud contours --> <path mask="url(#msk)" fill="dodgerblue" class="pathOne" d="m320 128c52.6 0 95.4 42.4 96 94.8-0.2 1.9-0.4 3.9-0.5 5.9l-0.8 23.5 22.3 7.8C462.7 268.9 480 293.1 480 320c0 35.3-28.7 64-64 64H96c-35.3 0-64-28.7-64-64 0-34.9 28.2-63.4 63-64 1.5 0.2 3.1 0.4 4.6 0.5l24.3 1.6 8-23C140.9 209.3 165.1 192 192 192c3.1 0 6.6 0.4 11.2 1.2l22.4 4 11.2-19.8C253.9 146.9 285.8 128 320 128m0-32C272.1 96 230.8 122.7 208.8 161.7 203.4 160.7 197.8 160 192 160 150.1 160 114.8 187.1 101.7 224.6 99.8 224.4 98 224 96 224 43 224 0 267 0 320c0 53 43 96 96 96h320c53 0 96-43 96-96 0-41.9-27.1-77.2-64.6-90.3C447.5 227.8 448 225.9 448 224 448 153.3 390.7 96 320 96Z"/> <text x="200" y="300" font-size="36px" fill="dodgerblue" > Click me <animate id="op" attributeName="opacity" begin="an.end" dur="1s" values="1;0" fill="freeze" repeatCount="1" /> </text> </svg> Option with repeated animation after a 2s pause To do this, add a restart condition after a pause of 2s: begin="svg1.click;an.end+2s" <svg id="svg1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="312" height="312" viewBox="0 0 512 512" > <defs> <mask id="msk"> <rect width="100%" height="100%" fill="white" /> <!-- middle line --> <path stroke="#111" stroke-dashoffset="700" stroke-width="45" fill="none" d="m262.3 400c56 0.2 111.3 0 168 0 14.8 0 28.2-10.8 39.1-20.7 9-8.2 15.8-19.2 19.9-30.7 5.2-14.5 9.1-31 5.4-46-4.8-19.1-18.9-35.5-33.7-48.3-7.8-6.7-24.3-4.1-27.6-13.8-5.7-16.5-1.3-35.8-7.7-52.2-7.1-18.4-17.9-36.4-33-49.1-18.4-15.4-42-27.5-66-29.1-24.1-1.7-49.5 6.8-69.8 19.9-16.9 10.9-21.1 35.5-39.1 46-12.4 6.2-27.9-0.8-41.4 2.3-13 3-26.9 6.5-36.8 15.3-13.2 11.7-14.3 25-26.1 46-3.1 5.6-12.9 0.2-19.2 1.5-15.4 3.2-31.9 5.9-44.5 15.3-15.3 11.5-27.7 28.5-33 46.8-4 14-4.3 30.7 2.3 43.7 12.1 24 35.3 50.8 62.1 51.4 65.1 1.5 120.7 1.3 181 1.5z"> <!-- A mask animation with a wide line that reveals the outlines of the cloud --> <animate id="an" attributeName="stroke-dasharray" begin="svg1.click;an.end+2s" dur="6s" values="1281,0;0,1281" fill="freeze" /> </path> </mask> </defs> <!-- Cloud contours --> <path mask="url(#msk)" fill="dodgerblue" class="pathOne" d="m320 128c52.6 0 95.4 42.4 96 94.8-0.2 1.9-0.4 3.9-0.5 5.9l-0.8 23.5 22.3 7.8C462.7 268.9 480 293.1 480 320c0 35.3-28.7 64-64 64H96c-35.3 0-64-28.7-64-64 0-34.9 28.2-63.4 63-64 1.5 0.2 3.1 0.4 4.6 0.5l24.3 1.6 8-23C140.9 209.3 165.1 192 192 192c3.1 0 6.6 0.4 11.2 1.2l22.4 4 11.2-19.8C253.9 146.9 285.8 128 320 128m0-32C272.1 96 230.8 122.7 208.8 161.7 203.4 160.7 197.8 160 192 160 150.1 160 114.8 187.1 101.7 224.6 99.8 224.4 98 224 96 224 43 224 0 267 0 320c0 53 43 96 96 96h320c53 0 96-43 96-96 0-41.9-27.1-77.2-64.6-90.3C447.5 227.8 448 225.9 448 224 448 153.3 390.7 96 320 96Z"/> <text x="200" y="300" font-size="36px" fill="dodgerblue" > Click me <animate id="op" attributeName="opacity" begin="6s" dur="1s" values="1;0" fill="freeze" /> </text> </svg>
How to detect real size of svg path in FireFox?
I'm trying to get real "path" size, using getBoundingClientRect function for that, but in FireFox I get different results In Google Chrome all is well: 1. 100px x 100px 2. 100px x 100px But in FireFox: 1. 104px x 104px 2. 100px x 100px Why stroke-width="1" added 4px? How to get real size without empty spaces in FF? <div>With stroke-width="1"</div> <svg width="110" height="110"> <path stroke-width="1" d="M0 0 L 100 0 L100 100 L 0 100 Z" fill="black" stroke="black"></path> </svg> <br> <br> <div>With stroke-width="0"</div> <svg width="110" height="110"> <path stroke-width="0" d="M0 0 L 100 0 L100 100 L 0 100 Z" fill="black" stroke="black"></path> </svg> P.S. I'm triyng to add "line with text" to this path. I get path position+size with getBoundingClientRect function, create new div in those coordinates. Result:
I made solution for FF. Simple but it works. last_current.attr('stroke-width',0); // FireFox fix! let c_pos = last_current[0].getBoundingClientRect(); last_current.attr('stroke-width', 1); // FireFox fix!