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.
Related
I created a circle in Inkscape and switched off the fill so that only the stroke is visible and also made the starting point 45 degrees and the ending point 315 degrees.
I then rotated it 90 degrees and this is the end result.
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg width="300" height="300" version="1.1" viewBox="0 0 79.375 79.375" xmlns="http://www.w3.org/2000/svg">
<path transform="rotate(90)" d="m64.961-15.355a34.984 34.412 0 0 1-49.474 1e-6 34.984 34.412 0 0 1-1e-6 -48.666 34.984 34.412 0 0 1 49.474-2e-6" fill="none" opacity=".55814" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="10.583"/>
</svg>
And it renders like this:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg width="300" height="300" version="1.1" viewBox="0 0 79.375 79.375" xmlns="http://www.w3.org/2000/svg">
<path transform="rotate(90)" d="m64.961-15.355a34.984 34.412 0 0 1-49.474 1e-6 34.984 34.412 0 0 1-1e-6 -48.666 34.984 34.412 0 0 1 49.474-2e-6" fill="none" opacity=".55814" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="10.583"/>
</svg>
I want to be able to overlay a copy and control the length of the stroke starting at the bottom left corner. So for example display only 22% of the total length of the overlay or display the segment from the 315 degree end point to 255.60 degrees?
How would we go about this (Effectively programmatically doing the inkscape start and end controls)?
Probably easiest way would be to use pathLength attribute like:
pathlength="100" stroke-dasharray="10 100"
Altering the the first value of the stroke-dasharray would express the "percentage" (10 in above example makes it occupy 10% of the total length). Moving that segment along the path is possible thanks negative stroke-dashoffset. Funky perk of this approach is that it can be used for "tracing" any compact path:
<body bgcolor="darkslategray" text="snow">
Length:
<input id="l" type="range" value="10" max="80"
oninput="p.setAttribute('stroke-dasharray', value + ' 100');
o.max = 100 - value; nextElementSibling.value = value;
"> <output>10</output><br>
Offset:
<input id="o" type="range" value="20" max="90"
oninput="p.setAttribute('stroke-dashoffset', - value);
l.max = 100 - value; nextElementSibling.value = value;
"> <output>20</output><br>
<svg width="300" height="150" viewBox="0 0 80 80" fill="none" stroke-linecap="round"
stroke="#000" stroke-width="10">
<path d="M13 66 A 35 35 0 1 1 65 65 A 10 10 1 1 1 40 45 A 7 7 1 1 0 25 35" />
<path d="M13 66 A 35 35 0 1 1 65 65 A 10 10 1 1 1 40 45 A 7 7 1 1 0 25 35"
id="p"
stroke="#F99"
stroke-width="4"
pathlength="100.1"
stroke-dashoffset="-20"
stroke-dasharray="10 1000"
/></svg>
<!--
* 100.1 pathlength value is to keep zero length "dot" at the final 100 offset
* 1000 array "gap" value is here just to be sure; any value greater or equal pathlength should do.
-->
The following snippet takes a percentage as input and then computes the parameters of the elliptical arc curve command A in the <path> element. 100% corresponds to a three-quarter-arc.
var path = document.getElementById("path");
function draw(v) {
var theta = v * Math.PI * 0.015;
var large = theta <= Math.PI ? 0 : 1;
path.setAttribute("d", `M1,0 A1,1 0 ${large} 1 ${Math.cos(theta)},${Math.sin(theta)}`);
}
<svg width="150" height="150" viewBox="-1.2 -1.2 2.4 2.4"
transform="rotate(135)">
<path d="M1,0 A1,1 0 1 1 0,-1"
fill="none" opacity=".55814"
stroke="#000" stroke-linecap="round"
stroke-linejoin="round" stroke-width=".25"/>
<path id="path"
fill="none"
stroke="red" stroke-linecap="round"
stroke-linejoin="round" stroke-width=".1"/>
</svg>
<form onsubmit="draw(this.v.value); return false;">
<input name="v"/>%
<input type="submit" value="Draw"/>
</form>
(After reading myf's answer, it became clear that you want two arcs in total. I have adapted my code accordingly, but the idea remains basically the same.)
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.
I would like to make an image appear as hexagon.
Therefore I am using svg.
<svg id="hexagon">
<defs>
<pattern id="pattern1" height="100%" width="100%" patternContentUnits="objectBoundingBox">
<image height="1" width="1" preserveAspectRatio="none" xlink:href="https://pixabay.com/static/uploads/photo/2016/01/14/01/41/image-view-1139204_960_720.jpg"/>
</pattern>
</defs>
<polygon fill="url(#pattern1)" points=" 121.25 0 242.5 100 242.5 300 121.25 400 121.25 400 0 300 0 100"/>
</svg>
Now I want to manipulate the coordinates of this svg depending on position of mouse on screen. So if the mouse-cursor is on right side of screen the first point of hexagon (the upper one) should be at right edge of screen too. Otherwise if the mouse-cursor is on left side of screen the first point of hexagon should be at left edge of screen. The position of this upper point should change dynamically depending on mouse-cursor position.
For testing I tried this one to access the points but it did not work:
<script>
var polygon = document.getElementById("hexagon");
polygon.setAttribute("points", "0,0 100,100 200,200");
</script>
What did I do wrong?
You need to find the center of the svg (I think I have that correct but you might want to verify). Once you have that, you can rotate it to "look at the mouse"
document.addEventListener("mousemove", function(event) {
var follower = document.getElementById("hexagon");
// -----------------------
// calculate the center of the hexagon
// -----------------------
var followerCentroid = (function() {
var followerClientBox = follower.getBoundingClientRect();
return [
(followerClientBox.top + followerClientBox.bottom) / 2,
(followerClientBox.left + followerClientBox.right) / 2
];
})();
// -----------------------
// -----------------------
// rotate to look at mouse
// -----------------------
var lookAngle = Math.atan2(
event.pageX - followerCentroid[1],
-(event.pageY - followerCentroid[0])) * (180 / Math.PI);
follower.style.transform = 'rotate(' + lookAngle + 'deg)';
// -----------------------
});
<div style="padding: 50px;">
<svg id="hexagon">
<defs>
<pattern id="pattern1" height="100%" width="100%" patternContentUnits="objectBoundingBox">
<image height="1" width="1" preserveAspectRatio="none" xlink:href="https://pixabay.com/static/uploads/photo/2016/01/14/01/41/image-view-1139204_960_720.jpg" />
</pattern>
</defs>
<polygon fill="url(#pattern1)" points=" 121.25 0 242.5 100 242.5 300 121.25 400 121.25 400 0 300 0 100" />
</svg>
</div>
I was wondering if there is a way to set the transform attribute to an element so that it can rotate (around his own center) and orbit around a different point. This is what I have so far:http://jsfiddle.net/8nmtrg84/1/
function timerTick() {
with (new Date()) {
var v;
v = 8 * getSeconds();
document.getElementById('left_gear_small').setAttribute('transform', 'rotate(' + v + ', 100, 100)');
setTimeout(timerTick, 1000);
}
}
I managed to orbit it around a point, however I am not sure how to rotate it around its own center to0, simultaneously.
Thanks!
Short answer:
First you have to find where the centre of your object is. You provided (100,100) as the rotation centre coordinates, but the centre of your gear object is actually at (65,141) (jsfiddle link). Once thats' fixed, then you can think about how to make it orbit some other point. This could be done by enclosing it in a <g> element with another rotation transform (jsfiddle again).
Longer answer:
You're approaching this the wrong way. Rotations are much easier to work with if you start with an object whose origin is already at the point you want it to rotate around. With gear objects in particular, it's very easy to calculate the coordinates with a bit of code. If you need to apply a translation offset too, use another <g> element.
Here's an example with two gears that rotate around their own centres while orbiting a third point:
var theta = 0;
function rotate_gears() {
theta = theta + 3;
document.getElementById('gear1').setAttribute('transform', 'rotate(' + theta + ')');
document.getElementById('gear2').setAttribute('transform', 'rotate('+(15-theta*3) + ')');
document.getElementById('spin').setAttribute('transform', 'rotate(' + (theta/2) + ')');
}
setInterval(rotate_gears,30);
<svg width="200" height="200" viewBox="0 0 100 100">
<g transform="translate(50,50)">
<g id="spin" transform="rotate(0)">
<g transform="translate(-20,0)">
<path id="gear1" fill="gold" d="M0 42.5 1.41 42.98 3.07 46.9 4.66 47.27 6.2 47.09 7.66 46.37 8.39 42.17 9.65 41.39 11 41.05 12.48 41.15 15.11 44.51 16.73 44.46 18.18 43.88 19.4 42.81 19.02 38.57 20.03 37.48 21.25 36.81 22.71 36.52 26.11 39.08 27.67 38.61 28.92 37.68 29.82 36.33 28.35 32.33 29.05 31.02 30.05 30.05 31.38 29.39 35.34 30.99 36.72 30.13 37.68 28.92 38.2 27.38 35.75 23.89 36.09 22.44 36.81 21.25 37.92 20.27 42.15 20.79 43.27 19.6 43.88 18.18 43.99 16.56 40.72 13.82 40.67 12.34 41.05 11 41.88 9.76 46.1 9.17 46.87 7.74 47.09 6.2 46.77 4.61 42.91 2.81 42.48 1.39 42.5 0 42.98-1.41 46.9-3.07 47.27-4.66 47.09-6.2 46.37-7.66 42.17-8.39 41.39-9.65 41.05-11 41.15-12.48 44.51-15.11 44.46-16.73 43.88-18.18 42.81-19.4 38.57-19.02 37.48-20.03 36.81-21.25 36.52-22.71 39.08-26.11 38.61-27.67 37.68-28.92 36.33-29.82 32.33-28.35 31.02-29.05 30.05-30.05 29.39-31.38 30.99-35.34 30.13-36.72 28.92-37.68 27.38-38.2 23.89-35.75 22.44-36.09 21.25-36.81 20.27-37.92 20.79-42.15 19.6-43.27 18.18-43.88 16.56-43.99 13.82-40.72 12.34-40.67 11-41.05 9.76-41.88 9.17-46.1 7.74-46.87 6.2-47.09 4.61-46.77 2.81-42.91 1.39-42.48 0-42.5-1.41-42.98-3.07-46.9-4.66-47.27-6.2-47.09-7.66-46.37-8.39-42.17-9.65-41.39-11-41.05-12.48-41.15-15.11-44.51-16.73-44.46-18.18-43.88-19.4-42.81-19.02-38.57-20.03-37.48-21.25-36.81-22.71-36.52-26.11-39.08-27.67-38.61-28.92-37.68-29.82-36.33-28.35-32.33-29.05-31.02-30.05-30.05-31.38-29.39-35.34-30.99-36.72-30.13-37.68-28.92-38.2-27.38-35.75-23.89-36.09-22.44-36.81-21.25-37.92-20.27-42.15-20.79-43.27-19.6-43.88-18.18-43.99-16.56-40.72-13.82-40.67-12.34-41.05-11-41.88-9.76-46.1-9.17-46.87-7.74-47.09-6.2-46.77-4.61-42.91-2.81-42.48-1.39-42.5 0-42.98 1.41-46.9 3.07-47.27 4.66-47.09 6.2-46.37 7.66-42.17 8.39-41.39 9.65-41.05 11-41.15 12.48-44.51 15.11-44.46 16.73-43.88 18.18-42.81 19.4-38.57 19.02-37.48 20.03-36.81 21.25-36.52 22.71-39.08 26.11-38.61 27.67-37.68 28.92-36.33 29.82-32.33 28.35-31.02 29.05-30.05 30.05-29.39 31.38-30.99 35.34-30.13 36.72-28.92 37.68-27.38 38.2-23.89 35.75-22.44 36.09-21.25 36.81-20.27 37.92-20.79 42.15-19.6 43.27-18.18 43.88-16.56 43.99-13.82 40.72-12.34 40.67-11 41.05-9.76 41.88-9.17 46.1-7.74 46.87-6.2 47.09-4.61 46.77-2.81 42.91-1.39 42.48z"
/>
</g>
<g transform="translate(40,0)">
<path id="gear2" fill="orange" transform="rotate(15)" d="M0 12.5 1.27 12.94 3.32 16.67 5.08 16.75 6.7 16.17 8.01 14.99 7.22 10.81 7.93 9.66 8.84 8.84 10.05 8.25 14.13 9.44 15.43 8.25 16.17 6.7 16.27 4.93 12.75 2.54 12.44 1.23 12.5 0 12.94-1.27 16.67-3.32 16.75-5.08 16.17-6.7 14.99-8.01 10.81-7.22 9.66-7.93 8.84-8.84 8.25-10.05 9.44-14.13 8.25-15.43 6.7-16.17 4.93-16.27 2.54-12.75 1.23-12.44 0-12.5-1.27-12.94-3.32-16.67-5.08-16.75-6.7-16.17-8.01-14.99-7.22-10.81-7.93-9.66-8.84-8.84-10.05-8.25-14.13-9.44-15.43-8.25-16.17-6.7-16.27-4.93-12.75-2.54-12.44-1.23-12.5 0-12.94 1.27-16.67 3.32-16.75 5.08-16.17 6.7-14.99 8.01-10.81 7.22-9.66 7.93-8.84 8.84-8.25 10.05-9.44 14.13-8.25 15.43-6.7 16.17-4.93 16.27-2.54 12.75-1.23 12.44z"
/>
</g>
</g>
</g>
</svg>
You can use animateTransform to perform various rotations as in this short sample: http://jsfiddle.net/hmct2eof/
No javascript is needed. Only SVG:
<svg width="320" height="320" viewBox="-160 -160 320 320">
<circle fill="#0f0" stroke="#000" cx="0" cy="0" r="5"/>
<g>
<animateTransform attributeName="transform"
attributeType="XML"
type="rotate"
from="360"
to="0"
dur="7.33s"
repeatCount="indefinite"/>
<g transform="translate(0, 100)">
<path fill="orange" stroke="#000" d="M0-20L10,10L0,0L-10,10Z">
<animateTransform attributeName="transform"
attributeType="XML"
type="rotate"
from="0"
to="360"
dur="1s"
repeatCount="indefinite"/>
</path>
</g>
</g>
</svg>
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 !