How to morph a SVG diamond into a circle - html

I've recently been dipping my toe into SVGs and I'm currently trying to morph a diamond into a circle when the user hovers over it.
I found this tutorial over at CSS Tricks
I've noticed that they're using points to do the animation however my SVG shapes are:
<circle cx="49.873" cy="50.155" r="49.845"/>
and
<rect x="15.211" y="14.798" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -20.8426 50.3112)" width="70.198" height="71.034"/>
Is there a way to do this? How would I get the points of these shapes so I could follow the CSS Tricks tutorial?

For those interested:
<svg viewBox="0 0 300 300" width="500" height="500" style="border:1px solid red;"preserveAspectRatio="xMinYMax meet">
<rect id="shape2" rx="0" y="0" x="100" width="50" height="50" transform="rotate(45)">
<animate begin="shape2.mouseover" attributeName="rx" dur="700ms" to="50%" fill="freeze"/>
<animate begin="shape2.mouseout" attributeName="rx" dur="700ms" to="0" fill="freeze"/>
</rect>
</svg>
http://jsfiddle.net/4e71gra6/

Extending the first answer by user1788364:
With saving square value of shape:
https://jsfiddle.net/HoretskiyDima/xfat6oc2/13/
<svg viewBox="0 0 300 300" width="500" height="500" style="border:1px solid red;"preserveAspectRatio="xMinYMax meet">
<rect id="shape2" rx="0" y="0" x="100" width="50" height="50" transform="rotate(45)">
<!-- Making cirle from rectangle -->
<animate begin="shape2.mouseover" attributeName="rx" dur="2000ms" to="50%" fill="freeze"/>
<animate begin="shape2.mouseout" attributeName="rx" dur="325ms" to="0" fill="freeze"/>
<!-- In order to save square value, we need bigger radius then rectangle -->
<!-- S = width * height -->
<!-- S = PI * r^2 -->
<!-- d = r * 2 = sqrt(S/PI) * 2 = 56 -->
<animate begin="shape2.mouseover" attributeName="width" dur="375ms" to="56" fill="freeze"/>
<animate begin="shape2.mouseout;370ms" attributeName="width" dur="675ms" to="50" fill="freeze"/>
<animate begin="shape2.mouseover" attributeName="height" dur="375ms" to="56" fill="freeze"/>
<animate begin="shape2.mouseout;370ms" attributeName="height" dur="675ms" to="50" fill="freeze"/>
<!-- In order to pin shape center position on the screenm we need to move back on half of delta radius -->
<!-- (56 - 50) / 2 = 3 -->
<animate begin="shape2.mouseover" attributeName="x" dur="375ms" to="97" fill="freeze"/>
<animate begin="shape2.mouseout" attributeName="x" dur="675ms" to="100" fill="freeze"/>
<animate begin="shape2.mouseover" attributeName="y" dur="375ms" to="-3" fill="freeze"/>
<animate begin="shape2.mouseout" attributeName="y" dur="675ms" to="0" fill="freeze"/>
<!-- TODO: "rx" attribute animation timing working strange. -->
</rect>
</svg>

Related

Animate SVG paths clipped to an image

I'm trying to show parts of an image with a fade in animation. So this is what I've done:
I created an SVG with 2 paths (2 parts of the image that I want to show with a fade in animation)
I clipped the SVG to the image
The result is: the image has a mask and only those 2 parts are shown.
Everything's good but now I have to animate them and I cannot find enything that help me. Can you?
This is my code
<style>
img {
clip-path: url(#clip);
width: 100%;
}
</style>
<img src="https://wikitesti.com/wp-content/uploads/2020/11/yellow-is-the-color-of.jpg"/>
<svg xmlns="http://www.w3.org/2000/svg"
width="3.33333in" height="2.5in"
viewBox="0 0 1000 750">
<clipPath id="clip" clipPathUnits="objectBoundingBox" transform="scale(0.001, 0.0013333333333333)">
<path id="path" d="M 416.00,140.00
C 426.58,139.14 423.70,137.74 438.00,138.00
440.13,138.04 442.65,137.95 444.26,139.60
446.32,141.71 446.00,146.23 446.00,149.00
446.00,149.00 446.00,175.00 446.00,175.00
446.00,175.00 452.00,230.00 452.00,230.00
452.00,230.00 452.00,242.00 452.00,242.00
452.00,242.00 454.66,271.00 454.66,271.00
454.66,271.00 454.09,277.00 454.09,277.00
454.09,277.00 458.25,312.00 458.25,312.00
459.85,321.79 462.98,335.77 463.00,345.00
463.00,345.00 465.00,372.00 465.00,372.00
465.02,385.91 468.58,409.91 462.00,422.00
462.00,422.00 435.08,408.00 435.08,408.00
435.08,408.00 435.08,397.00 435.08,397.00
435.08,397.00 436.82,381.00 436.82,381.00
436.82,381.00 433.17,360.00 433.17,360.00
433.17,360.00 431.48,338.00 431.48,338.00
431.48,338.00 424.17,308.00 424.17,308.00
424.17,308.00 424.95,294.00 424.95,294.00
424.95,294.00 424.95,283.00 424.95,283.00
424.95,283.00 424.09,273.00 424.09,273.00
424.09,273.00 421.91,239.00 421.91,239.00
421.91,239.00 421.00,227.00 421.00,227.00
421.00,227.00 421.00,202.00 421.00,202.00
421.00,202.00 420.00,190.00 420.00,190.00
420.00,190.00 420.00,179.00 420.00,179.00
420.00,179.00 419.00,165.00 419.00,165.00
419.00,165.00 417.79,148.00 417.79,148.00
417.79,148.00 416.00,140.00 416.00,140.00 Z" fill="#C4C4C4"/>
<path class="fade-in three" id="path2" d="M 530.00,168.00
C 530.00,168.00 588.00,168.00 588.00,168.00
588.00,168.00 588.00,468.00 588.00,468.00
588.00,468.00 530.00,468.00 530.00,468.00
530.00,468.00 530.00,168.00 530.00,168.00 Z" fill="#C4C4C4" />
</clipPath>
</svg>
Thank you.
[EDIT]
I tried to do something like this:
<path....>
<animate attributeType="CSS" attributeName="opacity" from="1" to="0" dur="5s" repeatCount="indefinite" />
</path>
But it seems like if path is clipped opacity doesn't work
[EDIT]
I have to animate them with different duration and delay so I cannot just animate the image
[DESIRED RESULT]
This should be the final results. Same picture, different masks and different fade in effect time
SOLVED!!!
Solution is not clipping the path to the image but setting the image as path background and then animate the path.
Here is the code:
<svg xmlns="http://www.w3.org/2000/svg"
width="50%" height="50%"
viewBox="0 0 1000 750">
<defs>
<pattern id="img1" patternUnits="userSpaceOnUse" width="1000" height="750">
<image href="image_to_mask.jpg" x="0" y="0" width="1000" height="750" />
</pattern>
</defs>
<path id="path1" opacity="0" d="M 296.00,277.00
C 296.00,277.00 699.00,277.00 699.00,277.00
699.00,277.00 699.00,353.00 699.00,353.00
699.00,353.00 296.00,353.00 296.00,353.00
296.00,353.00 296.00,277.00 296.00,277.00 Z" fill="url(#img1)">
<animate attributeType="CSS" attributeName="opacity" from="0" to="1" dur="0.5s" fill="freeze"/>
</path>
<path id="path2" opacity="0" d="M 222.00,466.00
C 222.00,466.00 792.00,466.00 792.00,466.00
792.00,466.00 792.00,580.00 792.00,580.00
792.00,580.00 222.00,580.00 222.00,580.00
222.00,580.00 222.00,466.00 222.00,466.00 Z" fill="url(#img1)">
<animate attributeType="CSS" attributeName="opacity" from="0" to="1" dur="0.5s" begin="0.5s" fill="freeze"/>
</path>
</svg>

Capital letters in html attributs

I want to add animation on my chart.I'm using jquery(append) to add animation tag on my html page but the animation doesn't work.
The animation tag attributs such as attributename or repeatcount have one capital letter and if i add this with attr method or another the capital letter is ignored and the animation doesn't work.
<rect fill="#555" width="2" height="2" x="0" y="0">
<animate attributename="x" from="0" to="0" attributename="XML" dur="1.5s" repeatcount="indefinite"></animate>
<animate attributename="y" from="0" to="0" attributetype="XML" dur="1.5s" repeatcount="indefinite"></animate>
</rect>
That's because you're moving from 0 to 0. If you try to put the capital letters and tell the box to move (let's say from 0 to 2) you'll see something :)
<svg viewBox="0 0 10 10">
<rect fill="#555" width="2" height="2" x="0" y="0">
<animate attributeName="x" from="0" to="2" attributeName="XML" dur="1.5s" repeatCount="indefinite"></animate>
<animate attributeName="y" from="0" to="2" attributeType="XML" dur="1.5s" repeatCount="indefinite"></animate>
</rect>
</svg>

How do i animate a group of SVGs, rather than only animating one at a time?

I have a little svg drawing that I'd like to animate, it consists of several SVG elements. I'd like to be able to animate them together, as if they were the same thing.
So far I've grouped them together and put an individual animation at the end of each SVG, like this:
<g id="buildings">
<rect fill="#aad4ff" height="22" width="90" x="223.5" y="376.5">
<animate attributeType="XML" attributeName="y" from="376.5" to="373" begin="mouseover" end="mouseout" dur="500ms"/>
</rect>
<rect fill="#aad4ff" height="117" width="113" x="110.5" y="281.5">
<animate attributeType="XML" at . . .
</g>
as you can see the i have <rect ...> <animate .../> for each svg, this makes it complicated if my SVG is a drawing of a bird, consisting of a lot of different SVGs
My question is: How can I use animate when referring to a group of SVGs?
<g id="something">
<ellipse cx="46.78408" cy="425.59942" fill="#ff5656" rx="15" ry="16"/>
<ellipse cx="50" cy="437" fill="#ff5656" rx="25" ry="10"/>
<animate attributeType="XML" attributeName="cx" from="47" to="646" repeatCount="indefinite" dur="10s"/>
</g>
I want to use one animate line for all the SVG elements inside the group and this way of writing it does not seem to work.
PS - it is for a project and i am not allowed to use CSS, if this can be done within HTML that would be best.
You can only animate the attributes of the group. You don't give details of what you want to do exactly, but let's assume you want to move your bird across the screen from left to right, while the wings of the bird move in relation to its body.
That would mean you must define the wing movement for each individual wing, but the movement across the screen can be defined as an animation of the transform attribute of the group. There is even a specialised element for that:
<g id="something">
<animateTransform attributeType="XML" attributeName="transform" type="translate"
from="0" to="600" repeatCount="indefinite" dur="10s"/>
<ellipse cx="46.78408" cy="425.59942" fill="#ff5656" rx="15" ry="16"/>
<ellipse cx="50" cy="437" fill="#ff5656" rx="25" ry="10"/>
</g>
Thee syntax of <animateTransform> is a shortened form for "go from attribute transform="translate(0)" to transform="translate(600)". The translate() function has actually two parameters, the x and y relative movement. For example transform="translate(600 100)" would mean "go 600 to the right, and 100 down". In the animation element, only the numbers need to be listed, like this:
<animateTransform attributeType="XML" attributeName="transform" type="translate"
from="0 0" to="600 100" repeatCount="indefinite" dur="10s"/>
The animation interpolates over both numbers simultanuously, resulting in a diagonal movement in a straight line from origin to endpoint.
If you need to move several elements of a group together across the screen, then you need to replace the animation of one element with the animation of the entire group.
Use animation command to move:
<animateTransform xlink:href="#something" attributeName="transform" type="translate"
values="x1,y1;x2,y2" />
By combining the values of the horizontal and vertical coordinates, you can get:
Move a group of elements horizontally:
values="x1,y1;x2,y1"
<svg width="800" height="800" viewBox="800 800">
<g id="something" >
<ellipse id="el1" cx="46" cy="42" fill="#ff5656" rx="16" ry="16"/>
<ellipse id="el2"cx="46" cy="43" fill="#B53D3D" rx="25" ry="10"/>
</g>
<animateTransform xlink:href="#something" attributeName="transform" type="translate"
values="0,10;300,0;0,10" repeatCount="indefinite" dur="5s"/>
</svg>
Moving a group of elements vertically:
values="x1,y1;x1,y2"
<svg width="800" height="800" viewBox="800 800">
<g id="something" >
<ellipse id="el1" cx="46" cy="42" fill="#ff5656" rx="16" ry="16"/>
<ellipse id="el2"cx="46" cy="43" fill="#B53D3D" rx="25" ry="10"/>
</g>
<animateTransform xlink:href="#something" attributeName="transform" type="translate"
values="0,10;0,300;0,10" repeatCount="indefinite" dur="5s"/>
</svg>
Movement in all directions:
values="x1,y1;x2,y2;x3,y3"
<svg width="800" height="800" viewBox="800 800">
<g id="something" >
<ellipse id="el1" cx="46" cy="42" fill="#ff5656" rx="16" ry="16"/>
<ellipse id="el2"cx="46" cy="43" fill="#B53D3D" rx="25" ry="10"/>
</g>
<animateTransform xlink:href="#something" attributeName="transform" type="translate"
values="
0,10;
50,250;
100,150;
200,300;
100,400;
0,10"
repeatCount="indefinite"
dur="5s"/>
</svg>
You can also move raster or vector images with this command translate
<svg width="800" height="800" viewBox="800 800">
<image xlink:href="https://twemoji.maxcdn.com/svg/1f341.svg" width="25%" height="25%" >
<animateTransform attributeName="transform" type="translate"
values="
0,10;
150,350;
200,300;
350,150;
200,100;
100,400;
0,10"
repeatCount="indefinite"
dur="5s"/>
</image>
</svg>

Svg fill animation for the given path

I am trying to animate an arrow from left to right.The code of my arrow's path is given below:
<svg id="svg_circle" width="100%" height="100%" viewBox = '0 0 450 400'>
<g transform = "translate(0,0)">
<path class="path" stroke="#F0F0F0" fill="#fff" stroke-width="1" opacity="1" d="m34.97813,21.70979l-33.55223,0.47088l-0.0394,-13.57138l34.2665,-0.47295l-0.0208,-7.14282l14.50618,14.42226l-14.95643,15.04345l-0.20382,-8.74944z" id="svg_1">
<animate id="project_anim1" attributeName="fill" from="#fff" to="#4DAF4C" begin="1s" dur="1s" fill="freeze" repeatCount="1"></animate>
</path>
</g>
</svg>
The above is the svg path content of my arrow.
Kindly anyone help me how to fill the path from left to right. Waiting for quick response
You can do this by just animating the <stop>s in a <linear gradient>.
<svg id="svg_circle" width="100%" height="100%" viewBox = '0 0 450 400'>
<defs>
<linearGradient id="left-to-right">
<stop offset="0" stop-color="#4DAF4C">
<animate dur="2s" attributeName="offset" fill="freeze" from="0" to="1" />
</stop>
<stop offset="0" stop-color="#fff">
<animate dur="2s" attributeName="offset" fill="freeze" from="0" to="1" />
</stop>
</linearGradient>
</defs>
<path class="path" stroke="#F0F0F0" fill="url(#left-to-right)" stroke-width="1" opacity="1" d="m34.97813,21.70979l-33.55223,0.47088l-0.0394,-13.57138l34.2665,-0.47295l-0.0208,-7.14282l14.50618,14.42226l-14.95643,15.04345l-0.20382,-8.74944z" id="svg_1" />
</svg>
How this works is that we have a linear gradient representing an abrupt change from green to white. The <animation> elements move the position, of that abrupt change, from the left of the arrow (offset=0) to the right (offset="1").
Note that SVG <animate> elements will not work in IE. If you need to support IE, you will need to use the FakeSmile library or use a different method (such as a JS animation library).
Building upon andreas' answer. You can cover your arrow with a shape that is animated to uncover it.
<svg id="svg_circle" width="450" height="400" viewBox='0 0 450 400'>
<path class="path" stroke="#F0F0F0" fill="#fff"
stroke-width="1" opacity="1" id="svg_1"
d="m34.97813,21.70979l-33.55223,0.47088l-0.0394,
-13.57138l34.2665,-0.47295l-0.0208,-7.14282
l14.50618,14.42226l-14.95643,15.04345l-0.20382,
-8.74944z">
<animate id="project_anim1" attributeName="fill"
from="#fff" to="#4DAF4C" begin="0s" dur="3s"
fill="freeze" repeatCount="indefinite" />
</path>
<rect x="0" y="0" width="53" height="34" fill="#fff">
<animate attributeType="XML" attributeName="x"
from="0" to="53" begin="0s" dur="3s"
repeatCount="indefinite" />
<animate attributeType="XML" attributeName="width"
from="53" to="0" begin="0s" dur="3s"
repeatCount="indefinite" />
</rect>
</svg>
I don't think this is possible with the fill attribute. But instead, you can invert your SVG path to a rectangle with a triangle like hole. Now you just need a second element behind that path, where you can simply animate the scale in x-direction, to fill the hole from left to right.
Here is an image showing the technique:
An here is a working example:
<svg width="100%" height="100%" viewBox='0 0 450 400'>
<rect x="0" y="0" width="1" height="22" style="fill: black;" >
<animateTransform attributeName="transform" type="scale" from="1 1" to="50 1" begin="0s" dur="2s" repeatCount="indefinite" />
</rect>
<path fill="#ffffff" d="M0,0v29.8h86V0H0z M6.5,25V5.5L48.8,25H6.5z"/>
</svg>
Note: The answer was updated from triangle to arrow, I won't update my answer as the technique is the same for every shape.
<svg id="svg_circle" width="100%" height="100%" viewBox = '0 0 450 400'>
<defs>
<linearGradient id="left-to-right">
<stop offset="0" stop-color="#4DAF4C">
<animate dur="2s" attributeName="offset" fill="freeze" from="0" to="1" />
</stop>
<stop offset="0" stop-color="#fff">
<animate dur="2s" attributeName="offset" fill="freeze" from="0" to="1" />
</stop>
</linearGradient>
</defs>
<path class="path" stroke="#F0F0F0" fill="url(#left-to-right)" stroke-width="1" opacity="1" d="m34.97813,21.70979l-33.55223,0.47088l-0.0394,-13.57138l34.2665,-0.47295l-0.0208,-7.14282l14.50618,14.42226l-14.95643,15.04345l-0.20382,-8.74944z" id="svg_1" />
</svg>

how to keep text orientation unchanged during rotation in SVG

I am using <g transform = "rotate(45, 10, 30)"> in svg to roate som circles and texts around a point at the same time, however, I want to keep orientation of each individual font the same (e.g., always facing one direction while the text is moved/rotated).
For example,how could I change the labels such as "A" in the right-side image to correct orientation after rotation?
How should I do that?
Thanks!
Pure SVG
Rotate the entire group of elements: triangle, spiral and colored circles with the letters
<g id = "common"`>
....
</g>
<animateTransform xlink:href="#common"
attributeName="transform"
type="rotate"
begin="svg1.click"
restart="whenNotActive"
repeatCount="indefinite"
dur="10s"
values="
0, 75.74, 74.91;
-360, 75.74, 74.91"
additive="sum" />
Inside is the second animation of the rotation of circles and letters.
<animateTransform attributeName="transform" type="rotate" begin="svg1.click" restart="whenNotActive"
repeatCount="indefinite" dur="10s"
values="
0, 56.13, 106.87;
360, 56.13, 106.87"
additive="sum" />
We find the coordinates of the center of rotation of the letters using the getBBox () JS method
<script>
//Find the center of rotation of the letter A
let bb = a1.getBBox();
console.log(bb.x+bb.width/2);
console.log(bb.y+bb.height/2);
</script>
The animation will start after clicking
text {
font-family:sans-serif;
font-size:14px;
font-weight:bold;
fill:#6E6E6E;
}
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="190px" height="190px" viewBox="0 0 150 150" version="1.1">
<defs>
</defs>
<g id="common">
<g transform="translate(-27.970238,-63.089294)">
<circle cx="102.9" cy="138.0" r="75" fill="#faa"/>
<path d="m163.7 175.2-121.5 0 60.8-105.2z" fill="#fea"/>
<!-- Spiral -->
<path d="m101.3 136.5c1.1 2-2.1 2.5-3.3 1.9-3.2-1.7-2.6-6.2-0.5-8.4 3.7-4.1 10.2-2.9 13.6 0.9 5 5.6 3.3 14.3-2.3 18.8-7.4 6-18.4 3.7-23.9-3.6-7-9.2-4.1-22.5 5-29.1 11-8 26.6-4.4 34.3 6.4 9 12.8 4.8 30.7-7.8 39.4-14.6 10-34.8 5.2-44.6-9.2-11.1-16.4-5.6-39 10.6-49.7 18.2-12.1 43.1-6 54.9 11.9 13.1 19.9 6.4 47.2-13.3 60.1" style="fill:none;stroke-width:1;stroke:#6E6E6E">
</path>
<g id="La">
<circle cx="55.9" cy="108.0" r="12.9" fill="#efa"/>
<text id="a1" x="51" y="112">
A
</text>
<!-- Animation of the rotation of the letter `A` -->
<animateTransform attributeName="transform" type="rotate" begin="svg1.click" restart="whenNotActive" repeatCount="indefinite" dur="10s"
values="0, 56.13, 106.87;360, 56.13, 106.87" additive="sum" />
</g>
<g>
<circle cx="153.7" cy="110.3" r="12.9" fill="#efa"/>
<text id="b1" xml:space="preserve" x="114" y="116" >
B
</text>
<!-- Animation of the rotation of the letter `B` -->
<animateTransform attributeName="transform" type="rotate" begin="svg1.click" restart="whenNotActive" repeatCount="indefinite" dur="10s"
values="0, 153.7, 110.3;360, 153.7, 110.3" additive="sum" />
</g>
<g>
<circle cx="105.2" cy="192.5" r="12.9" fill="#efa" />
<text id="c1" x="100" y="198" >
C
</text>
<!-- Animation of the rotation of the letter `C` -->
<animateTransform attributeName="transform" type="rotate" begin="svg1.click" restart="whenNotActive" repeatCount="indefinite" dur="10s"
values="0, 104.93, 193.46;360, 104.93, 193.46" additive="sum" />
</g>
</g>
</g>
<!-- Animating the rotation of the entire shape -->
<animateTransform xlink:href="#common" attributeName="transform" type="rotate" begin="svg1.click" restart="whenNotActive" repeatCount="indefinite" dur="10s"
values="0, 75.74, 74.91;-360, 75.74, 74.91" additive="sum" />
</svg>
<script>
//Find the center of rotation of the letter A
let bb = a1.getBBox();
console.log(bb.x+bb.width/2);
console.log(bb.y+bb.height/2);
</script>
Example with adding animation of the ball movement in a spiral
text {
font-family:sans-serif;
font-size:14px;
font-weight:bold;
fill:#6E6E6E;
}
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="190px" height="190px" viewBox="0 0 150 150" version="1.1">
<defs>
</defs>
<g id="common">
<g transform="translate(-27.970238,-63.089294)">
<circle cx="102.9" cy="138.0" r="75" fill="#faa"/>
<path d="m163.7 175.2-121.5 0 60.8-105.2z" fill="#fea"/>
<path d="m163.7 175.2-121.5 0 60.8-105.2z" fill="#fea"/>
<!-- Spiral track (pink) -->
<path id="track" d="m101.3 136.5c1.1 2-2.1 2.5-3.3 1.9-3.2-1.7-2.6-6.2-0.5-8.4 3.7-4.1 10.2-2.9 13.6 0.9 5 5.6 3.3 14.3-2.3 18.8-7.4 6-18.4 3.7-23.9-3.6-7-9.2-4.1-22.5 5-29.1 11-8 26.6-4.4 34.3 6.4 9 12.8 4.8 30.7-7.8 39.4-14.6 10-34.8 5.2-44.6-9.2-11.1-16.4-5.6-39 10.6-49.7 18.2-12.1 43.1-6 54.9 11.9 13.1 19.9 6.4 47.2-13.3 60.1" style="fill:none;stroke-width:3;stroke:#FFAAAA"/>
<!-- Spiral -->
<path stroke-dasharray="0,432" d="m101.3 136.5c1.1 2-2.1 2.5-3.3 1.9-3.2-1.7-2.6-6.2-0.5-8.4 3.7-4.1 10.2-2.9 13.6 0.9 5 5.6 3.3 14.3-2.3 18.8-7.4 6-18.4 3.7-23.9-3.6-7-9.2-4.1-22.5 5-29.1 11-8 26.6-4.4 34.3 6.4 9 12.8 4.8 30.7-7.8 39.4-14.6 10-34.8 5.2-44.6-9.2-11.1-16.4-5.6-39 10.6-49.7 18.2-12.1 43.1-6 54.9 11.9 13.1 19.9 6.4 47.2-13.3 60.1" style="fill:none;stroke-width:2;stroke:#6E6E6E">
<!-- Spiral animation -->
<animate attributeName="stroke-dasharray" begin="svg1.click" repeatCount="indefinite" restart="whenNotActive" dur="10s" values="0,432;432,0;0,432" fill="freeze" />
</path>
<circle cx="0" cy="0" r="6" fill="#6E6E6E">
<!-- Ball movement in a spiral clockwise -->
<animateMotion id="forwards"
begin="svg1.click;back.end"
dur="5s" >
<mpath xlink:href="#track" />
</animateMotion>
<!-- Ball movement in a spiral counterclockwise -->
<animateMotion
id="back"
dur="5s"
begin="forwards.end"
repeatCount="1"
keyPoints="1;0"
keyTimes="0;1"
calcMode="linear"
rotate="auto"
fill="freeze" >
<mpath xlink:href="#track" />
</animateMotion>
</circle>
<g id="La">
<circle cx="55.9" cy="108.0" r="12.9" fill="#efa"/>
<text x="51" y="112"> A </text>
<animateTransform attributeName="transform" type="rotate" begin="svg1.click" restart="whenNotActive" repeatCount="indefinite" dur="10s"
values="0, 55.9, 108;360, 55.9, 108" additive="sum" />
</g>
<g>
<circle cx="153.7" cy="110.3" r="12.9" fill="#efa"/>
<text xml:space="preserve" x="114" y="116" >
B
</text>
<animateTransform attributeName="transform" type="rotate" begin="svg1.click" restart="whenNotActive" repeatCount="indefinite" dur="10s"
values="0, 153.7, 110.3;360, 153.7, 110.3" additive="sum" />
</g>
<g>
<circle cx="105.2" cy="192.5" r="12.9" fill="#efa" />
<text x="100" y="198" > C
</text>
<!-- Animation of the rotation of the letter `C` -->
<animateTransform attributeName="transform" type="rotate" begin="svg1.click" restart="whenNotActive" repeatCount="indefinite" dur="10s"
values="0, 105.2, 192.5;360, 105.2, 192.5" additive="sum" />
</g>
</g>
</g>
<!-- Animating the rotation of the entire shape -->
<animateTransform xlink:href="#common" attributeName="transform" type="rotate" begin="svg1.click" restart="whenNotActive" repeatCount="indefinite" dur="10s"
values="0, 75.38, 75;-360, 75.38, 75" additive="sum" />
</svg>
Instead of rotation of <g>roup and reverse rotation of the text within it, try this alternate grouping. Center the <g> around origin(0,0) with negative x= and y= values & use rotate(degree, 0, 0) on circle_group, then translate(x,y) on the main_group.
Edit: Here's an animated example, modified from this source. The trick is to move it around the origin with sin() and cos() trigonometric functions.
<!DOCTYPE html>
<html>
<head>
<title>JavaScript SVG Animation</title>
<meta http-equiv="X-UA-Compatible" content="IE=Edge"/> <!-- Remove this line in production. -->
</head>
<body>
<svg width="800px" height="800px" viewBox="0 0 800 800">
<g transform="translate(400, 400)"> <!-- Create a Cartesian coordinate system (with the y-axis flipped) for the animated square. That is, place the origin at the center of the 800 x 800 SVG viewport: -->
<!-- A 200 x 200 square with the upper left-hand corner at (-100, -100). This places the center of the square
at the origin (0, 0): -->
<rect id="mySquare" x="-100" y="-100" width="200" height="200" rx="5" ry="5"
style=" fill: yellow; stroke: yellow; stroke-width: 1; stroke-dasharray: 10, 5;" />
<!-- Represents the x-axis: -->
<line x1="-400" y1="0" x2="400" y2="0" style="stroke: blue;" />
<!-- Represents the y-axis (although up is negative and down is positive): -->
<line x1="0" y1="-400" x2="0" y2="400" style="stroke: blue;" />
<circle cx="0" cy="0" r="141" fill="none" stroke="yellow"/>
<g id="circle_a">
<circle cx="0" cy="0" r="10" fill="none" stroke="blue"/>
<text x="-5" y="5" width="20" height="20">A</text>
</g>
<g id="circle_b">
<circle cx="0" cy="0" r="10" fill="none" stroke="red"/>
<text x="-5" y="5" width="20" height="20">B</text>
</g>
</g>
</svg>
<script>
"use strict";
/* CONSTANTS */
var initialTheta = 0; // The initial rotation angle, in degrees.
var thetaDelta = 0.3; // The amount to rotate the square about every 16.7 milliseconds, in degrees.
var angularLimit = 180; // The maximum number of degrees to rotate the square.
var theSquare = document.getElementById("mySquare");
var circleA = document.getElementById("circle_a");
var circleB = document.getElementById("circle_b");
theSquare.currentTheta = initialTheta; // The initial rotation angle to use when the animation starts, stored in a custom property.
var requestAnimationFrameID = requestAnimationFrame(doAnim); // Start the loop.
function doAnim() {
if (theSquare.currentTheta > angularLimit) {
cancelAnimationFrame(requestAnimationFrameID); // The square has rotated enough, instruct the browser to stop calling the doAnim() function.
return; // No point in continuing, bail now.
}
theSquare.setAttribute("transform", "rotate(" + theSquare.currentTheta + ")"); // Rotate the square by a small amount.
circleA.setAttribute("transform", "translate(" +Math.cos((theSquare.currentTheta-45)*Math.PI/180)*141 + "," + Math.sin((theSquare.currentTheta-45)*Math.PI/180)*141+")"); // Move the circle A
circleB.setAttribute("transform", "translate(" +Math.cos((theSquare.currentTheta+45)*Math.PI/180)*141 + "," + Math.sin((theSquare.currentTheta+45)*Math.PI/180)*141+")"); // move the circle B
theSquare.currentTheta += thetaDelta; // Increase the angle that the square will be rotated to, by a small amount.
requestAnimationFrameID = requestAnimationFrame(doAnim); // Call the doAnim() function about 60 times per second (60 FPS), or about once every 16.7 milliseconds until cancelAnimationFrame() is called.
}
</script>