Animate SVG on hover - Make a smile from dots on hover - javascript

I have an SVG file with dots in in straight line. What I want to achieve is when a user hover on the svg file the dots to become a smile like the attached image.
The transition need to be smooth.
What is the best approach here? Can I do it with only css or I should use js also?
Thanks

With a SMIL animation, this is possible without any scripting. It morphs the cubic bezier path from straight to curved and back. The animation is triggered by mouseover and mouseout events over a transparent rectangle that sits on top of the line.
The line itself uses the combination of two little tricks: You can set a pathLength as an attribute, so that stroke-dasharray then computes dash lengths according to it. And for a stroke-dasharray: 0 1 in combination with stroke-linecap, the zero-length dashes are displayed as dots with the stroke width as their diameter. Just play with the values for pathLength and stroke-width to change the distance of the dots and their size.
#line {
fill: none;
stroke: black;
stroke-width: 4;
stroke-dasharray: 0 1;
stroke-linecap: round;
}
#overlay {
opacity: 0;
}
<svg viewBox="0 0 100 100" width="150">
<path id="line" d="M 10 50 C 35 50 65 50 90 50" pathLength="15">
<animate attributeName="d" begin="overlay.mouseover" dur="0.3s"
fill="freeze" restart="whenNotActive"
from="M 10 50 C 35 50 70 50 90 50"
to="M 15 30 C 20 70 80 70 85 30"/>
<animate attributeName="d" begin="overlay.mouseout" dur="0.3s"
fill="freeze" restart="whenNotActive"
from="M 15 30 C 20 70 80 70 85 30"
to="M 10 50 C 35 50 65 50 90 50"/>
</path>
<rect id="overlay" width="100%" height="100%" />
</svg>

In the next example I'm calculating the position of the dots on the paths each at one tenth of the path's total length calculated with getTotalLength. For each circle I'm setting the value of the initial cx (in this case since the initial cy==0 I don't set it.
Also inside each circle I'm adding 2 <animate> elements that will animate the cx and the cy to the next position on the curbed path.
The animation will begin on click.
const SVG_NS = "http://www.w3.org/2000/svg";//svg namespace
const dur = .5;// the animation duration
let circles = Array.from(document.querySelectorAll("circle"))
let la = a.getTotalLength();
let lb = b.getTotalLength();
let start = {x:-100,y:0}
circles.forEach((c,i) =>{
let da = i*la/10;
let db = i*lb/10;
let pa = a.getPointAtLength(da);
let pb = b.getPointAtLength(db);
c.setAttribute("cx",pa.x);
let a1 = document.createElementNS(SVG_NS,"animate");
a1.setAttribute("attributeName","cx");
a1.setAttribute("from",pa.x);
a1.setAttribute("to",pb.x);
a1.setAttribute("dur",dur);
a1.setAttribute("begin","svg.click");
c.appendChild(a1);
let a2 = document.createElementNS(SVG_NS,"animate");
a2.setAttribute("attributeName","cy");
a2.setAttribute("from",pa.y);
a2.setAttribute("to",pb.y);
a2.setAttribute("dur",dur);
a2.setAttribute("begin","svg.click");
c.appendChild(a2);
})
svg.addEventListener("click",()=>{
circles.forEach((c,i) =>{
let db = i*lb/10
let pb = b.getPointAtLength(db);
c.setAttribute("cx",pb.x)
c.setAttribute("cy",pb.y)
})
})
svg{border:solid}
path{fill:none; stroke:black;}
<svg id="svg" viewBox="-150 -50 300 150" width="300">
<path id="a" d="M-100,0 A15000,15000 0 0 0 100,0"/>
<path id="b" d="M-100,0 A150,150 0 0 0 100,0"/>
<circle r="5" />
<circle r="5" />
<circle r="5" />
<circle r="5" />
<circle r="5" />
<circle r="5" />
<circle r="5" />
<circle r="5" />
<circle r="5" />
<circle r="5" />
<circle r="5" />
</svg>
In the example the paths used to calculate the position of the circles are stroked. You can remove the stroke from the CSS.

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?

Putting value at 100 doesn't fill up SVG circle. What's wrong with my calculation

I am trying to fill up a SVG circle that has a radius of 13.5. And I have found a calculation but when entering the value as 100 it's only half full. Which believes me there is something wrong with the math part. Putting the value as 225 fills it up fully. And that's not what's desired at all.
SVG:
//Background of progress circle
<circle r="13.5" cx="16" cy="16" fill="transparent" stroke="#9E9E9E" stroke-width="3" stroke-dasharray="84.82300164692441" stroke-dashoffset="28.27433388230813" />
</svg>
//Progress circle
<svg style={{ height: '32px', width: '32px', transform: 'rotate(150deg)' }}>
<circle r="13.5" cx="16" cy="16" fill="transparent" stroke="#000" stroke-width="3" stroke-dasharray={dashArrayValue} stroke-dashoffset={dashOffsetValue} />
</svg>
Calculation code
let value = 100
let radius = 13.5
let circumference = radius * 2 * Math.PI
let percent = value * 100 / 220
let offset = circumference - ((-percent * 62) / 100) / 100 * circumference
let convertedOffset = -offset
setDashArrayValue(`${circumference}`) //${circumference}
setDashOffsetValue(`${convertedOffset}`)
Hopefully someone can spot the flaw because I certainly can't since my math is awful.
Thanks.
If it is the dash array that you try to manipulate, here are some examples. YOu can see that I'm just changing two values; the rotation of the circle (where the stroke will start) and the first value in the dash array (the length of the stroke). I allso added the pathLength attribute that controls the total length of the stroke of the circle (in this case 360, but it could also be 100 his that fist better into your use case).
<p>From 12 o'clock to 3 o'clock:
<svg height="32px" width="32px">
<circle r="13.5" cx="16" cy="16" fill="transparent"
stroke="#000" stroke-width="3" pathLength="360"
stroke-dasharray="90 360"
transform="rotate(-90 16 16)"/>
</svg>
</p>
<p>From 12 o'clock to 6 o'clock:
<svg height="32px" width="32px">
<circle r="13.5" cx="16" cy="16" fill="transparent"
stroke="#000" stroke-width="3" pathLength="360"
stroke-dasharray="180 360"
transform="rotate(-90 16 16)"/>
</svg>
</p>
<p>From 12 o'clock to 10 o'clock:
<svg height="32px" width="32px">
<circle r="13.5" cx="16" cy="16" fill="transparent"
stroke="#000" stroke-width="3" pathLength="360"
stroke-dasharray="300 360"
transform="rotate(-90 16 16)"/>
</svg>
</p>
<p>From 6 o'clock to 10 o'clock:
<svg height="32px" width="32px">
<circle r="13.5" cx="16" cy="16" fill="transparent"
stroke="#000" stroke-width="3" pathLength="360"
stroke-dasharray="120 360"
transform="rotate(90 16 16)"/>
</svg>
</p>
And the interactive version:
document.forms.form01.number.addEventListener('change', e => {
let number = e.target.value;
document.getElementById('c1').attributes['stroke-dasharray'].value = `${number} 100`;
});
<form name="form01">
<input name="number" type="range" value="50" min="0" max="100" />
</form>
<p><svg height="32px" width="32px">
<circle id="c1" r="13.5" cx="16" cy="16" fill="transparent"
stroke="#000" stroke-width="3" pathLength="100"
stroke-dasharray="50 100"
transform="rotate(-90 16 16)"/>
</svg></p>

SVG progress bar with image

I am trying to create a progress bar (arc) with SVG. I currently have the progress bar working, it is moving the desired amount using a value stored in a data attribute, and looks pretty good. although i am trying to get an image to move around the arc with the bar. The image should start at 0 with the bar and move around to the completion point, say 50% which will be at the top.
<div class="w-100 case-progress-bar input p-2" style="position: relative;" data-percentage="80">
<svg class='progress_bar' viewBox="0 0 100 50" >
<g fill-opacity="0" stroke-width="4">
<path d="M5 50a45 45 0 1 1 90 0" stroke="#EBEDF8"></path>
<path class="progress" d="M5 50a45 45 0 1 1 90 0" stroke="#f00" stroke-dasharray="142" stroke-dashoffset="142"></path>
</g>
<circle fill="url(#image)" id='case_progress__prog_fill' class="case_progress__prog" cx="0" cy="0" r="8" fill="#999" stroke="#fff" stroke-width="1" />
<defs>
<pattern id="image" x="0%" y="0%" height="100%" width="100%" viewBox="0 0 60 60">
<image x="0%" y="0%" width="60" height="60" xlink:href="https://via.placeholder.com/150x150"></image>
</pattern>
</defs>
</svg>
</div>
(function(){
var $wrapper = $('.case-progress-bar'),
$bar = $wrapper.find('.progress_bar'),
$progress = $bar.find('.progress'),
$percentage = $wrapper.data('percentage');
$progress.css({
'stroke-dashoffset': 'calc(142 - (0 * 142 / 100))',
'transition': 'all 1s'
});
var to = setTimeout(function(){
$progress.css('stroke-dashoffset', 'calc(142 - (' + $percentage + ' * 142 / 100))');
clearTimeout(to);
}, 500);
})();
this is what I currently have
this is what i'm trying to achieve
To solve, you need to combine two animations:
Painting half of the arc from the beginning to the middle (top)
Animation of movement of a circle with an image inside
Set the same time for both animations
<div class="w-100 case-progress-bar input p-2" style="position: relative;" data-percentage="80">
<svg class='progress_bar' viewBox="0 0 100 50" >
<g fill-opacity="0" stroke-width="4">
<path id="pfad" d="M5 50C5 44.1 6.1 38.5 8.2 33.4 10.8 26.8 14.9 20.9 20.2 16.3 28.1 9.3 38.6 5 50 5" stroke="#EBEDF8"></path>
<path d="M5 50a45 45 0 1 1 90 0" stroke="#EBEDF8"></path>
<!-- Animation to fill half an arc -->
<path class="progress" d="M5 50a45 45 0 1 1 90 0" stroke="#f00" stroke-dasharray="142" stroke-dashoffset="142">
<animate attributeName="stroke-dashoffset" from="142" to="71" dur="4s" fill="freeze" />
</path>
</g>
<defs>
<pattern id="image" x="0%" y="0%" height="100%" width="100%" viewBox="0 0 60 60">
<image x="0%" y="0%" width="60" height="60" xlink:href="https://via.placeholder.com/150x150"></image>
</pattern>
</defs>
<circle fill="url(#image)" id='case_progress__prog_fill' class="case_progress__prog" cx="0" cy="0" r="8" fill="#999" stroke="#fff" stroke-width="1" >
<!-- Animation of movement of a circle with an image -->
<animateMotion begin="0s" dur="4s" fill="freeze">
<mpath xlink:href="#pfad" />
</animateMotion>
</circle>
</svg>
</div>
This is a case where it has advantages not to use thestroke-dasharray trick.
SVG can draw a marker at the end of a path. That marker can be any sort of grafic, and its syntax is just like that of a <symbol>. The position of the marker is defined by the path d attribute, and not influenced by a dashed stroke.
The general strategy is to compute the endpoint of the path
endpoint_x = center_x - cos(percentage / 100 * 180°) * radius
endpoint_y = center_y - sin(percentage / 100 * 180°) * radius
It is possible to do so relatively seamlessly because you decided to use only a half-circle to represent 100%. I have changed the way the path data are written to make that possible:
`M5 50 A 45 45 0 ${large} 1 ${x} ${y}`
A means: draw an arc and use absolute coordinates.
45 45 0 use a rx of 45, a ry of 45, do not rotate the axis of the arc.
${large} is the important bit. It discerns arcs of less than 180° from those that have more than 180°. As soon as that value would be crossed, the flag must change from 0 to 1. But since you are never expecting values above 180°, you would not need it.
1 means looking in the direction of the path, the arc should be drawn to the left side.
${x} ${y} are the final coordinates expressed in absolute, not relative coordinates.
The <marker> element has a number of attributes that must be considered:
orient="0" means the marker will not change its direction with the direction of the path at its end. orient="auto" would make it turn around , as you would like to see with an arrow for example.
markerUnits="userSpaceOnUse" means the numbers in the other attributes are in px units of the coordinate system of the path. Default would be markerUnits="strokeWidth", which would mean a size relative to the width of the stroke.
viewBox="-8 -8 16 16" is choosen because the circle used is centered around the coordinate system origin.
markerWidth="16" markerHeight="16" is saying how large the marker should be drawn.
refX="0" refY="-10" describes how the marker should be positioned: Take a point in the coordinate system of the marker itself (slightly above its topmost point and in the middle), and align it exactly with the end of the path.
Finally, note the marker-end="url(#image)" presentation attribute for the path. This is what sets the marker, and defines that it will be at the end of the path.
(function(){
var $wrapper = $('.case-progress-bar'),
$bar = $wrapper.find('.progress_bar'),
$progress = $bar.find('.progress'),
$percentage = $wrapper.data('percentage');
function computePath (percentage) {
var x = 50 - Math.cos(percentage / 100 * Math.PI) * 45,
y = 50 - Math.sin(percentage / 100 * Math.PI) * 45,
large = percentage > 100 ? 1 : 0;
return `M5 50 A 45 45 0 ${large} 1 ${x} ${y}`;
}
var to = setTimeout(function(){
$progress.attr('d', computePath($percentage));
clearTimeout(to);
}, 500);
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="w-100 case-progress-bar input p-2" style="position: relative;" data-percentage="80">
<svg class='progress_bar' viewBox="0 0 100 70" >
<g fill-opacity="0" stroke-width="4">
<path d="M5 50a45 45 0 1 1 90 0" stroke="#EBEDF8"></path>
<path class="progress" d="M5 50 A 45 45 0 0 1 95 50`" stroke="#f00"
marker-end="url(#image)"></path>
</g>
<marker id="image" orient="0" markerUnits="userSpaceOnUse"
viewBox="-8 -8 16 16"
markerWidth="16" markerHeight="16"
refX="0" refY="-10">
<circle r="8" fill="#aaf" />
<path d="M-6 0h12" stroke="#000" stroke-width="2" />
</marker>
</svg>
</div>
Just use a little JavaScript since you can't do trigonometry in CSS easily yet.
Codepen: https://codepen.io/mullany/pen/02cd0773588b3d975c8443ab6a87f670
(function(){
var $wrapper = $('.case-progress-bar'),
$bar = $wrapper.find('.progress_bar'),
$progress = $bar.find('.progress'),
$percentage = $wrapper.data('percentage');
var $circpos = $('.case_progress__prog');
$progress.css({
'stroke-dashoffset': 'calc(142 - (0 * 142 / 100))',
'transition': 'all 1s'
});
var to = setTimeout(function(){
$progress.css('stroke-dashoffset', 'calc(142 - (' + $percentage + ' * 142 / 100))');
var angleInRadians = 180*(1-$percentage/100) * 0.01745329251;
var xPos = 5 + 45 * (1 + Math.cos(angleInRadians) );
var yPos = 5 + 45 * (1 - Math.sin(angleInRadians) );
$circpos.css('cx', xPos);
$circpos.css('cy', yPos);
clearTimeout(to);
}, 500);
})();
I had a very similarly shaped loading SVG. You cen see it in action here. The green one at the bottom of the main banner.
What I used was the ProgressBar.js library. It made it very easy. I just focused on adjusting my SVG in terms of shape, because of the design of my site and then just used:
<svg id="progress-bar" xmlns="http://www.w3.org/2000/svg" width="650" height="526" viewBox="0 0 650 526">
<path opacity=".55" id="progress-bar-base" fill="none" stroke="#fefefe" stroke-width="20" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M84.591 512.622S20 441.232 20 324.941 79.903 131.327 137.4 84.476 269.116 20 324.94 20s124.217 15.743 184.57 62.183 89.159 101.578 103.475 142.419c14.316 40.84 25.203 105.21 8.788 170.477-16.415 65.268-43.628 101.409-56.482 117.543"></path>
<linearGradient id="grade" gradientUnits="userSpaceOnUse" x1="592.08" y1="157.665" x2="46.149" y2="472.859">
<stop offset="0" stop-color="#2cab9a"></stop>
<stop offset="1" stop-color="#8ed1c3"></stop>
</linearGradient>
<path fill-opacity="0" id="progress-bar-indicator" stroke="url(#grade)" stroke-width="24" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M84.591 512.622S20 441.232 20 324.941 79.903 131.327 137.4 84.476 269.116 20 324.94 20s124.217 15.743 184.57 62.183 89.159 101.578 103.475 142.419c14.316 40.84 25.203 105.21 8.788 170.477-16.415 65.268-43.628 101.409-56.482 117.543" style="stroke-dasharray: 1362.73, 1362.73; stroke-dashoffset: 1140.45;"></path>
</svg>
var progressBar = new ProgressBar.Path('#progress-bar-indicator', {
easing: 'easeInOut',
duration: 2500
});
progressBar.set(0); // Initiate it at zero.
progressBar.animate(0.33); // this is your percentage of load
It's a very basic example, but I think you could adjust it to your needs.
As for the image, perhaps you could add it to your own SVG at the tip of the loading curve and it should move with it I think.

Fill Percentage area in a custom Oval SVG image

I would like to fill a custom SVG to a specific percentage.
Here is my initial SVG
<svg width="202" height="195" viewBox="0 0 202 195" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.1" d="M96.8166 4.06964C16.0794 8.40606 -20.4645 94.8546 20.2957 157.019C54.6867 204.16 143.361 202.123 184.273 150.807C226.464 97.5789 163.505 0.38025 96.8166 4.06964Z" stroke="#313848" stroke-width="6.87634" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Suppose there is a progress of x% so I would like to fill this SVG like
<svg width="207" height="203" viewBox="0 0 207 203" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.1" d="M99.8166 12.0696C19.0794 16.4061 -17.4645 102.855 23.2957 165.019C57.6867 212.16 146.361 210.123 187.273 158.807C229.464 105.579 166.505 8.38025 99.8166 12.0696Z" stroke="#313848" stroke-width="6.87634" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M99.8142 12.0736C166.502 8.38527 229.463 105.585 187.273 158.812" stroke="#EA7052" stroke-width="6.87634" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M96.1683 2.4287C88.1789 2.85671 84.5529 11.2658 88.579 17.3074C91.9765 21.8887 100.751 21.6836 104.805 16.6905C108.986 11.5113 102.768 2.06471 96.1683 2.4287Z" fill="#EDEDEE" stroke="#EA7052" stroke-width="4.76054" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M171.545 162.236C169.583 169.548 177.007 175.33 184.329 173.522C189.985 171.84 192.408 163.889 188.57 158.747C184.582 153.434 173.156 156.193 171.545 162.236Z" fill="#EDEDEE" stroke="#EA7052" stroke-width="4.76054" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
I am not able to figure out how to achieve this.
I want it to be dynamic so that I can make it for any percentage.
Also, I need to animate it from the starting point to the endpoint in a circular motion.
Any help would be highly appreciatable.
As I've commented:
You can calculate the length of the path using the getTotalLength() method. This represents 100%.
Next you can get the length representing the x% (xperc in the code).
Now you can use stroke-dasharray to represent the partial path.
You can calculate the position of the last point using the getPointAtLength() method.
Please read the comments in my code.
//the desired percentege
let xperc = .35;
//the total length of the path
let tl = base.getTotalLength();
//the partial length at the given percentage xperc
let partial = tl * xperc;
//set the stroke-dasharray of the second use element
perc.setAttribute("stroke-dasharray", `${partial} ${tl -partial}`)
//calculate the position of the point marking the end position
let theEnd = base.getPointAtLength(partial);
// set the cx and the cy attributes for the end point
end.setAttribute("cx", theEnd.x);
end.setAttribute("cy", theEnd.y);
circle {
stroke: red;
fill:white;
stroke-width: 6.87634;
}
<svg width="207" height="203" viewBox="0 0 207 203" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<path id="base" d="M99.8166,12.0696L99.8166,12.0696C166.505,8.38025 229.464,105.579 187.273,158.807C146.361,210.123 57.6867,212.16 23.2957,165.019C-17.4645,102.855 19.0794,16.4061 99.8166,12.0696Z" stroke-width="6.87634" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</defs>
<use xlink:href="#base" stroke="silver" />
<use xlink:href="#base" stroke="red" id="perc" />
<circle cx="99.8166" cy="12.0696" r="10" />
<circle id="end" r="10" />
</svg>
OBSERVATION: since your path goes counter clockwise I had to reverse the path to get the desired result
And this is an example where I'm using an input type range to change the percent value:
let xperc = itr.value;
onInput();
itr.addEventListener("input", onInput)
function onInput() {
xperc = itr.value;
let tl = base.getTotalLength();
let partial = tl * xperc;
perc.setAttribute("stroke-dasharray", `${partial} ${tl - partial}`);
let theEnd = base.getPointAtLength(partial);
end.setAttribute("cx", theEnd.x);
end.setAttribute("cy", theEnd.y);
}
circle {
stroke: red;
fill:white;
stroke-width: 6.87634;
}
<input id="itr" type="range" min="0" max="1" step=".001" value=".35" /><br>
<svg width="207" viewBox="-5 -5 220 220" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<path id="base" d="M99.8166,12.0696L99.8166,12.0696C166.505,8.38025 229.464,105.579 187.273,158.807C146.361,210.123 57.6867,212.16 23.2957,165.019C-17.4645,102.855 19.0794,16.4061 99.8166,12.0696Z" stroke-width="6.87634" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</defs>
<use xlink:href="#base" stroke="silver" />
<use xlink:href="#base" stroke="red" id="perc" />
<circle cx="99.8166" cy="12.0696" r="10" />
<circle id="end" r="10" />
</svg>
And another demo where I'm using javascript to animate it from 0 to 1:
//the animation begins at 0
let xperc = 0;
//get the total length of the path
let tl = base.getTotalLength();
//the request animation id
let rid = null;
function Animation() {
rid = window.requestAnimationFrame(Animation);
// while xperc < 1 increase it's value by 0.001. Else stop the animation
if (xperc < 1) {
xperc += 0.001;
}else{window.cancelAnimationFrame(rid)}
//the same as in the first example
let partial = tl * xperc;
perc.setAttribute("stroke-dasharray", `${partial} ${tl - partial}`);
let theEnd = base.getPointAtLength(partial);
end.setAttribute("cx", theEnd.x);
end.setAttribute("cy", theEnd.y);
}
Animation();
circle {
stroke: red;
fill:white;
stroke-width: 6.87634;
}
<svg width="207" viewBox="-5 -5 220 220" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<path id="base" d="M99.8166,12.0696L99.8166,12.0696C166.505,8.38025 229.464,105.579 187.273,158.807C146.361,210.123 57.6867,212.16 23.2957,165.019C-17.4645,102.855 19.0794,16.4061 99.8166,12.0696Z" stroke-width="6.87634" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</defs>
<use xlink:href="#base" stroke="silver" />
<use xlink:href="#base" stroke="red" id="perc" />
<circle cx="99.8166" cy="12.0696" r="10" />
<circle id="end" r="10" />
</svg>

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