SVG animate dotted line around cicle - javascript

I'm trying to draw a line animation of a circle. I need this to work on mobile so opted for SVG. I have a perfect working example, but it is very inefficient and makes the other animations on the page stutter.
This is what I currently have and what I'm trying to achieve: http://jsfiddle.net/sj76ysqs/
<svg class="bean-halo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"
viewBox="0 0 500 500"
preserveAspectRatio="xMidYMid"
style="width:100%; height:100%; position:absolute; top:0; left:0;">
<path d="M200,200 " id="bean-halo" fill="none" stroke="#FF0000" stroke-linecap="round" stroke-width="2.5" stroke-dasharray="0.1,10" />
</svg>
(function() {
var i = 0,
circle = document.getElementById('bean-halo'),
angle = 0,
radius = 167,
interval = 20,
d, radians, x, y, e;
window.timer = window.setInterval(function() {
angle -= 5;
angle %= 360;
radians = (angle / 180) * Math.PI;
x = 250 + Math.cos(radians) * radius;
y = 250 + Math.sin(radians) * radius;
e = circle.getAttribute('d');
d = e + (i === 0 ? ' M ' : ' L ') + x + ' ' + y;
if (angle === -5 && i !== 0) {
window.clearInterval(window.timer);
this.beanHaloisDrawn = 1;
}
circle.setAttribute('d', d);
i++;
}.bind(this), interval);
})()
I'd like to use the following technique or something similar, but don't know enough about SVGs to do this: http://css-tricks.com/svg-line-animation-works/
I've also though about having a static dotted line that is masked by an animated line that reveals it, but again, I don't know how to do this.
Any help would be appreciated.
UPDATE: The solution has to work on an element with a image as background.

How about just manipulating stroke-dasharray of a circle
<svg class="bean-halo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"
viewBox="0 0 500 500"
preserveAspectRatio="xMidYMid"
style="width:100%; height:100%; position:absolute; top:0; left:0;">
<circle cx="200" cy="200" r="167" id="bean-halo" fill="none" stroke="#FF0000" stroke-linecap="round" stroke-width="2.5" stroke-dasharray="0.1,20000" />
</svg>
together with something like this...
(function() {
var angle = 0;
var circle = document.getElementById('bean-halo');
var dash="0.1,10 ";
var interval = 20;
window.timer = window.setInterval(function() {
circle.setAttribute("stroke-dasharray", dash + " 0, 20000");
dash = dash + "0.1,10 ";
if (angle >= 360) window.clearInterval(window.timer);
angle += 10.1/360;
}.bind(this), interval);
})()
If you don't want to use javascript you'll have to do the interpolation yourself by creating a huge animate with all the intermediate steps. I've done 4 below but you get the gist. You could create the attribute using javascript and a loop though.
<svg class="bean-halo" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"
viewBox="0 0 500 500"
preserveAspectRatio="xMidYMid"
style="width:100%; height:100%; position:absolute; top:0; left:0;">
<circle cx="200" cy="200" r="167" stroke-width="1" stroke="red" fill="white">
<animate attributeName="stroke-dasharray"
values="1,10,0,20000;1,10,1,10,0,20000;1,10,1,10,1,10,0,20000;1,10,1,10,1,10,1,10,0,20000"
dur="4s" repeatCount="1" fill="freeze" />
</circle>
</svg>

Animation trick using two circles, no coding required:-
<svg width="400" height="400" viewBox="0 0 400 400" >
<circle cx="200" cy="200" r="167" stroke-dasharray="1,6" stroke-width="1" stroke="red" fill="white" />
<circle cx="200" cy="200" r="167" stroke-dasharray="1200,1200 " stroke-width="3" stroke-dashoffset="0" stroke="white" fill="none">
<animate attributeType="XML" attributeName="stroke-dashoffset" from="0" to="1200" dur="4s" repeatCount="1" fill="freeze" />
</circle>
</svg>

Related

Calculating exact animation delay

I am trying to animate an svg element as following
a. I want to increase the width of the rect and control the rate of animation speed with a cubic-beziervalue, in this case it is cubic-bezier(0, 0, 0.58, 1).
b. There are also 3 lines which I also want to rotate, each of them exactly when the width of green rect reaches them at it's animation cycle and not before that.
What I tried so far
I came across this post and my understanding was that in the bezier curve graph, for a given output ratio (progression of animation -plotted on y axis), the time ratio (time ratio plotted on x axis) can be calculated, by solving the following equation.
Since, I can already calculate, at what phase of the animation the green rect is going to come across those lines
{50/125, 80/125, 125/125},
they become the Y value and I can use them to solve for t in y(t) and pass on that t value to solve x by passing on t value in x(t), which becomes my time ratio and I can use that to calculate the delay of individual lines.
This is what the code looks like, which unfortunately does not do what I wanted.
I am not sure whether the math has gone wrong here or something else needs to be done. I can feel that I am close, but not sure what needs to be done here for the exact output.
const svg = document.querySelector("svg");
//max px to increase the width animation
var mxWidth = 125;
//animation duration of the green rect
var dur = 2000;
//set style of the green rect
var x = document.querySelector("[class=hitter");
x.style.setProperty('--v2', `${(mxWidth/svg.viewBox.baseVal.width)*100}%`);
x.style.setProperty('--dur', `${dur}ms`)
//what are the x corodinates of the lines
var lnX = [50, 80, 125];
//at what output ratio (width increase) the green rect is likely to
//come across the lines
var progPct = lnX.map(x => x / mxWidth);
//what is the desired cubic bez
var cubicBezCurvVal = "0, 0, 0.58, 1"
//split bezier curve value
var cleanVal = cubicBezCurvVal.split(',');
//clean space with map -retunrns new array with the function, original array unchnaged
var cleanVal = cleanVal.map((x) => parseFloat(x.replace(/ /g, '')));
//p0
const p0 = { x: 0, y: 0 };
//p3
const p3 = { x: 1, y: 1 };
//p1
const p1 = { x: cleanVal[0], y: cleanVal[1] };
//p2
const p2 = { x: cleanVal[2], y: cleanVal[3] };
const x0 = p0.x;
const y0 = p0.y;
const x1 = p1.x;
const y1 = p1.y;
const x2 = p2.x;
const y2 = p2.y;
const x3 = p3.x;
const y3 = p3.y;
const coefficient_a_y = y3 - 3 * y2 + 3 * y1 - y0;
const coefficient_b_y = 3 * (y2 - 2 * y1 + y0);
const coefficient_c_y = 3 * (y1 - y0);
const coefficient_d_y = y0 - y1;
function getY(prgRatio) {
const outputRatio = prgRatio /*y value of cubic bezier curve */
//get all the t values of y of the cubic equation
var solution_t_y = [
{ sol: 1, cubicBezierProgressRatio_y: outputRatio - coefficient_d_y },
{ sol: 2, cubicBezierProgressRatio_y: (-1 * coefficient_b_y + Math.sqrt(Math.pow(coefficient_b_y, 2) - (4 * coefficient_a_y * coefficient_c_y))) / (2 * coefficient_a_y) },
{ sol: 3, cubicBezierProgressRatio_y: (-1 * coefficient_b_y - Math.sqrt(Math.pow(coefficient_b_y, 2) - (4 * coefficient_a_y * coefficient_c_y))) / (2 * coefficient_a_y) }
]
var solTY = solution_t_y.filter(x => x.cubicBezierProgressRatio_y > 0 && x.cubicBezierProgressRatio_y < 1);
function getX(t) {
return Math.pow(1 - t, 3) * x0 +
3 * Math.pow(1 - t, 2) * t * x1 +
3 * (1 - t) * Math.pow(t, 2) * x2 +
Math.pow(t, 3) * x3;
}
solTY.forEach(
(a, i) => {
a.cubicBezierTimeRatio_x = getX(a.cubicBezierProgressRatio_y)
}
)
return solTY;
}
var timeRatio = [];
progPct.forEach(
(a) => timeRatio.push(getY(a))
)
//get all the receivers
var impacter = document.querySelectorAll("[class^='axisLines']");
timeRatio.forEach(
(a, i) => {
(i == 2) ? impacter[i].style.setProperty('--del', `${dur}ms`): impacter[i].style.setProperty('--del', `${(a[0].cubicBezierTimeRatio_x)*dur}ms`)
}
)
.hitter {
visibility: hidden;
/*hide default*/
animation-name: moveWidth;
animation-delay: 0s;
animation-duration: var(--dur);
animation-iteration-count: 1;
animation-timing-function: cubic-bezier(0, 0, 0.58, 1);
animation-direction: normal;
animation-fill-mode: forwards;
}
[class^="axisLine"] {
transform-box: fill-box;
transform-origin: bottom;
stroke-width: 1;
color: green;
animation: rotate 1s cubic-bezier(0, 0, 0.58, 1) var(--del) 1 alternate forwards;
/*rotate 1s cubic-bezier(0, 0, 0.58, 1) var(--del) 1 alternate forwards;*/
}
#keyframes moveWidth {
0% {
visibility: visible;
/*show again*/
width: 0%;
}
100% {
visibility: visible;
/*Edit-2 maintains visibility after animation overs*/
width: var(--v2);
}
}
#keyframes rotate {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(7.5deg);
}
}
<!DOCTYPE html>
<html>
<body>
<link rel="stylesheet" href="style.css">
</link>
<svg class="layer1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 200">
<rect class="bg" id="bg" width="200" height="100" fill="#e6e6e6"></rect>
<rect class="hitter" id="hitter" x="0" y="40" width="0" height="5" fill="#92D050" stroke="#92D050"
stroke-width="0.1" ></rect>
<line class="axisLines0" id="axisLines0" x1="50" x2="50" y1="0" y2="100" stroke="#ED7D31" stroke-width=".5"
></line>
<line class="axisLines1" id="axisLines1" x1="80" x2="80" y1="0" y2="100" stroke="#548235" stroke-width=".5"
></line>
<line class="axisLines2" id="axisLines2" x1="125" x2="125" y1="0" y2="100" stroke="#00B0F0" stroke-width=".5">
</line>
</svg>
<script src="index3.js"></script>
</body>
</html>
When solving such problems, when several animations are interconnected, it is better to use SMIL SVG (in my opinion).
Since smil has a powerful tool that allows you to flexibly set the conditions for sequential start, pause, stop animations.
If there is a need to further change the logic of the work of many animations, then it is enough to change the logical chains in the begin attribute.
begin="dash1.end+1s"
The example below runs multiple animations one after the other, but we don't need to count the timings and delays for each animation.
Animation starts after clicking on the canvas
#tube {
stroke:red;
}
.axisLine {
stroke:green;
}
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 400 200" >
<rect x="20" y="50" width="200" height="50" fill="none" stroke="black" />
<path id="tube" stroke-dasharray="0,200" d="M20,75 220,75" >
<animate id="dash1" attributeName="stroke-dasharray" begin="svg1.click" dur="1s" values="0 200;50 150" fill="freeze" restart="never" />
<animate id="dash2" attributeName="stroke-dasharray" begin="dash1.end+1s" dur="1s" values="50 150;100 100" fill="freeze" />
<animate id="dash3" attributeName="stroke-dasharray" begin="dash2.end+1s" dur="1s" values="100 100;150 50" fill="freeze" />
<animate id="dash4" attributeName="stroke-dasharray" begin="dash3.end+1s" dur="1s" values="150 50;200 0" fill="freeze" />
</path>
<!-- vertical green lines -->
<path id="line1" class="axisLine" d="M70,50 70,100"/>
<path id="line2" class="axisLine" d="M120,50 120,100"/>
<path id="line3" class="axisLine" d="M170,50 170,100" />
<path id="line4" class="axisLine" d="M220,50 220,100" />
</svg>
The example below runs multiple animations one after the other, but we don't need to count the timings and delays for each animation:
The first animation of the growth of the horizontal line -
id="dash1" starts after clicking on the canvas begin="svg1.click"
The second green vertical line rotation animation starts after the
end of the first animation begin="dash1.end"
The third animation in order - the horizontal growth of the line will
begin after the end of the rotation of the green line
#tube {
stroke:brown;
}
.axisLine {
stroke:green;
}
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 400 200" >
<rect x="20" y="50" width="200" height="50" fill="none" stroke="black" />
<path id="tube" stroke-dasharray="0,200" d="M20,75 220,75" >
<animate id="dash1" attributeName="stroke-dasharray" begin="svg1.click" dur="1s" values="0 200;50 150" fill="freeze" restart="never" />
<animate id="dash2" attributeName="stroke-dasharray" begin="dash1.end+1s" dur="1s" values="50 150;100 100" fill="freeze" />
<animate id="dash3" attributeName="stroke-dasharray" begin="dash2.end+1s" dur="1s" values="100 100;150 50" fill="freeze" />
<animate id="dash4" attributeName="stroke-dasharray" begin="dash3.end+1s" dur="1s" values="150 50;200 0" fill="freeze" />
</path>
<!-- Vertical line animation-->
<path id="line1" class="axisLine" d="M70,50 70,100">
<animateTransform id="aT1"
attributeName="transform"
type="rotate"
begin="dash1.end" dur="1s"
values="
0 70 100;
14 70 100;
0 70 100"
/>
</path>
<path id="line2" class="axisLine" d="M120,50 120,100"/>
<path id="line3" class="axisLine" d="M170,50 170,100" />
<path id="line4" class="axisLine" d="M220,50 220,100" />
</svg>
Below is the complete code:
#tube {
stroke:brown;
}
.axisLine {
stroke:green;
}
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 400 200" >
<rect x="20" y="50" width="200" height="50" fill="none" stroke="black" />
<path id="tube" stroke-dasharray="0,200" d="M20,75 220,75" >
<!-- Line Growth Animation -->
<animate id="dash1" attributeName="stroke-dasharray" begin="svg1.click" dur="1s" values="0 200;50 150" fill="freeze" restart="never" />
<animate id="dash2" attributeName="stroke-dasharray" begin="aT1.end+0.2s" dur="1s" values="50 150;100 100" fill="freeze" />
<animate id="dash3" attributeName="stroke-dasharray" begin="aT2.end+0.2s" dur="1s" values="100 100;150 50" fill="freeze" />
<animate id="dash4" attributeName="stroke-dasharray" begin="aT3.end+0.2s" dur="1s" values="150 50;200 0" fill="freeze" />
</path>
<!-- Animation of rotation of vertical lines -->
<path id="line1" class="axisLine" d="M70,50 70,100">
<animateTransform id="aT1"
attributeName="transform"
type="rotate"
begin="dash1.end" dur="1s"
values="
0 70 100;
14 70 100;
0 70 100"
/>
</path>
<path id="line2" class="axisLine" d="M120,50 120,100">
<animateTransform id="aT2"
attributeName="transform"
type="rotate"
begin="dash2.end" dur="1s"
values="
0 120 100;
14 120 100;
0 120 100"
/>
</path>
<path id="line3" class="axisLine" d="M170,50 170,100" >
<animateTransform id="aT3"
attributeName="transform"
type="rotate"
begin="dash3.end" dur="1s"
values="
0 170 100;
14 170 100;
0 170 100"
/>
</path>
<path id="line4" class="axisLine" d="M220,50 220,100" >
<animateTransform id="aT4"
attributeName="transform"
type="rotate"
begin="dash4.end" dur="1s"
values="
0 220 100;
14 220 100;
0 220 100"
/>
</path>
</svg>
In the following example, I will double the time of 1 and 3 of the line growth animation - dur="2s"
Note: that the logic of the application will not break, the animations will still go one after another
If CSS animations were used, then timings and delays would have to be recalculated for each animation.
Animation starts after clicking on the canvas
#tube {
stroke:brown;
}
.axisLine {
stroke:green;
}
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 400 200" >
<rect x="20" y="50" width="200" height="50" fill="none" stroke="black" />
<path id="tube" stroke-dasharray="0,200" d="M20,75 220,75" >
<!-- Line Growth Animation -->
<animate id="dash1" attributeName="stroke-dasharray" begin="svg1.click" dur="2s" values="0 200;50 150" fill="freeze" restart="never"/>
<animate id="dash2" attributeName="stroke-dasharray" begin="aT1.end+0.2s" dur="1s" values="50 150;100 100" fill="freeze" />
<animate id="dash3" attributeName="stroke-dasharray" begin="aT2.end+0.2s" dur="2s" values="100 100;150 50" fill="freeze" />
<animate id="dash4" attributeName="stroke-dasharray" begin="aT3.end+0.2s" dur="1s" values="150 50;200 0" fill="freeze" />
</path>
<!-- Animation of rotation of vertical lines -->
<path id="line1" class="axisLine" d="M70,50 70,100">
<animateTransform id="aT1"
attributeName="transform"
type="rotate"
begin="dash1.end" dur="1s"
values="0 70 100;14 70 100;0 70 100"
/>
</path>
<path id="line2" class="axisLine" d="M120,50 120,100">
<animateTransform id="aT2"
attributeName="transform"
type="rotate"
begin="dash2.end" dur="1s"
values="0 120 100;14 120 100;0 120 100"
/>
</path>
<path id="line3" class="axisLine" d="M170,50 170,100" >
<animateTransform id="aT3"
attributeName="transform"
type="rotate"
begin="dash3.end" dur="1s"
values="0 170 100;14 170 100;0 170 100"
/>
</path>
<path id="line4" class="axisLine" d="M220,50 220,100" >
<animateTransform id="aT4"
attributeName="transform"
type="rotate"
begin="dash4.end" dur="1s"
values="0 220 100;14 220 100;0 220 100"
/>
</path>
</svg>

SVG rotate attribute of the <animateMotion> element set to auto not working correctly

I have a question to svg animation. Please find my code here. Using javascript I am adding animateMotion element to red arrow symbol. I would like to achieve the following thing
Arrow should move on the path designated by rectangle and rotate to align with the slope of the path (so rotate 90 deg)
I can partially meet this requirement. Moving arrow along the given path is quite simple. JS script is setting path attribute for animateMotion element. I wanted to use rotate attribute to fit rotate changes to the path.
Please have a look that when you uncomment this line
animateMotion.setAttribute("rotate", "auto");
in JS code something strange happens. Instead rotating 90 deg after reaching each corner arrow unexpected disappear.
Do you know why?
Thank you very much in advance.
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
function getArrowSymbolXcoordinate(pathAttribute) {
var commaIdx = pathAttribute.indexOf(',');
return pathAttribute.substring(1,commaIdx);
}
function getArrowSymbolYcoordinate(pathAttribute) {
var commaIdx = pathAttribute.indexOf(',');
var lineCommandIdx = pathAttribute.indexOf('l');
console.log(pathAttribute.substring(commaIdx, lineCommandIdx));
return pathAttribute.substring(commaIdx+1, lineCommandIdx);
}
function getTopPathAttribute(element, xCoordinate) {
var toTopRightCorrner = Math.abs(topRightCorrner.x - xCoordinate);
var path = 'm0,0 ' + 'h' + toTopRightCorrner + ' v' + height + ' h-' + width + ' v-' + height + ' z';
return path;
}
let topLeftCorrner = new Point(200,100);
let topRightCorrner = new Point(350,100);
let bottomLeftCorrner = new Point(200,150);
let bottomRightCorrner = new Point(350,150);
let topArrowSymbols = Array.from(document.getElementsByClassName('top'));
let width = Math.abs(topLeftCorrner.x - topRightCorrner.x);
let height = Math.abs(topLeftCorrner.y - bottomLeftCorrner.y);
topArrowSymbols.forEach( function(element) {
var xCoordinate = getArrowSymbolXcoordinate(element.getAttribute('d'));
var animateMotion = document.createElementNS('http://www.w3.org/2000/svg', "animateMotion");
var pathAttribute = getTopPathAttribute(element, xCoordinate);
animateMotion.setAttribute("dur", "7s");
animateMotion.setAttribute("path", pathAttribute);
//animateMotion.setAttribute("rotate", 'auto');
element.appendChild(animateMotion);
});
body {
height: 100vh;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script src="main_home.js" defer="defer"></script>
</head>
<body>
<figure >
<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" viewbox="120 80 300 200">
<g>
<rect fill="none" height="50" stroke="black" stroke-width="2" width="150" x="200" y="100"/>
<path class="arrow_symbol top" d="m215.21876,99.72372l-2.49741,-2.5l1.64474,0l2.49741,2.5l-2.49741,2.5l-1.64474,0l2.49741,-2.5z" fill="#ffffff" stroke="#ff0000" stroke-width="2"/>
</g>
</svg>
</figure>
</body>
</html>
Your problem is that your arrow has a large offset from the origin of the SVG. So when it hits the end of the first curve and rotates around the corner, it is disappearing off screen.
Here is a simplified example that hopefully shows what is happening.
<svg viewbox="-100 -100 400 400" width="400">
<!-- axes to show the origin -->
<line x1="0" y1="-100" x2="0" y2="300" stroke="#cce" stroke-width="1"/>
<line x1="-100" y1="0" x2="300" y2="0" stroke="#cce" stroke-width="1"/>
<!-- the path that the arrow is actually following (ie the one in the animateMotion) -->
<rect width="80" height="80" fill="none" stroke="#888" stroke-width="2"/>
<!-- dashed line showing the offset from the animateMotionPath to the arrow -->
<line x1="0" y1="0" x2="100" y2="100" fill="none" stroke="#ff0000" stroke-width="2" stroke-dasharray="10 10">
<animateMotion dur="7s" rotate="auto"
path="M 0,0 L 80,0 L 80,80 L 0,80 Z"/>
</line>
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- the pon-screen path that the arrow appears to be following -->
<rect fill="none" x="100" y="100" width="80" height="80" stroke="black" stroke-width="2" />
<!-- the arrow -->
<path class="arrow_symbol top" d="M 110,100 L 100,110 L 100,90 Z" fill="#ffffff" stroke="#ff0000" stroke-width="2">
<animateMotion dur="7s" rotate="auto"
path="M 0,0 L 80,0 L 80,80 L 0,80 Z"/>
</path>
</svg>
To fix your SVG, you have to make sure that your arrow rotates around its centre. Not the origin.
let topArrowSymbols = Array.from(document.getElementsByClassName('top'));
topArrowSymbols.forEach( function(element) {
var animateMotion = document.createElementNS('http://www.w3.org/2000/svg', "animateMotion");
animateMotion.setAttribute("dur", "7s");
animateMotion.setAttribute("path", 'm 220,100 h 130 v 50 h -150 v -50 z');
animateMotion.setAttribute("rotate", 'auto');
animateMotion.setAttribute("fill", "freeze");
element.appendChild(animateMotion);
});
body {
height: 100vh;
}
svg {
overflow: visible;
position: absolute;
top: 400px;
left: 400px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script src="main_home.js" defer="defer"></script>
</head>
<body>
<figure >
<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" viewbox="120 80 300 200">
<g>
<rect id="my-path" fill="none" height="50" stroke="black" stroke-width="2" width="150" x="200" y="100"/>
<path class="arrow_symbol top" d="m0.21876,0.72372l-2.49741,-2.5l1.64474,0l2.49741,2.5l-2.49741,2.5l-1.64474,0l2.49741,-2.5z" fill="#ffffff" stroke="#ff0000" stroke-width="2"/>
</g>
</svg>
</figure>
</body>
</html>

SVG - Greensock Timeline for animation

What is the GSAP counterpart of the additive and accumulate animation attributes in SVG? I am animating using click events so I want to continue animation from the last state of the object. Or is there a way to access those attributes.
I am just starting out, so any links to guides or tutorials is appreciated.
var svgNS = "http://www.w3.org/2000/svg";
function anim(evt) {
if (window.svgDocument == null)
svgDoc = evt.target.ownerDocument;
rot('shape', 120);
}
function rot(target_id, angle) {
var my_element = svgDoc.getElementById(target_id);
var a = svgDoc.createElementNS(svgNS, "animateTransform");
var bb = my_element.getBBox();
var cx = bb.x + bb.width / 2;
var cy = bb.y + bb.height / 2;
a.setAttributeNS(null, "attributeName", "transform");
a.setAttributeNS(null, "attributeType", "XML");
a.setAttributeNS(null, "type", "rotate");
a.setAttributeNS(null, "dur", "1s");
a.setAttributeNS(null, "repeatCount", "1");
a.setAttributeNS(null, "fill", "freeze");
a.setAttributeNS(null, "additive", "sum");
a.setAttributeNS(null, "accumulate", "sum");
a.setAttributeNS(null, "from", "0 " + cx + " " + cy);
a.setAttributeNS(null, "to", angle + " " + cx + " " + cy);
my_element.appendChild(a);
a.beginElement();
}
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="500px" height="500px" viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve">
<g id="shape">
<circle fill="#FFA557" stroke="#000000" stroke-miterlimit="10" cx="254.186" cy="247.288" r="107.203" />
<polygon fill="#8CFFD5" stroke="#000000" stroke-miterlimit="10" points="239.634,218.5 225.083,193.5 239.634,168.5
268.736,168.5 283.288,193.5 268.736,218.5 " />
<polygon fill="#8CFFD5" stroke="#000000" stroke-miterlimit="10" points="239.634,268.5 225.083,243.5 239.634,218.5
268.736,218.5 283.288,243.5 268.736,268.5 " />
<polygon fill="#8CFFD5" stroke="#000000" stroke-miterlimit="10" points="195.634,243.5 181.083,218.5 195.634,193.5
224.737,193.5 239.288,218.5 224.737,243.5 " />
<polygon fill="#8CFFD5" stroke="#000000" stroke-miterlimit="10" points="282.635,243.5 268.083,218.5 282.635,193.5
311.736,193.5 326.288,218.5 311.736,243.5 " />
</g>
<g onclick="anim(evt)">
<rect x="123.5" y="391.5" fill="#6E005D" stroke="#000000" stroke-miterlimit="10" width="268" height="77" />
<text transform="matrix(1 0 0 1 184.0811 439.5081)" fill="#FFFFFF" font-family="'ComicSansMS'" font-size="36">Click Me</text>
</g>
</svg>
I am not sure if I understand your question correctly but is this the kind of effect you are trying to reproduce using TweenMax? Let me know.
Update #1:
Using TimelineMax:
Keep adding new TweenMax tweens into an existing timeline
instance by using the add() method of TimelineMax.
Check to see if timeline is currently in a playing state, if not, play() it.
jsFiddle #1.
Update #2:
Increment the speed of timeline using
timeScale() on a per-click basis.
Set a cap on this timeScale() property.
Add an onComplete callback to the timeline instance to clear() the timeline.
jsFiddle #2.

SVG animation using javascript not working in firefox

I'm struggling with something that should be easy, let me explain :
I have a SVG using the animateTransform tag I use JavaScript to
change the form attribut
then I use the beginElement()
The SVG
<svg version="1.2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%">
<defs>
<path id="right" fill="#F7931E" d="M55.002,30c0-13.808-11.192-25-25-25v6c10.477,0,19,8.523,19,19s-8.523,19-19,19v6 C43.81,55,55.002,43.808,55.002,30z">
<animateTransform id="rotate" attributeName="transform" type="rotate" from="0 30 30" to="180 30 30" begin="0s" fill="freeze"/>
</path>
<path id="left" fill="#F7931E" d="M11.002,30c0-10.477,8.523-19,19-19V5c-13.808,0-25,11.192-25,25s11.192,25,25,25v-6 C19.526,49,11.002,40.477,11.002,30z">
<animateTransform id="rotate2" attributeName="transform" type="rotate" from="0 30 30" to="180 30 30" begin="0s" fill="freeze"/>
</path>
<mask id="hide-left">
<rect x="0" y="0" width="30" height="60" fill="white"/>
</mask>
<mask id="hide-right">
<rect id="super" x="30" y="0" width="30" height="60" fill="white"/>
</mask>
</defs>
<!-- Layout -->
<use xlink:href="#right" mask="url(#hide-right)"/>
<use xlink:href="#left" mask="url(#hide-left)"/>
</svg>
The JS
var updateCircle= function (pourcentage) {
if (pourcentage < 0.5) {
var angle = pourcentage * 2;
var angle_vert = 180 * angle;
var angle_rouge = 0;
}
else {
var angle_vert = 180;
var angle = (1 - pourcentage) * 2;
var angle_rouge = 180 - (180 * angle);
}
$("#mod_countdown #right #rotate").attr('from', angle_vert + ' 30 30');
$("#mod_countdown #left #rotate2").attr('from', angle_rouge + ' 30 30');
$("#mod_countdown #right #rotate")[0].beginElement();
$("#mod_countdown #left #rotate2")[0].beginElement();
};
The example to play with : http://jsfiddle.net/oandcf08/2/
My problem is : it's not working on firefox and I don't know why...
[edit]
Fun fact : when I add the attribute transform : <path transform="scale(5)" ... it's working in firefox check it out : http://jsfiddle.net/oandcf08/3/ , it's working but I don't understand why and it don't seem to be a reliable workaround

Can't figure out this svg animation

I have been trying to get the circles in my stage to move around the ellipses, I even copied code from someone that had a very similar setup, but no dice. Heres the codepen and the markup below.
http://codepen.io/alcoven/pen/XJXMNW
<div id="wrapper">
<div class="container">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 30 30" enable-background="new 0 0 30 30" xml:space="preserve">
<!--<g>
<circle fill="#F26451" cx="17.6" cy="3.3" r="1.4"/>
</g>
<g>
<circle fill="#F26451" cx="6.4" cy="23.1" r="1.4"/>
</g>-->
<line class="line" stroke-width="1.3" stroke-miterlimit="10" x1="3.7" y1="26.1" x2="26.2" y2="3.6"/>
<path class="vertical" d="M9.9,14.9a5,14 0 1,0 10,0a5,14 0 1,0 -10,0"/>
<ellipse class="_x34_5deg" transform="matrix(0.5037 0.8639 -0.8639 0.5037 20.2917 -5.4991)" stroke-width="1.3" stroke-miterlimit="10" cx="14.9" cy="14.9" rx="5" ry="14"/>
<ellipse class="_x2D_45deg" transform="matrix(-0.5037 0.8639 -0.8639 -0.5037 35.3327 9.5202)" stroke-width="1.3" stroke-miterlimit="10" cx="14.9" cy="14.9" rx="5" ry="14"/>
<path class="circlet" d="M16.4,3.2a1.3,1.3 0 1,0 2.6,0a1.3,1.3 0 1,0 -2.6,0"/>
<path class="circleb" d="M5,23.2a1.4,1.4 0 1,0 2.8,0a1.4,1.4 0 1,0 -2.8,0"/>
</svg>
</div>
</div>
CSS
#wrapper {
top:0;
left:0;
position:absolute;
width:100%;
height:100%;
background:#F26451;
}
.container {
width:100%;
position:fixed;
top:30%;
bottom:70%;
}
svg {
width:100px;
height:auto;
margin:10% auto;
display:block;
}
line, .vertical, ellipse._x34_5deg, ellipse._x2D_45deg {
stroke:#fff;
fill:none;
stroke-width:1.3;
stroke-miterlimit:10;
}
.circlet, .circleb {
stroke:#fff;
fill:#F26451;
stroke-width:1.3;
stroke-miterlimit:10;
}
.line {
display:none;
}
JS
(function($){
$('[class^="circle-"]').animate({opacity:1},500);
// get the animation path node
var $path = $('.vertical'), path = $path[0];
var $path2 = $('.vertical'), path2 = $path2[0];
// get the animation object node
var $obj = $('.circlet');
var $obj2 = $('.cirlceb');
// get path's length
var pathLength = path.getTotalLength();
var pathLength2 = path2.getTotalLength();
// create new tween by initializing TWEEN.Tween object from 0
var tween = new TWEEN.Tween({ length: 0 })
// to path length
// in 2000 milliseconds
.to({ length: pathLength }, 1500)
// on update callback fires on every tick
.onUpdate(function(){
var point = path.getPointAtLength(this.length);
$obj.css({
'transform': 'translate('+ point.x + 'px,'+ point.y +'px)'
});
}).repeat(999999999).start();
var tween2 = new TWEEN.Tween({ length: 0 })
// to path length
// in 2000 milliseconds
.to({ length: pathLength2 }, 1500)
// on update callback fires on every tick
.onUpdate(function(){
var point2 = path2.getPointAtLength(this.length);
$obj2.css({
'transform': 'translate('+ point2.x + 'px,'+ point2.y +'px)'
});
}).repeat(999999999).start();
// animate loop
animate = function(){
requestAnimationFrame(animate)
TWEEN.update()
}
//start the animation loop
animate()
}(jQuery));
Can't quite figure out why this isn't working, not sure if it's my js or the way my svg is setup please help :]
Here's the js I copied http://codepen.io/joshy/pen/cojbD
Define an animation path, which could be a circle , ellipse or Bezier curve.
Enclose the path definition between animateMotion tags ,one pair within each moving object definition, as follows:
<?xml version="1.0"?>
<svg width="120" height="120" viewBox="0 0 120 120"
xmlns="http://www.w3.org/2000/svg" version="1.1"
xmlns:xlink="http://www.w3.org/1999/xlink" >
<!-- Draw the outline of the motion path in grey, along
with 2 small circles at key points -->
<path d="M10,110 A120,120 -45 0,1 110 10 A120,120 -45 0,1 10,110"
stroke="lightgrey" stroke-width="2"
fill="none" id="theMotionPath"/>
<circle cx="10" cy="110" r="3" fill="lightgrey" />
<circle cx="110" cy="10" r="3" fill="lightgrey" />
<!-- Here is a red circle which will be moved along the motion path. -->
<circle cx="" cy="" r="5" fill="red">
<!-- Define the motion path animation -->
<animateMotion dur="6s" repeatCount="indefinite">
<mpath xlink:href="#theMotionPath"/>
</animateMotion>
</circle>
No javascript or jQuery required !

Categories