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>
Related
I'm able to make the pulse animation on the heart but on the second icon it's sliding, I don't understand why.
<svg>
<g transform="translate(50, 50)">
<path transform="translate(-50, -50)" d="M82.6,50L82.6,50c-0.2-8.1-6.9-15.2-15.1-15.2c-4.8,0-9,2.4-11.8,6c-2.8-3.6-7-6-11.8-6c-8.3,0-15,7.2-15.1,15.2h0c0,0,0,0.1,0,0.1c0,0,0,0.1,0,0.1c0,0.2,0.1,0.4,0.1,0.6c0.7,20.5,26.6,29,26.6,29s26.3-8.4,27.1-28.9c0-0.2,0.1-0.4,0.1-0.6c0,0,0-0.1,0-0.1C82.6,50.1,82.6,50.1,82.6,50z"/>
<animateTransform attributeType="XML" attributeName="transform" type="scale" values="1;1.5;1" additive="sum" begin="0s" dur="2s" repeatCount="indefinite"/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1042.816 1297.406">
<g transform="translate(50, 50)">
<path transform="translate(-50, -50)" d="M698.467,114.89a10.209,10.209,0,0,1-3.787-.817c-13.05-5.219-51.65-19.04-65.74-21.65s-23.48-4.96-19.83-14.09,7.57-24.78,7.57-24.78,5.57-30.79,7.61-34.44c1.618-2.894,3.594-3.82,7.465-3.82,1.01,0,2.149.062,3.445.17,6.26.52,26.61,3.65,25.3,8.87s-2.6,7.92,8.87,10.09,49.374,13.388,51.457,18.084c2.47,5.567-3.977,24.786-8.147,35.217-3.732,9.321-4.754,27.166-14.213,27.166M628.979,10.6c-6.16,0-8.353,2.8-10.209,12.954-2.76,15.01-13.91,53.56-14.82,56.671a3.161,3.161,0,0,1-.14.4c-4.27,10.521,1.78,12.86,22,16.231,20.35,3.389,57.3,17,63.09,18.889,3.735,1.222,8.923,4.074,13.182,4.074,2.924,0,5.41-1.343,6.688-5.484,3.13-10.17,12.78-39.649,16.95-52.17s-4.95-18.79-17.74-21.92c-11.46-2.8-29.64-7.5-39.67-11.45a4.522,4.522,0,0,1-2.87-4.26c.14-8.97-6.28-9.83-22.41-12.2-6.227-.916-10.719-1.734-14.051-1.734" fill="#4cb5e3"/>
<animateTransform attributeType="XML" attributeName="transform" type="scale" values="1;1.5;1" additive="sum" begin="0s" dur="2s" repeatCount="indefinite"/>
</g>
</svg>
You will need to use a different transform like so:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1042.816 1297.406">
<g transform="translate(664.6295, 65.2095)">
<path transform="translate(-664.6295, -65.2095)" d="M698.467,114.89a10.209,10.209,0,0,1-3.787-.817c-13.05-5.219-51.65-19.04-65.74-21.65s-23.48-4.96-19.83-14.09,7.57-24.78,7.57-24.78,5.57-30.79,7.61-34.44c1.618-2.894,3.594-3.82,7.465-3.82,1.01,0,2.149.062,3.445.17,6.26.52,26.61,3.65,25.3,8.87s-2.6,7.92,8.87,10.09,49.374,13.388,51.457,18.084c2.47,5.567-3.977,24.786-8.147,35.217-3.732,9.321-4.754,27.166-14.213,27.166M628.979,10.6c-6.16,0-8.353,2.8-10.209,12.954-2.76,15.01-13.91,53.56-14.82,56.671a3.161,3.161,0,0,1-.14.4c-4.27,10.521,1.78,12.86,22,16.231,20.35,3.389,57.3,17,63.09,18.889,3.735,1.222,8.923,4.074,13.182,4.074,2.924,0,5.41-1.343,6.688-5.484,3.13-10.17,12.78-39.649,16.95-52.17s-4.95-18.79-17.74-21.92c-11.46-2.8-29.64-7.5-39.67-11.45a4.522,4.522,0,0,1-2.87-4.26c.14-8.97-6.28-9.83-22.41-12.2-6.227-.916-10.719-1.734-14.051-1.734" fill="#4cb5e3"/>
<animateTransform attributeType="XML" attributeName="transform" type="scale" values="1;1.5;1" additive="sum" begin="0s" dur="2s" repeatCount="indefinite"/>
</g>
</svg>
In order to get the new transformation I'm using getBBox() for the path. This is returning in this case SVGRect {x: 602.5171508789062, y: 10.600000381469727, width: 124.22491455078125, height: 109.21900939941406}
In order to get the transformation for the path:
x = 602.5171508789062 + 124.22491455078125/2
y = 10.600000381469727 + 109.21900939941406/2
I have a repeating 20-second svg animation. Halfway (10 seconds) it should abruptly hide one path-element called leftside. When the animation finishes and repeats, it should show the element again. How can I achieve this?
Right now, I got the first loop working. But the reset when the animation repeats isn't working unfortunately.
This is what I have:
<svg class="svg-object" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1923 643" preserveAspectRatio="xMinYMin meet">
<path id="motionPath" fill="none" stroke="#000000" stroke-miterlimit="10"
d="M1438.8,348.8c6.2,189.4-75.3,34.5-157.8,28.3c-515.1,38.8-757.8,54.5-849.3,72.8
c-17.9,10.9-13.4,91.9-14.9,155.8"
/>
<g id="vehicle">
<path id="rightside" d="M13,2c-0.6,0-1-0.4-1-1s0.4-1,1-1s8,0.4,8,1S13.6,2,13,2z"/>
<path id="leftside" d="M8,2C7.4,2,0,1.6,0,1s7.4-1,8-1s1,0.4,1,1S8.6,2,8,2z"/>
</g>
<animateMotion id="movement"
xlink:href="#vehicle"
dur="20s"
begin="0;movement.end+4s"
fill="freeze"
keyPoints="0;1;0"
keyTimes="0;0.5;1"
calcMode="spline"
keySplines= ".6 .01 .2 1; 0.6 .01 .2 1";
>
<mpath xlink:href="#motionPath" />
</animateMotion>
<animate xlink:href="#leftside" attributeName="opacity" from="1" to="0" dur="0.01s" begin="10s;movement.begin+10s;" repeatCount="indefinitive" fill="freeze" />
<animate xlink:href="#leftside" attributeName="opacity" from="0" to="1" dur="0.01s" begin="movement.begin" repeatCount="indefinitive" fill="freeze" />
</svg>
Mybe so?
<svg class="svg-object" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1923 643" preserveAspectRatio="xMinYMin meet">
<path id="motionPath" fill="none" stroke="#000000" stroke-miterlimit="10"
d="M1438.8,348.8c6.2,189.4-75.3,34.5-157.8,28.3c-515.1,38.8-757.8,54.5-849.3,72.8
c-17.9,10.9-13.4,91.9-14.9,155.8"
/>
<g id="vehicle" stroke-width="2" stroke="red">
<path id="rightside" d="M13,2c-0.6,0-1-0.4-1-1s0.4-1,1-1s8,0.4,8,1S13.6,2,13,2z"/>
<path id="leftside" d="M8,2C7.4,2,0,1.6,0,1s7.4-1,8-1s1,0.4,1,1S8.6,2,8,2z"/>
</g>
<!-- Two dash move forward 10s -->
<animateMotion id="movement_forward"
xlink:href="#vehicle"
dur="10s"
begin="0;movement_back.end"
keyPoints="0;1"
keyTimes="0;1"
calcMode="linear"
>
<mpath xlink:href="#motionPath" />
</animateMotion>
<!-- One dash goes back 10 seconds -->
<animateMotion id="movement_back"
xlink:href="#rightside"
dur="10s"
begin="movement_forward.end"
keyPoints="1;0"
keyTimes="0;1"
calcMode="linear"
>
<mpath xlink:href="#motionPath" />
</animateMotion>
</svg>
begin="0;movement_back.end" - the restart of the first animation starts after the end of the second animation
begin="movement_forward.end - thus, two animations loop. When the first animation ends, the second animation begins
For uneven movement on different sections of the path, you need to change the attribute values:
keyPoints="0;0.2;0.4;0.8;1"
keyTimes="0;0.495;0.6;0.75;1"
<svg class="svg-object" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1923 643" preserveAspectRatio="xMinYMin meet">
<path id="motionPath" fill="none" stroke="#000000" stroke-miterlimit="10"
d="M1438.8,348.8c6.2,189.4-75.3,34.5-157.8,28.3c-515.1,38.8-757.8,54.5-849.3,72.8
c-17.9,10.9-13.4,91.9-14.9,155.8"
/>
<g id="vehicle" stroke-width="2" stroke="red">
<path id="rightside" d="M13,2c-0.6,0-1-0.4-1-1s0.4-1,1-1s8,0.4,8,1S13.6,2,13,2z"/>
<path id="leftside" d="M8,2C7.4,2,0,1.6,0,1s7.4-1,8-1s1,0.4,1,1S8.6,2,8,2z"/>
</g>
<!-- Two dash move forward 10s -->
<animateMotion id="movement_forward"
xlink:href="#vehicle"
dur="10s"
begin="0;movement_back.end"
keyPoints="0;0.2;0.4;0.8;1"
keyTimes="0;0.495;0.6;0.75;1"
calcMode="linear"
>
<mpath xlink:href="#motionPath" />
</animateMotion>
<!-- One dash goes back 10 seconds -->
<animateMotion id="movement_back"
xlink:href="#rightside"
dur="10s"
begin="movement_forward.end"
keyPoints="1;0.8;0.4;0.2;0"
keyTimes="0;0.495;0.6;0.75;1"
calcMode="linear"
>
<mpath xlink:href="#motionPath" />
</animateMotion>
</svg>
This is hard to follow for me, but I got this solution:
<svg class="svg-object" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1923 643" preserveAspectRatio="xMinYMin meet">
<path id="motionPath" fill="none" stroke="#000000" stroke-miterlimit="10"
d="M1438.8,348.8c6.2,189.4-75.3,34.5-157.8,28.3c-515.1,38.8-757.8,54.5-849.3,72.8
c-17.9,10.9-13.4,91.9-14.9,155.8"
/>
<g id="vehicle">
<path id="rightside" d="M13,2c-0.6,0-1-0.4-1-1s0.4-1,1-1s8,0.4,8,1S13.6,2,13,2z"/>
<path id="leftside" d="M8,2C7.4,2,0,1.6,0,1s7.4-1,8-1s1,0.4,1,1S8.6,2,8,2z"/>
</g>
<animateMotion id="movement"
xlink:href="#vehicle"
dur="20s"
begin="0;movement.end+4s"
fill="freeze"
keyPoints="0;1;0"
keyTimes="0;0.5;1"
calcMode="spline"
keySplines= ".6 .01 .2 1; 0.6 .01 .2 1";
>
<mpath xlink:href="#motionPath" />
</animateMotion>
<animate xlink:href="#leftside" attributeName="opacity" from="1" to="0" dur="0.01s" begin="movement.begin+10s; 20s" fill="freeze" />
<animate xlink:href="#leftside" attributeName="opacity" from="0" to="1" dur="0.01s" begin="movement.begin" fill="freeze" />
</svg>
A couple of points:
If you want to repeat the animation, the keyword is indefinite, not indefinitive.
You apparently wanted to set the leftside animation to indefinite. This would apply to the opacity animation itself, with a 0.01s duration. This means that, after being triggered, the animation would be repeating itself every 0.01s in a blinking pattern.
I believe the issue here is related to the interplay between both leftside animations, and which one has the preference at each time. However, it looks like a complex issue, and I do not understand it fully (explained here).
I made this Avatar image with SVG and added animation to it, the circle clips the man path but at page load it shows the path then it jumps to animation. How do I keep it so that it would not show the path until animation begins
<svg xmlns="http://www.w3.org/2000/svg" version="1" viewBox="25 70 160 160">
<defs>
<clipPath id="a">
<circle cx="105" cy="149" r="69"></circle>
</clipPath>
</defs>
<circle cx="105" cy="149" r="69" fill="#999" stroke="#848080" stroke-linecap="square" stroke-linejoin="round" stroke-width="3"></circle>
<g clip-path="url(#a)">
<g>
<defs>
<clipPath id="b">
<ellipse cx="105" cy="149" rx="68" ry="68"></ellipse>
</clipPath>
</defs>
<path fill="#ccc" stroke="#e3e3e3" clip-path="url(#b)" stroke-linecap="square" stroke-linejoin="round" stroke-width="3" d="M137 137c0 18-14 32-31 32s-31-14-31-32 14-32 31-32 31 14 31 32zm-70 36c-13 0-17 12-17 24 0 13 4 21 17 21h76c13 0 17-9 17-21 0-13-4-24-17-24h-17a26 26 0 0 1-43 0z"></path>
<animateTransform attributeName="transform" type="translate" from="0 120" to="0 0" begin="0s" dur="1.5s"></animateTransform>
<animate attributeName="opacity" attributeType="XML" from="0" to="1" begin="0s" dur="1s"></animate>
</g>
</g>
</svg>
Set the opacity of the object to 0 at the start in markup and then move the animations so they are children of the element itself rather than animating the parent <g> element. That way the animation has sufficient specificity to override the element's properties.
<svg xmlns="http://www.w3.org/2000/svg" version="1" viewBox="25 70 160 160">
<defs>
<clipPath id="a">
<circle cx="105" cy="149" r="69"></circle>
</clipPath>
</defs>
<circle cx="105" cy="149" r="69" fill="#999" stroke="#848080" stroke-linecap="square" stroke-linejoin="round" stroke-width="3"></circle>
<g clip-path="url(#a)">
<g>
<defs>
<clipPath id="b">
<ellipse cx="105" cy="149" rx="68" ry="68"></ellipse>
</clipPath>
</defs>
<path fill="#ccc" stroke="#e3e3e3" clip-path="url(#b)" stroke-linecap="square" stroke-linejoin="round" stroke-width="3" d="M137 137c0 18-14 32-31 32s-31-14-31-32 14-32 31-32 31 14 31 32zm-70 36c-13 0-17 12-17 24 0 13 4 21 17 21h76c13 0 17-9 17-21 0-13-4-24-17-24h-17a26 26 0 0 1-43 0z" opacity="0">
<animateTransform attributeName="transform" type="translate" from="0 120" to="0 0" begin="0s" dur="1.5s"></animateTransform>
<animate attributeName="opacity" from="0" to="1" begin="0s" dur="1s" fill="freeze"></animate>
</path>
</g>
</g>
</svg>
I am trying to make a SVG group follow a SVG path and transform animate the group. I am trying to make #moon transform with animateTransform but nothing seems to work.
Can anyone spot the problem?
<svg width="100%" height="100%" viewBox="0 0 570 594" preserveAspectRatio="true" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="padding: 0 10px 0 18px;fill-rule:evenodd;clip-rule:evenodd;stroke-miterlimit:10;">
<path id="orbit" d="M146.719,183.637l-18.408,-7.796l-13.233,-6.252l-12.327,-6.302l-18.44,-9.379l-12.42,-11.695l-16.36,-10.421l-15.546,-10.511l-12.326,-12.281l-14.415,-14.728l-8.426,-16.45l-4.168,-14.276l2.084,-14.272l6.297,-11.239l8.019,-10.103l12.013,-6.302l16.682,-8.426l16.356,-4.169l22.804,-4.217l27.474,-4.168l22.03,0l21.75,1.042l24.881,1.042l20.524,1.042l26.875,3.126l27.917,5.211l41.477,9.293l37.047,10.702l41.159,12.782l35.33,14.012l19.808,8.426l25.874,12.554l18.86,11.423l18.578,11.556l18.815,14.105l17.777,16.951l12.233,16.718l8.345,17.187l1.091,27.64l-7.434,8.207l-11.194,10.466l-15.595,10.559l-24.221,7.844l-22.609,5.211l-30.925,3.265l-43.658,0l-32.546,-2.085" style="fill:none;stroke-width:0px;stroke:#ff6060;"/>
<g id="moon" style="transform: translateY(-130px) translateX(-53px);">
<path d="M77.39,295.34c0,-10.683 -8.658,-19.343 -19.342,-19.343c-10.683,0 -19.344,8.66 -19.344,19.343c0,10.683 8.661,19.343 19.344,19.343c10.684,0 19.342,-8.66 19.342,-19.343" style="fill:#fff;fill-rule:nonzero;"/>
<path d="M61.54,304.476c0,-2.967 -2.404,-5.373 -5.371,-5.373c-2.969,0 -5.373,2.406 -5.373,5.373c0,2.967 2.404,5.373 5.373,5.373c2.967,0 5.371,-2.406 5.371,-5.373" style="fill:#878787;fill-opacity:0.199997;fill-rule:nonzero;"/>
<animateMotion dur="6s" repeatCount="indefinite">
<mpath xlink:href="#orbit" />
</animateMotion>
<animateTransform attributeName="transform"
attributeType="XML"
type="rotate"
from="0 60 70"
to="360 60 70"
dur="10s"
repeatCount="indefinite"/>
</g>
</svg>
You're mixing a CSS transform with the SMIL animation of a transform attribute. Although SVG 2 suggests they should be the same thing, SVG 1.1 has them as different things. Until the SVG 2 specification and UAs implementation of SVG 2 gets closer to completion it's best not to mix these things.
I've converted the g element's transform to an attribute transform and the animations certainly seem to do something for me now on Firefox.
<svg width="100%" height="100%" viewBox="0 0 570 594" preserveAspectRatio="true" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="padding: 0 10px 0 18px;fill-rule:evenodd;clip-rule:evenodd;stroke-miterlimit:10;">
<path id="orbit" d="M146.719,183.637l-18.408,-7.796l-13.233,-6.252l-12.327,-6.302l-18.44,-9.379l-12.42,-11.695l-16.36,-10.421l-15.546,-10.511l-12.326,-12.281l-14.415,-14.728l-8.426,-16.45l-4.168,-14.276l2.084,-14.272l6.297,-11.239l8.019,-10.103l12.013,-6.302l16.682,-8.426l16.356,-4.169l22.804,-4.217l27.474,-4.168l22.03,0l21.75,1.042l24.881,1.042l20.524,1.042l26.875,3.126l27.917,5.211l41.477,9.293l37.047,10.702l41.159,12.782l35.33,14.012l19.808,8.426l25.874,12.554l18.86,11.423l18.578,11.556l18.815,14.105l17.777,16.951l12.233,16.718l8.345,17.187l1.091,27.64l-7.434,8.207l-11.194,10.466l-15.595,10.559l-24.221,7.844l-22.609,5.211l-30.925,3.265l-43.658,0l-32.546,-2.085" style="fill:none;stroke-width:0px;stroke:#ff6060;"/>
<g id="moon" transform="translate(-53, -130)">
<path d="M77.39,295.34c0,-10.683 -8.658,-19.343 -19.342,-19.343c-10.683,0 -19.344,8.66 -19.344,19.343c0,10.683 8.661,19.343 19.344,19.343c10.684,0 19.342,-8.66 19.342,-19.343" style="fill:#fff;fill-rule:nonzero;"/>
<path d="M61.54,304.476c0,-2.967 -2.404,-5.373 -5.371,-5.373c-2.969,0 -5.373,2.406 -5.373,5.373c0,2.967 2.404,5.373 5.373,5.373c2.967,0 5.371,-2.406 5.371,-5.373" style="fill:#878787;fill-opacity:0.199997;fill-rule:nonzero;"/>
<animateMotion dur="6s" repeatCount="indefinite">
<mpath xlink:href="#orbit" />
</animateMotion>
<animateTransform attributeName="transform"
attributeType="XML"
type="rotate"
from="0 60 70"
to="360 60 70"
dur="10s"
repeatCount="indefinite"/>
</g>
</svg>
Easy !
AnimateTransform tag has to be within
AnimateMotion tag, completely enclosed, not following.
Precessing Orbit:
<?xml version="1.0"?>
<svg width="940" height="360" viewBox="0 0 350 350"
xmlns="http://www.w3.org/2000/svg" version="1.1"
xmlns:xlink="http://www.w3.org/1999/xlink" >
<!-- Here is a red circle which will be moved along the motion path. -->
<g>
<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="470" cy="180" r="160" fill="paleblue" />
<circle cx="10" cy="110" r="3" fill="lightgrey" />
<circle cx="110" cy="10" r="3" fill="lightgrey" />
<circle cx="" cy="" r="10" fill="red">
<!-- Define the motion path animation -->
<animateMotion dur="6s" repeatCount="indefinite">
<animateTransform attributeName="transform"
attributeType="XML"
type="rotate"
from="0 440 190"
to="360 440 190"
dur="6s"
repeatCount="indefinite"/>
<mpath xlink:href="#theMotionPath"/>
</animateMotion>
</circle>
<animateTransform attributeName="transform"
attributeType="XML"
type="rotate"
from="0 60 70"
to="360 60 70"
dur="10s"
repeatCount="indefinite"/>
</g>
</svg>
Copy, paste, edit to your liking.
<!DOCTYPE html>
<div width="100%">
<svg style="background:plum" width="240px" height="120px"
xmlns="http://www.w3.org/2000/svg" version="1.1"
xmlns:xlink="http://www.w3.org/1999/xlink" >
<polygon points="60,30 90,90 30,90">
<animateTransform attributeName="transform"
attributeType="XML"
type="rotate"
from="0 60 70"
to="360 60 70"
dur="10s"
repeatCount="indefinite"/>
</polygon>
</svg>
</div>
I'm trying to animate scale transformation around the object's center using SMIL, it works in Firefox 38, but not in Chrome 43, in Chrome the CSS transform-origin property seems ignored for some reason
Original
document.querySelector("#trigger").addEventListener("click", function(e){
if (e.ctrlKey)
document.querySelector("#triggerScaleOut").beginElement();
else
document.querySelector("#triggerScaleIn").beginElement();
}, false);
<svg version="1.1" width="512" height="512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="triggerContainer" transform="scale(1)" style="transform-origin: 150px 150px 0;">
<circle id="trigger" cx="150" cy="150" r="25" />
<animateTransform id="triggerScaleIn" begin="indefinite" values="1; 2" dur="0.5s"
type="scale"
attributeName="transform"
fill="freeze"/>
<animateTransform id="triggerScaleOut" begin="indefinite" values="2; 1" dur="0.5s"
type="scale"
attributeName="transform"
fill="freeze"/>
</g>
</svg>
I need this method to work in Chrome since its the cleanest/easiest.
I have tried other things that work like this:
Trial#1
document.querySelector("#trigger").addEventListener("click", function(e){
if ( e.ctrlKey )
document.querySelector("#triggerScaleOut").beginElement();
else
document.querySelector("#triggerScaleIn").beginElement();
}, false);
<svg version="1.1" width="512" height="512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="triggerContainerFix" transform="translate(150,150)">
<g id="triggerContainer" transform="scale(1)">
<circle id="trigger" cx="150" cy="150" r="25" transform="translate(-150,-150)"/>
<animateTransform id="triggerScaleIn" begin="indefinite" values="1; 2" dur="0.5s"
type="scale"
attributeName="transform"
fill="freeze"/>
<animateTransform id="triggerScaleOut" begin="indefinite" values="2; 1" dur="0.5s"
type="scale"
attributeName="transform"
fill="freeze"/>
</g>
</g>
</svg>
But it's a bit hacky, and i don't prefer it.
I also tried additive animations, but it is problematic (probably my fault)
Trial#2
document.querySelector("#trigger").addEventListener("click", function(e){
if (e.ctrlKey){
document.querySelector("#triggerScaleOut").beginElement();
document.querySelector("#triggerTranslateOut").beginElement();
}
else{
document.querySelector("#triggerScaleIn").beginElement();
document.querySelector("#triggerTranslateIn").beginElement();
}
}, false);
<svg version="1.1" width="512" height="512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="triggerContainer" transform="scale(1)">
<circle id="trigger" class="button" cx="150" cy="150" r="25" />
<animateTransform id="triggerTranslateIn" begin="indefinite" values="0,0; -150,-150" dur="0.5s"
type="translate"
attributeName="transform"
fill="freeze"
additive="sum"/>
<animateTransform id="triggerScaleIn" begin="indefinite" values="1; 2" dur="0.5s"
type="scale"
attributeName="transform"
fill="freeze"
additive="sum"/>
<animateTransform id="triggerTranslateOut" begin="indefinite" values="-150,-150; 0,0" dur="0.5s"
type="translate"
attributeName="transform"
fill="freeze"
additive="sum"/>
<animateTransform id="triggerScaleOut" begin="indefinite" values="2; 1" dur="0.5s"
type="scale"
attributeName="transform"
fill="freeze"
additive="sum"/>
</g>
</svg>
Any ideas? Thanks.
As you have discovered transform-origin has only recently become supported in browsers. So you probably shouldn't try to rely on it just yet.
Both of your "Trial" approaches are commonly used. IMO, the simplest approach is your "Trial #1" version. It's what I most commonly use. The idea is to apply the animation in a coordinate space where the element being scaled sits at the origin.
Here's a slightly simplified version of your sample.
document.querySelector("#trigger").addEventListener("click", function(e){
if ( e.ctrlKey )
document.querySelector("#triggerScaleOut").beginElement();
else
document.querySelector("#triggerScaleIn").beginElement();
}, false);
<svg version="1.1" width="512" height="512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="triggerContainer" transform="translate(150,150)">
<circle id="trigger" cx="0" cy="0" r="25">
<animateTransform id="triggerScaleIn" begin="indefinite" values="1; 2" dur="0.5s"
type="scale"
attributeName="transform"
fill="freeze"/>
<animateTransform id="triggerScaleOut" begin="indefinite" values="2; 1" dur="0.5s"
type="scale"
attributeName="transform"
fill="freeze"/>
</circle>
</g>
</svg>
I don't consider it hacky at all.