How to animated SVG to draw the lines instead of outlines? - css
I am trying to animate an SVG file to look like the gif below as much as possible, i'm getting pretty close i think but i'm stuck on an issue where i don't know why the outlines are drawed then the entire thing is filled. I would like the entire lines to be animated as shown in the gif.
Do anyone know what i could change in my CSS or if i there is something in the SVG that i need to modify to make this possible, i'm quite new to animating SVGs.
Current Animation
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1244.41 201.57">
<defs>
<style>
.cls-1 {
fill:#f59e00;
}
.cls-2 {
fill:#7a1331;
}
#Dots circle {
fill:#1e9a64;
}
#Lines path {
animation: draw 3s linear forwards;
animation-delay: 1.2s;
}
#Years_Text {
animation: 1s ease-out 0s 1 slideInFromRight;
}
.line-1 {
stroke-dasharray: 2150;
stroke-dashoffset: 2150;
}
.line-2 {
stroke-dasharray: 1600;
stroke-dashoffset: 1600;
}
.line-3 {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
}
.line-4 {
stroke-dasharray: 650;
stroke-dashoffset: 650;
}
.line-5 {
stroke-dasharray: 1600;
stroke-dashoffset: 1600;
}
.line-6 {
stroke-dasharray: 1300;
stroke-dashoffset: 1300;
}
#keyframes draw {
to {
stroke-dashoffset: 0;
fill: #1e9a64;
}
}
.dot-1 {
animation: 1s ease-out 0s 1 slideInFromLeft;
}
.dot-2 {
animation: 1s ease-out 0s 1 slideInFromCenterToLeft;
}
.dot-3 {
animation: 1s ease-out 0s 1 slideInFromCenterToLeft;
}
.dot-4 {
animation: 1s ease-out 0s 1 slideInFromCenterToLeft;
}
.dot-5 {
animation: 1s ease-out 0s 1 slideInFromLeft;
}
.dot-6 {
animation: 1s ease-out 0s 1 slideInFromLeft;
}
.dot-7 {
animation: 1s ease-out 0s 1 slideInFromCenterToRight;
}
.dot-8 {
animation: 1s ease-out 0s 1 slideInFromCenterToRight;
}
.dot-9 {
animation: 1s ease-out 0s 1 slideInFromTop;
}
.dot-10 {
animation: 1s ease-out 0s 1 slideInFromLeft;
}
.dot-11 {
animation: 1s ease-out 0s 1 slideInFromRight;
}
.dot-12 {
animation: 1s ease-out 0s 1 slideInFromRight;
}
#keyframes slideInFromLeft {
0% {
transform: translate(-20%, -20%);
}
100% {
transform: translate(0, 0);
}
}
#keyframes slideInFromRight {
0% {
transform: translate(+20%, +20%);
}
100% {
transform: translate(0, 0);
}
}
#keyframes slideInFromCenterToRight {
0% {
transform: translate(-5%, +50%);
}
100% {
transform: translate(0, 0);
}
}
#keyframes slideInFromCenterToLeft {
0% {
transform: translate(+15%, +30%);
}
100% {
transform: translate(0, 0);
}
}
#keyframes slideInFromTop {
0% {
transform: translate(-5%, -5%);
}
100% {
transform: translate(0, 0);
}
}
</style>
</defs>
<g id="Lines">
<path class="line-1" fill="none" stroke="#1e9a64" stroke-width="2" d="M1155.49,188.09h-69.85A3.74,3.74,0,0,1,1083,187l-20.2-20.19a3.73,3.73,0,0,1-1.09-2.64v-137a3.73,3.73,0,0,1,1.09-2.64L1083,4.35a3.74,3.74,0,0,1,2.64-1.1h24.21a3.74,3.74,0,0,1,0,7.47h-22.67l-18,18V162.61l18,18h66.76l18-18V28.73l-18-18h-23.45a3.74,3.74,0,1,1,0-7.47h25a3.74,3.74,0,0,1,2.64,1.1l20.2,20.19a3.73,3.73,0,0,1,1.09,2.64v137a3.73,3.73,0,0,1-1.09,2.64L1158.13,187A3.74,3.74,0,0,1,1155.49,188.09Z" />
<path class="line-2" fill="none" stroke="#1e9a64" stroke-width="2" d="M1145.2,169.43h-14.71a3.74,3.74,0,1,1,0-7.47h13.11l9.7-10.21V39.25l-9.67-9.87H1098.2l-10.37,9.93V151.68l10.4,10.28h11.62a3.74,3.74,0,0,1,0,7.47H1096.7a3.73,3.73,0,0,1-2.62-1.08l-12.6-12.46a3.71,3.71,0,0,1-1.11-2.65V37.72a3.69,3.69,0,0,1,1.15-2.69L1094.12,23a3.71,3.71,0,0,1,2.58-1h48.5a3.79,3.79,0,0,1,2.67,1.12l11.82,12.08a3.72,3.72,0,0,1,1.07,2.61V153.24a3.72,3.72,0,0,1-1,2.57l-11.82,12.45A3.73,3.73,0,0,1,1145.2,169.43Z" />
<path class="line-3" fill="none" stroke="#1e9a64" stroke-width="2" d="M1131.61,150.77h-23.15a3.76,3.76,0,0,1-2.6-1.05l-5.69-5.51a3.71,3.71,0,0,1-1.14-2.68V106a3.73,3.73,0,1,1,7.46,0v34l3.48,3.36h20.31l4.36-3.55V52.26L1130.13,48h-20l-3.63,4V85.35a3.73,3.73,0,0,1-7.46,0V50.64a3.73,3.73,0,0,1,1-2.49l5.7-6.34a3.74,3.74,0,0,1,2.78-1.24h23.15a3.73,3.73,0,0,1,2.55,1l6.76,6.34a3.75,3.75,0,0,1,1.18,2.72v90.89a3.74,3.74,0,0,1-1.38,2.89l-6.76,5.51A3.73,3.73,0,0,1,1131.61,150.77Z" />
<path class="line-4" fill="none" stroke="#1e9a64" stroke-width="2" d="M974.43,150.77H938a3.74,3.74,0,0,1,0-7.47H970.7v-84l-11.33,5.72A3.73,3.73,0,0,1,956,58.41L972.75,50a3.72,3.72,0,0,1,5.41,3.33V147A3.73,3.73,0,0,1,974.43,150.77Z" />
<path class="line-5" fill="none" stroke="#1e9a64" stroke-width="2" d="M1048.22,188.09H938a3.73,3.73,0,0,1-3.73-3.74V165.69A3.73,3.73,0,0,1,938,162h51.39V29.38h-6.5L949.75,46.73a3.73,3.73,0,1,1-3.46-6.61l33.92-17.78a3.72,3.72,0,0,1,1.73-.43h11.15a3.73,3.73,0,0,1,3.73,3.73V165.69a3.73,3.73,0,0,1-3.73,3.74H941.7v11.19h106.52a3.74,3.74,0,0,1,0,7.47Z" />
<path class="line-6" fill="none" stroke="#1e9a64" stroke-width="2" d="M1048.22,169.43h-36.47a3.74,3.74,0,0,1,0-7.47h32.73V150.77h-32.73A3.73,3.73,0,0,1,1008,147V10.72H975.33L940.84,28.36a3.73,3.73,0,1,1-3.4-6.64L972.73,3.66a3.74,3.74,0,0,1,1.7-.41h37.32A3.73,3.73,0,0,1,1015.48,7V143.3h32.74A3.73,3.73,0,0,1,1052,147v18.66A3.73,3.73,0,0,1,1048.22,169.43Z" />
</g>
<g id="Dots">
<circle class="dot-1" cx="941.03" cy="147.03" r="6.98" />
<circle class="dot-2" cx="941.23" cy="23.59" r="6.98" />
<circle class="dot-3" cx="958.83" cy="61.32" r="6.98" />
<circle class="dot-4" cx="949.22" cy="42.96" r="6.98" />
<circle class="dot-5" cx="1014.77" cy="165.69" r="6.98" />
<circle class="dot-6" cx="1045.08" cy="184.35" r="6.98" />
<circle class="dot-7" cx="1109.85" cy="6.98" r="6.98" />
<circle class="dot-8" cx="1130.49" cy="6.98" r="6.98" />
<circle class="dot-9" cx="1109.85" cy="165.69" r="6.98" />
<circle class="dot-10" cx="1130.49" cy="165.69" r="6.98" />
<circle class="dot-11" cx="1102.87" cy="105.99" r="6.98" />
<circle class="dot-12" cx="1102.87" cy="85.35" r="6.98" />
</g>
</svg>
Wanted Animation
The basic issue is:
#keyframes draw {
to {
stroke-dashoffset: 0;
fill: #1e9a64; <=== this
}
}
You can't fill as the path draws only after the path is complete.
I'd suggest adjusting the paths so that the space between the path "sides* is approximately half the stroke width.
Alternatively, adjust the stroke width (say stroke-width="7.5") and make the circles a little larger (say r="9.98)...
Something like this (poor approximation):
svg {
margin: 5vh
}
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1244.41 201.57">
<defs>
<style>
.cls-1 {
fill:#f59e00;
}
.cls-2 {
fill:#7a1331;
}
#Dots circle {
fill:#1e9a64;
}
#Lines path {
animation: draw 3s linear forwards;
animation-delay: 1.2s;
}
#Years_Text {
animation: 1s ease-out 0s 1 slideInFromRight;
}
.line-1 {
stroke-dasharray: 2150;
stroke-dashoffset: 2150;
}
.line-2 {
stroke-dasharray: 1600;
stroke-dashoffset: 1600;
}
.line-3 {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
}
.line-4 {
stroke-dasharray: 650;
stroke-dashoffset: 650;
}
.line-5 {
stroke-dasharray: 1600;
stroke-dashoffset: 1600;
}
.line-6 {
stroke-dasharray: 1300;
stroke-dashoffset: 1300;
}
#keyframes draw {
to {
stroke-dashoffset: 0;
}
}
.dot-1 {
animation: 1s ease-out 0s 1 slideInFromLeft;
}
.dot-2 {
animation: 1s ease-out 0s 1 slideInFromCenterToLeft;
}
.dot-3 {
animation: 1s ease-out 0s 1 slideInFromCenterToLeft;
}
.dot-4 {
animation: 1s ease-out 0s 1 slideInFromCenterToLeft;
}
.dot-5 {
animation: 1s ease-out 0s 1 slideInFromLeft;
}
.dot-6 {
animation: 1s ease-out 0s 1 slideInFromLeft;
}
.dot-7 {
animation: 1s ease-out 0s 1 slideInFromCenterToRight;
}
.dot-8 {
animation: 1s ease-out 0s 1 slideInFromCenterToRight;
}
.dot-9 {
animation: 1s ease-out 0s 1 slideInFromTop;
}
.dot-10 {
animation: 1s ease-out 0s 1 slideInFromLeft;
}
.dot-11 {
animation: 1s ease-out 0s 1 slideInFromRight;
}
.dot-12 {
animation: 1s ease-out 0s 1 slideInFromRight;
}
#keyframes slideInFromLeft {
0% {
transform: translate(-20%, -20%);
}
100% {
transform: translate(0, 0);
}
}
#keyframes slideInFromRight {
0% {
transform: translate(+20%, +20%);
}
100% {
transform: translate(0, 0);
}
}
#keyframes slideInFromCenterToRight {
0% {
transform: translate(-5%, +50%);
}
100% {
transform: translate(0, 0);
}
}
#keyframes slideInFromCenterToLeft {
0% {
transform: translate(+15%, +30%);
}
100% {
transform: translate(0, 0);
}
}
#keyframes slideInFromTop {
0% {
transform: translate(-5%, -5%);
}
100% {
transform: translate(0, 0);
}
}
</style>
</defs>
<g id="Lines">
<path class="line-1" fill="none" stroke="#1e9a64" stroke-width="7.5" d="M1155.49,188.09h-69.85A3.74,3.74,0,0,1,1083,187l-20.2-20.19a3.73,3.73,0,0,1-1.09-2.64v-137a3.73,3.73,0,0,1,1.09-2.64L1083,4.35a3.74,3.74,0,0,1,2.64-1.1h24.21a3.74,3.74,0,0,1,0,7.47h-22.67l-18,18V162.61l18,18h66.76l18-18V28.73l-18-18h-23.45a3.74,3.74,0,1,1,0-7.47h25a3.74,3.74,0,0,1,2.64,1.1l20.2,20.19a3.73,3.73,0,0,1,1.09,2.64v137a3.73,3.73,0,0,1-1.09,2.64L1158.13,187A3.74,3.74,0,0,1,1155.49,188.09Z" />
<path class="line-2" fill="none" stroke="#1e9a64" stroke-width="7.5" d="M1145.2,169.43h-14.71a3.74,3.74,0,1,1,0-7.47h13.11l9.7-10.21V39.25l-9.67-9.87H1098.2l-10.37,9.93V151.68l10.4,10.28h11.62a3.74,3.74,0,0,1,0,7.47H1096.7a3.73,3.73,0,0,1-2.62-1.08l-12.6-12.46a3.71,3.71,0,0,1-1.11-2.65V37.72a3.69,3.69,0,0,1,1.15-2.69L1094.12,23a3.71,3.71,0,0,1,2.58-1h48.5a3.79,3.79,0,0,1,2.67,1.12l11.82,12.08a3.72,3.72,0,0,1,1.07,2.61V153.24a3.72,3.72,0,0,1-1,2.57l-11.82,12.45A3.73,3.73,0,0,1,1145.2,169.43Z" />
<path class="line-3" fill="none" stroke="#1e9a64" stroke-width="7.5" d="M1131.61,150.77h-23.15a3.76,3.76,0,0,1-2.6-1.05l-5.69-5.51a3.71,3.71,0,0,1-1.14-2.68V106a3.73,3.73,0,1,1,7.46,0v34l3.48,3.36h20.31l4.36-3.55V52.26L1130.13,48h-20l-3.63,4V85.35a3.73,3.73,0,0,1-7.46,0V50.64a3.73,3.73,0,0,1,1-2.49l5.7-6.34a3.74,3.74,0,0,1,2.78-1.24h23.15a3.73,3.73,0,0,1,2.55,1l6.76,6.34a3.75,3.75,0,0,1,1.18,2.72v90.89a3.74,3.74,0,0,1-1.38,2.89l-6.76,5.51A3.73,3.73,0,0,1,1131.61,150.77Z" />
<path class="line-4" fill="none" stroke="#1e9a64" stroke-width="7.5" d="M974.43,150.77H938a3.74,3.74,0,0,1,0-7.47H970.7v-84l-11.33,5.72A3.73,3.73,0,0,1,956,58.41L972.75,50a3.72,3.72,0,0,1,5.41,3.33V147A3.73,3.73,0,0,1,974.43,150.77Z" />
<path class="line-5" fill="none" stroke="#1e9a64" stroke-width="7.5" d="M1048.22,188.09H938a3.73,3.73,0,0,1-3.73-3.74V165.69A3.73,3.73,0,0,1,938,162h51.39V29.38h-6.5L949.75,46.73a3.73,3.73,0,1,1-3.46-6.61l33.92-17.78a3.72,3.72,0,0,1,1.73-.43h11.15a3.73,3.73,0,0,1,3.73,3.73V165.69a3.73,3.73,0,0,1-3.73,3.74H941.7v11.19h106.52a3.74,3.74,0,0,1,0,7.47Z" />
<path class="line-6" fill="none" stroke="#1e9a64" stroke-width="7.5" d="M1048.22,169.43h-36.47a3.74,3.74,0,0,1,0-7.47h32.73V150.77h-32.73A3.73,3.73,0,0,1,1008,147V10.72H975.33L940.84,28.36a3.73,3.73,0,1,1-3.4-6.64L972.73,3.66a3.74,3.74,0,0,1,1.7-.41h37.32A3.73,3.73,0,0,1,1015.48,7V143.3h32.74A3.73,3.73,0,0,1,1052,147v18.66A3.73,3.73,0,0,1,1048.22,169.43Z" />
</g>
<g id="Dots">
<circle class="dot-1" cx="941.03" cy="147.03" r="9.98" />
<circle class="dot-2" cx="941.23" cy="23.59" r="9.98" />
<circle class="dot-3" cx="958.83" cy="61.32" r="9.98" />
<circle class="dot-4" cx="949.22" cy="42.96" r="9.98" />
<circle class="dot-5" cx="1014.77" cy="165.69" r="9.98" />
<circle class="dot-6" cx="1045.08" cy="184.35" r="9.98" />
<circle class="dot-7" cx="1109.85" cy="6.98" r="9.98" />
<circle class="dot-8" cx="1130.49" cy="6.98" r="9.98" />
<circle class="dot-9" cx="1109.85" cy="165.69" r="9.98" />
<circle class="dot-10" cx="1130.49" cy="165.69" r="9.98" />
<circle class="dot-11" cx="1102.87" cy="105.99" r="9.98" />
<circle class="dot-12" cx="1102.87" cy="85.35" r="9.98" />
</g>
</svg>
BTW, there is an attribute in SVG called pathLength which can be set manually say to pathLength=""`.
From CSS-Tricks
That doesn't do anything by itself (as far as I know). It's not like that only draws part of the path — it still draws the whole thing like as if you did nothing, only now the "math" of the path length is based on a value of 1.
Now we can set the stroke-dasharray to 1, and animate the offset in CSS!
E.g
#keyframes dash {
from {
stroke-dashoffset: 1;
}
to {
stroke-dashoffset: 0;
}
}
You can use significantly reduce repetition in your CSS.
Related
Animated stroke-dashoffset on iOS
So, I have this SVG logo animated by increasing the stroke-dashoffset value svg { position: absolute; top: 50%; left: 50%; transform: translateX(-50%) translateY(-50%); width: 150px; } .cls-1, .cls-2 { fill:none; stroke:#a9a9a9; stroke-linecap:round; stroke-linejoin:round; stroke-width:10px; } .cls-1 { stroke-dasharray: 496; stroke-dashoffset: -496; animation: firstLine 2s ease-out 0s infinite normal; } .cls-2 { stroke-dasharray: 458; stroke-dashoffset: -458; animation: secondLine 2s ease-out 0s infinite normal; } #keyframes firstLine { 0% { stroke-dashoffset: -496; } 40% { stroke-dashoffset: 0; } 60% { stroke-dashoffset: 0; } 85% { stroke-dashoffset: 496; } 100% { stroke-dashoffset: 496; } } #keyframes secondLine { 0% { stroke-dashoffset: -458; } 45% { stroke-dashoffset: 0; } 60% { stroke-dashoffset: 0; } 90% { stroke-dashoffset: 458; } 100% { stroke-dashoffset: 458; } } <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200.17 135"><path class="cls-1" d="M132.67,28.44a39.06,39.06,0,0,1,0,78.12H113.22V59.11A54.11,54.11,0,0,0,5,59.11v57.35a13.54,13.54,0,0,0,27.08,0v-9.9h27"/><path class="cls-2" d="M113.63,5h19a62.5,62.5,0,0,1,0,125H102.44a16.29,16.29,0,0,1-16.3-16.29V59.11a27,27,0,0,0-54.06,0V79.89h27"/></svg> When opened on desktop browser, everything is fine. Same for Android. But on iOS, the animation is going so wrong. Is there some iOS specific bug stroke-dashoffset that I'm not aware of?
I have been looking for a solution for a long time how to replace negative stroke-dashoffset values with positive values in order to circumvent the restrictions that safari imposes. Explanations are given for animating one line. For the second line, the calculation is similar. The total length of the line is 496 px; therefore, the value of stroke-dashoffset = "496"completely hides the line. With double value stroke-dashoffset ="992" line is drawn With triple value stroke-dashoffset =" 1488 ", the line is erased again CSS solution svg { position: absolute; top: 50%; left: 50%; transform: translateX(-50%) translateY(-50%); width: 150px; } .cls-1, .cls-2 { fill:none; stroke:#a9a9a9; stroke-linecap:round; stroke-linejoin:round; stroke-width:10px; } .cls-1 { stroke-dasharray: 496; stroke-dashoffset: 0; animation: firstLine 2s ease-out 0s infinite normal; } .cls-2 { stroke-dasharray: 458; stroke-dashoffset: 0; animation: secondLine 2s ease-out 0s infinite normal; } #keyframes firstLine { 0% { stroke-dashoffset: 496; } 40% { stroke-dashoffset: 992; } 60% { stroke-dashoffset: 992; } 85% { stroke-dashoffset: 1488; } 100% { stroke-dashoffset: 1488; } } #keyframes secondLine { 0% { stroke-dashoffset: 458; } 45% { stroke-dashoffset: 916; } 60% { stroke-dashoffset: 916; } 90% { stroke-dashoffset: 1374; } 100% { stroke-dashoffset: 1374; } } <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200.17 135"> <path class="cls-1 " d="M132.67,28.44a39.06,39.06,0,0,1,0,78.12H113.22V59.11A54.11,54.11,0,0,0,5,59.11v57.35a13.54,13.54,0,0,0,27.08,0v-9.9h27" > </path> <path class="cls-2" d="M113.63,5h19a62.5,62.5,0,0,1,0,125H102.44a16.29,16.29,0,0,1-16.3-16.29V59.11a27,27,0,0,0-54.06,0V79.89h27" > </path> </svg> Option with a shadow around the logo Add shadow <defs> <filter id="shadow" x="-20%" y="-20%" width="200%" height="200%"> <feDropShadow dx="4" dy="8" stdDeviation="4"/> </filter> </defs> body { background: rgb(144,210,152); background: linear-gradient(286deg, rgba(144,210,152,1) 29%, rgba(236,234,154,1) 69%); } svg { position: absolute; top: 50%; left: 50%; transform: translateX(-50%) translateY(-50%); width: 150px; } .cls-1, .cls-2 { fill:none; stroke:#a9a9a9; stroke-linecap:round; stroke-linejoin:round; stroke-width:10px; filter:url(#shadow); } .cls-1 { stroke-dasharray: 496; stroke-dashoffset: 0; animation: firstLine 4s ease-out 0s infinite normal; } .cls-2 { stroke-dasharray: 458; stroke-dashoffset: 0; animation: secondLine 4s ease-out 0s infinite normal; } #keyframes firstLine { 0% { stroke-dashoffset: 496; } 40% { stroke-dashoffset: 992; } 60% { stroke-dashoffset: 992; } 85% { stroke-dashoffset: 1488; } 100% { stroke-dashoffset: 1488; } } #keyframes secondLine { 0% { stroke-dashoffset: 458; } 45% { stroke-dashoffset: 916; } 60% { stroke-dashoffset: 916; } 90% { stroke-dashoffset: 1374; } 100% { stroke-dashoffset: 1374; } } <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220.17 150"> <defs> <filter id="shadow" x="-20%" y="-20%" width="200%" height="200%"> <feDropShadow dx="4" dy="8" stdDeviation="4"/> </filter> </defs> <path class="cls-1 " d="M132.67,28.44a39.06,39.06,0,0,1,0,78.12H113.22V59.11A54.11,54.11,0,0,0,5,59.11v57.35a13.54,13.54,0,0,0,27.08,0v-9.9h27" > </path> <path class="cls-2" d="M113.63,5h19a62.5,62.5,0,0,1,0,125H102.44a16.29,16.29,0,0,1-16.3-16.29V59.11a27,27,0,0,0-54.06,0V79.89h27" > </path> </svg> SVG solution svg { position: absolute; top: 50%; left: 50%; transform: translateX(-50%) translateY(-50%); width: 150px; } .cls-1, .cls-2 { fill:none; stroke:#a9a9a9; stroke-linecap:round; stroke-linejoin:round; stroke-width:10px; } <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200.17 135"> <path class="cls-1 " d="M132.67,28.44a39.06,39.06,0,0,1,0,78.12H113.22V59.11A54.11,54.11,0,0,0,5,59.11v57.35a13.54,13.54,0,0,0,27.08,0v-9.9h27" stroke-dasharray="496,496" stroke-dashoffset="496"> <animate id="an_offset" attributeName="stroke-dashoffset" begin="0s" dur="3s" values="496;992;992;1488" fill="freeze" repeatCount="indefinite" /> </path> <path class="cls-2" d="M113.63,5h19a62.5,62.5,0,0,1,0,125H102.44a16.29,16.29,0,0,1-16.3-16.29V59.11a27,27,0,0,0-54.06,0V79.89h27" stroke-dasharray="458,458" stroke-dashoffset="458"> <animate id="an_offset2" attributeName="stroke-dashoffset" begin="0s" dur="3s" values="458;916;916;1374" fill="freeze" repeatCount="indefinite" /> </path> </svg> Additional example Drawing from each line from its midpoint To implement the animation, change the parameters of the stroke-dasharray attribute With a total line length of 496px, half of it is` 248px since the values of the parameters in order mean: 0 - line, 248 - space 0 - line, 248 - space. Therefore, writing stroke-dasharray = "0,248 0,248" will completely hide the line With stroke-dasharray = "0,0 496,0" the line will be fully visible. svg { position: absolute; top: 50%; left: 50%; transform: translateX(-50%) translateY(-50%); width: 150px; } .cls-1, .cls-2 { fill:none; stroke:#a9a9a9; stroke-linejoin:round; stroke-width:10px; } <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200.17 135"> <path class="cls-1 " d="M132.67,28.44a39.06,39.06,0,0,1,0,78.12H113.22V59.11A54.11,54.11,0,0,0,5,59.11v57.35a13.54,13.54,0,0,0,27.08,0v-9.9h27" stroke-dasharray="496,496" stroke-dashoffset="496"> <animate id="an_array" attributeName="stroke-dasharray" begin="0s" dur="4s" values="0,248 0,248;0,0 496,0;0,0 496,0;0,248 0,248" fill="freeze" repeatCount="indefinite" /> </path> <path class="cls-2" d="M113.63,5h19a62.5,62.5,0,0,1,0,125H102.44a16.29,16.29,0,0,1-16.3-16.29V59.11a27,27,0,0,0-54.06,0V79.89h27" stroke-dasharray="458,458" stroke-dashoffset="458"> <animate id="an_array2" attributeName="stroke-dasharray" begin="0s" dur="4s" values="0,229 0,229;0,0 458,0;0,0 458,0;0,229 0,229" fill="freeze" repeatCount="indefinite" /> </path>
As mentioned by #RobertLongson, it's a Safari bug where is does not support negative values for stroke-dashiffset
CSS for my SVG (Having trouble with Transform Origin)
So I have two classes(firstCircle & spin) on the First circle on the left and I'm trying to get it to rotate in place.(removed them from css so you can see the circle) I'm getting confused on transform-origin: What is wrong with my code.It's rotating way out of place instead of spinning. I added a width and height and tried transform-origin and it just makes it disappear. .spin { position: absolute; top: 50%; left: 50%; width: 120px; height: 1120px; margin:-60px 0 0 -60px; -webkit-animation:spin 4s linear infinite; -moz-animation:spin 4s linear infinite; animation:spin 4s linear infinite; transform-origin: center center; } #-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } } #-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } } #keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } } .container { padding:auto; width: auto; height: auto; text-align:center; } .line1 { stroke-dasharray: 1000; stroke-dashoffset: 1000; animation: dash 10s linear forwards; animation-delay: 2.13s; } .line2 { stroke-dasharray: 1000; stroke-dashoffset: 1000; animation: dash 10s linear forwards; animation-delay: 2.5s; } .line3 { stroke-dasharray: 1000; stroke-dashoffset: 1000; animation: dash 10s linear forwards; animation-delay: 3s; } .line4 { stroke-dasharray: 1000; stroke-dashoffset: 1000; animation: dash 10s linear forwards; animation-delay: 3.4s; } .line5 { stroke-dasharray: 1000; stroke-dashoffset: 1000; animation: dash 10s linear forwards; animation-delay: 3.9s; } #keyframes dash { from { stroke-dashoffset: 1000; } to { stroke-dashoffset: 0; } } .insidefirstCircle { stroke-dasharray: 1000; stroke-dashoffset: 100; animation: insideCircle 10s linear forwards; animation-delay: 1.2s; } #keyframes insideCircle { from { stroke-dashoffset: 1000; opacity: 1; } to { stroke-dashoffset: 0; opacity: 1; } } .secondCircle { animation: secondCircle 2s linear forwards; animation-delay: 2.2s; } #keyframes secondCircle { from { stroke-dashoffset: 1000; opacity: 0; } to { stroke-dashoffset: 0; opacity: 1; } } .insidesecondCircle { animation: insidesecondCircle 2s linear forwards; animation-delay: 2.2s; } #keyframes insidesecondCircle { from { stroke-dashoffset: 1000; opacity: 0; } to { stroke-dashoffset: 0; opacity: 1; } } <!DOCTYPE html> <link rel="stylesheet" type="text/css" href="css/css.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <div class="container"> <svg> <path class="firstCircle spin" transform="matrix(-0.98886073,0.14884376,-0.16522036,-0.98625668,0,0)" d="m -28.957516,-109.01346 a 20.505369,19.487934 0 0 1 25.9801488,5.74848 20.505369,19.487934 0 0 1 -1.9792854,25.281519 20.505369,19.487934 0 0 1 -26.5892124,2.031123 20.505369,19.487934 0 0 1 -6.202719,-24.656512" id="path7158" style="opacity:1;fill:none;fill-opacity:0.94117647;stroke:#4fae7d;stroke-width:0.35702455;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" /> <path class="insidefirstCircle" transform="matrix(-0.22033261,-0.9754248,-0.97735568,0.21160309,0,0)" d="m -102.55362,-32.142649 a 7.185163,7.442451 0 0 1 5.829705,7.489633 7.185163,7.442451 0 0 1 -6.173275,7.188196 7.185163,7.442451 0 0 1 -7.86062,-5.124812" id="path7160" style="opacity:0;fill:none;fill-opacity:0.94117647;stroke:#4fae7d;stroke-width:0.35700712;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" /> <ellipse class="secondCircle" ry="5.8064542" rx="5.806459" transform="rotate(-9.0228844)" cy="102.10918" cx="31.181959" id="path7162" style="opacity:0;fill:none;fill-opacity:0.94117647;stroke:#4fae7d;stroke-width:0.38561434;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" /> <circle class="insidesecondCircle" r="2.081239" style="opacity:0;fill:none;fill-opacity:0.94117647;stroke:#4fae7d;stroke-width:2.138;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" id="circle7192" cx="46.80978" cy="95.955421" /> <circle class="line1" r="8.1839027" cy="124.84148" cx="88.252518" id="path7166" style="opacity:1;fill:none;fill-opacity:0.94117647;stroke:#4fae7d;stroke-width:0.63219434;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" /> <circle style="opacity:1;fill:none;fill-opacity:0.94117647;stroke:#4fae7d;stroke-width:3.454;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" id="circle7168" cx="88.252518" cy="124.84148" r="4.5812778" /> <circle r="6.7396846" style="opacity:1;fill:none;fill-opacity:0.94117647;stroke:#4fae7d;stroke-width:0.52063066;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" id="circle7174" cx="128.74611" cy="90.168755" /> <path style="opacity:1;fill:none;fill-opacity:0.94117647;stroke:#4fae7d;stroke-width:0.35702455;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" id="path7186" d="m -180.38976,-169.87182 a 20.505369,19.487934 0 0 1 27.64196,8.28339 20.505369,19.487934 0 0 1 -8.68637,26.27924 20.505369,19.487934 0 0 1 -27.66048,-8.22736 20.505369,19.487934 0 0 1 8.62739,-26.29677" transform="matrix(-0.98886073,0.14884376,-0.16522036,-0.98625668,0,0)" /> <ellipse style="opacity:1;fill:none;fill-opacity:0.94117647;stroke:#4fae7d;stroke-width:0.35702455;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" id="ellipse7190" cx="152.20651" cy="155.0309" transform="matrix(0.98886074,-0.14884364,0.16522023,0.9862567,0,0)" rx="5.5144606" ry="5.2409396" /> <circle cy="90.168755" cx="128.74611" id="circle7196" style="opacity:1;fill:none;fill-opacity:0.94117647;stroke:#4fae7d;stroke-width:2.13800001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" r="2.081239" /> <path class="line1" id="path875" d="m 19.085467,74.174836 c 22.366283,17.178223 22.335724,17.75844 22.335724,17.75844" style="fill:none;stroke:#4fae7d;stroke-width:0.28233331px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> <path class="line2" style="fill:none;stroke:#4fae7d;stroke-width:0.36648375px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="m 51.183439,99.59881 c 29.032633,22.29825 28.992966,23.0514 28.992966,23.0514" id="path885" /> <path class="line3" id="path879" d="M 95.534634,121.46865 C 123.9702,95.423153 123.73736,94.872744 123.73736,94.872744" style="fill:none;stroke:#4fae7d;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> <path class="line4" id="path881" d="m 134.621,93.468564 c 37.14699,33.672096 37.14699,33.672096 37.14699,33.672096" style="fill:none;stroke:#4fae7d;stroke-width:0.26971px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> <path class="line5" id="path883" d="m 181.40295,129.52127 c 31.40453,-10.83262 31.9066,-11.93052 31.9066,-11.93052" style="fill:none;stroke:#4fae7d;stroke-width:0.37912115px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> </g> </svg> </div> </body> </html>
Firstly, most of the CSS properties you have in your .spin and firstCircle definitions are invalid. position, top, 'left, and margin are all HTML-only properties. And width and height are not valid for <path> elements. It is important to remember that SVG is a totally different standard from HTML and works differently. Secondly, your path already has a transform. CSS transforms don't add, so any transform in your animation, will overwrite the one on your <path>. The simplest way to resolve that problem is to either (a) get your SVG editor to multiply through the transform to the path coordinates; or (b) work around it by using a nested group <g> element around the path. One of the transforms is applied to that, and the other is applied to the path. <g transform="matrix(-0.98886073,0.14884376,-0.16522036,-0.98625668,0,0)"> <path class="firstCircle spin" d="..." /> </g> transform-origin Now that those issues are resolved, we can deal with the matter of the centre-of-rotation. There are issues with browser compatibility with transform-origin. Chrome has an implementation that is out-of-date with respect to the specification. That is in the process of getting fixed, but for now, the workaround is to always use absolute coordinates instead of percentage values. The centre of your circle is at (-19.5, -91.7), so the correct transform-origin to use is: transform-origin: -19.5px -91.7px; So if we plug this into a working example: .spin { transform-origin: -19.5px -91.7px; animation:spin 4s linear infinite; } #keyframes spin { 100% { transform:rotate(360deg); } } <svg> <g transform="matrix(-0.98886073,0.14884376,-0.16522036,-0.98625668,0,0)"> <path class="firstCircle spin" d="m -28.957516,-109.01346 a 20.505369,19.487934 0 0 1 25.9801488,5.74848 20.505369,19.487934 0 0 1 -1.9792854,25.281519 20.505369,19.487934 0 0 1 -26.5892124,2.031123 20.505369,19.487934 0 0 1 -6.202719,-24.656512" style="opacity:1;fill:none;fill-opacity:0.94117647;stroke:#4fae7d;stroke-width:0.35702455;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" /> </g> </svg>
CSS animation rotate then wiggle SVG
I have an SVG compass with an arrow in it. I want to be able to add a class to the arrow and have it rotate a certain degree then stay there and wiggle. I have the rotation and wiggle working just not together. Not sure how to combine the two so they work together. Here is my code: div { max-width: 40%; } .st0 { fill: none; stroke: #505050; stroke-width: 4.11; stroke-linecap: round; stroke-miterlimit: 10; } .st1 { fill: none; stroke: #808080; stroke-width: 2.57; stroke-linecap: round; stroke-miterlimit: 10; } .st2 { fill: #505050; } .st3 { opacity: 0.5; } .st4 { fill: none; } /* Fill Colors */ .green { fill: rgba(21, 255, 0, 0.5); } .dgreen { fill: rgba(12, 140, 0, 0.5); } .red { fill: rgba(255, 42, 0, 0.5); } .dred { fill: rgba(140, 23, 0, 0.5); } /* Arrow */ #arrow { transform-origin: 50% 59.7%; animation-name: wiggle; animation-duration: 1s; animation-fill-mode: forward; -webkit-animation-fill-mode: forward; -webkit-animation-iteration-count: infinite; /* Safari 4.0 - 8.0 */ animation-iteration-count: infinite; } /* Rotations */ .north#arrow { -webkit-transform: rotate(45deg); -webkit-transition: -webkit-transform 0.5s ease-in; } .northEast#arrow { -webkit-transform: rotate(90deg); -webkit-transition: -webkit-transform 0.5s ease-in; } .west#arrow { -webkit-transform: rotate(135deg); -webkit-transition: -webkit-transform 0.5s ease-in; } .southWest#arrow { -webkit-transform: rotate(180deg); -webkit-transition: -webkit-transform 0.5s ease-in; } .south#arrow { -webkit-transform: rotate(225deg); -webkit-transition: -webkit-transform 0.5s ease-in; } .southWest#arrow { -webkit-transform: rotate(270deg); -webkit-transition: -webkit-transform 0.5s ease-in; } .west#arrow { -webkit-transform: rotate(315deg); -webkit-transition: -webkit-transform 0.5s ease-in; } .northWest#arrow { -webkit-transform: rotate(0deg); -webkit-transition: -webkit-transform 0.5s ease-in; } /* Wiggle Animation */ /* safari and chrome */ #-webkit-keyframes wiggle { 0% { -webkit-transform: rotate(4deg); } 50% { -webkit-transform: rotate(-4deg); } 100% { -webkit-transform: rotate(4deg); } } /* firefox */ #-moz-keyframes wiggle { 0% { -moz-transform: rotate(4deg); } 50% { -moz-transform: rotate(-4deg); } 100% { -moz-transform: rotate(4deg); } } #keyframes wiggle { 0% { transform: rotate(4deg); } 50% { transform: rotate(-4deg); } 100% { transform: rotate(4deg); } } <div> <?xml version="1.0" encoding="utf-8"?> <!-- Generator: Adobe Illustrator 22.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <svg version="1.1" id="Layer_4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 116.3 144" style="enable-background:new 0 0 116.3 144;" xml:space="preserve"> <title>compass</title> <line id="N" class="st0" x1="58.2" y1="31.3" x2="58.2" y2="49.6"/> <line id="NW" class="st1" x1="18.5" y1="46.1" x2="31.4" y2="59"/> <line id="W" class="st0" x1="3.6" y1="85.7" x2="21.9" y2="85.7"/> <line id="SW" class="st1" x1="18.3" y1="125.5" x2="31.3" y2="112.5"/> <line id="S" class="st0" x1="58" y1="140.3" x2="58" y2="122"/> <line id="SE" class="st1" x1="97.7" y1="125.6" x2="84.8" y2="112.6"/> <line id="E" class="st0" x1="113.4" y1="85.9" x2="95.1" y2="85.9"/> <line id="NE" class="st1" x1="97.8" y1="46.2" x2="84.9" y2="59.1"/> <path id="compass" class="st2" d="M69.6,28.8c6.7-6.3,7-16.9,0.7-23.6s-16.9-7-23.6-0.7s-7,16.9-0.7,23.6c0.2,0.2,0.4,0.5,0.7,0.7 c-31.5,6.3-51.9,37-45.6,68.5s37,51.9,68.5,45.6c31.5-6.3,51.9-37,45.6-68.5C110.6,51.4,92.6,33.4,69.6,28.8z M58.2,6.5 c5.6,0,10.2,4.6,10.2,10.2H48C48,11.1,52.6,6.5,58.2,6.5z M58.2,138.3c-29,0-52.5-23.5-52.5-52.5s23.5-52.5,52.5-52.5 c29,0,52.5,23.5,52.5,52.5c0,0,0,0,0,0C110.6,114.8,87.1,138.3,58.2,138.3z"/> <path id="inner_compass" class="st2" d="M58.2,130.8c-24.9,0-45.2-20.2-45.2-45.2s20.2-45.2,45.2-45.2c24.9,0,45.2,20.2,45.2,45.1 c0,0,0,0,0,0C103.3,110.6,83.1,130.8,58.2,130.8z M58.2,43.8c-23.1,0-41.9,18.8-41.9,41.9s18.8,41.9,41.9,41.9s41.9-18.8,41.9-41.9 C100.1,62.6,81.3,43.8,58.2,43.8L58.2,43.8z"/> <g id="NNW" class="st3"> <path id="nnwPie" class="st4 green" d="M57.9,27.7v58.2l-41-41C27.8,33.9,42.5,27.7,57.9,27.7z"/> </g> <g id="WNW" class="st3"> <path id="wnwPie" class="st4 dgreen" d="M57.9,85.8H0.2v-0.2c0-15.3,6-30,16.8-40.8L57.9,85.8z"/> </g> <g id="WSW"> <path id="wswPie" class="st4" d="M57.9,85.8l-40.8,40.8c-10.8-10.8-16.9-25.5-17-40.8H57.9z"/> </g> <g id="SSW"> <path id="sswPie" class="st4" d="M57.9,85.8v57.8c-15.3,0-30-6.2-40.8-17L57.9,85.8z"/> </g> <g id="SSE"> <path id="ssePie" class="st4 red" d="M99,126.9c-10.8,10.8-25.5,16.8-40.8,16.8H58V85.8L99,126.9z"/> </g> <g id="ESE"> <path id="esePie" class="st4 dred" d="M116.2,85.8c0,15.4-6.2,30.2-17.2,41l-41-41H116.2z"/> </g> <g id="ENE"> <path id="enePie" class="st4" d="M116.2,85.7v0.2H57.9l41.2-41.2C110.1,55.5,116.2,70.3,116.2,85.7z"/> </g> <g id="NNE"> <path id="nnePie" class="st4" d="M99.1,44.6L57.9,85.8V27.7h0.2C73.5,27.6,88.3,33.7,99.1,44.6z"/> </g> <polygon id="arrow" class="st2 west" points="78.4,105.3 80.2,107.1 79.1,108.3 77.2,106.4 75.5,109.7 74.1,108.6 75.9,105.1 75.1,104.3 73.3,107.7 71.9,106.6 73.8,103 72.9,102.1 71.2,105.6 69.8,104.5 71.7,100.9 63.5,92.7 63.5,92.7 41.5,70.7 41.4,70.8 39,74.3 34.5,62.5 46.3,67.1 42.5,69.5 64.6,91.6 65.2,92.1 72.9,99.8 76.5,98 77.6,99.5 74.1,101.1 74.9,101.9 78.6,100 79.7,101.4 76.2,103.1 75.9,102.9 77.1,104 80.8,102.3 81.9,103.8 "/> </svg> </div>
You need to chain animations together and use a delay between them so one plays after the other has finished. You were previously using a transition and then an animation which are two separate things. Also browser prefixes are now pretty redundant for animations, I personally would use the non-prefixed syntax. Here is one example where the arrow moves to the south and then wiggles, you will need to add in the others: Example CSS .wrap:hover #arrow { transform-origin: 50% 59.7%; animation-name: spinSouth, wiggleSouth; animation-delay: 0s, 1s; animation-duration: 1s, 1s; animation-iteration-count: 1, infinite; } /* Spin south Animation */ #keyframes spinSouth { 0% { transform: rotate(4deg); } 100% { transform: rotate(225deg); } } /* Wiggle Animation */ #keyframes wiggleSouth { 0% { transform: rotate(225deg); } 50% { transform: rotate(220deg); } 100% { transform: rotate(225deg); } } Fiddle: http://jsfiddle.net/5cn9sm99/
I think this may be a shorter solution with the code you already have. You could wrap your arrow in an arrow container like this: <g id="arrowContainer"> <polygon id="arrow" class="st2 west" points="78.4,105.3 80.2,107.1 79.1,108.3 77.2,106.4 75.5,109.7 74.1,108.6 75.9,105.1 75.1,104.3 73.3,107.7 71.9,106.6 73.8,103 72.9,102.1 71.2,105.6 69.8,104.5 71.7,100.9 63.5,92.7 63.5,92.7 41.5,70.7 41.4,70.8 39,74.3 34.5,62.5 46.3,67.1 42.5,69.5 64.6,91.6 65.2,92.1 72.9,99.8 76.5,98 77.6,99.5 74.1,101.1 74.9,101.9 78.6,100 79.7,101.4 76.2,103.1 75.9,102.9 77.1,104 80.8,102.3 81.9,103.8 "/> </g> Then add this styles to center the pivot point of the container: #arrowContainer{ transform-origin: 50% 50%; } Now replace the Rotations to target the arrowContainer and use Javascript or jQuery to add the classes you already created. Here is the full code. var changeDirection = function changeClass(myClass){ $('#compass').attr("class", myClass); } div { max-width: 300px; } .st0 { fill: none; stroke: #505050; stroke-width: 4.11; stroke-linecap: round; stroke-miterlimit: 10; } .st1 { fill: none; stroke: #808080; stroke-width: 2.57; stroke-linecap: round; stroke-miterlimit: 10; } .st2 { fill: #505050; } .st3 { opacity: 0.5; } .st4 { fill: none; } /* Fill Colors */ .green { fill: rgba(21, 255, 0, 0.5); } .dgreen { fill: rgba(12, 140, 0, 0.5); } .red { fill: rgba(255, 42, 0, 0.5); } .dred { fill: rgba(140, 23, 0, 0.5); } /* Arrow */ #arrowContainer{ transform-origin: 50% 50%; } #arrow { transform-origin: 50% 59.7%; animation-name: wiggle; animation-duration: 1s; animation-fill-mode: forward; -webkit-animation-fill-mode: forward; -webkit-animation-iteration-count: infinite; /* Safari 4.0 - 8.0 */ animation-iteration-count: infinite; } /* Rotations */ .north #arrowContainer { -webkit-transform: rotate(45deg); -webkit-transition: -webkit-transform 0.5s ease-in; } .northEast #arrowContainer { -webkit-transform: rotate(90deg); -webkit-transition: -webkit-transform 0.5s ease-in; } .east #arrowContainer { -webkit-transform: rotate(135deg); -webkit-transition: -webkit-transform 0.5s ease-in; } .southEast #arrowContainer { -webkit-transform: rotate(180deg); -webkit-transition: -webkit-transform 0.5s ease-in; } .south #arrowContainer { -webkit-transform: rotate(225deg); -webkit-transition: -webkit-transform 0.5s ease-in; } .southWest #arrowContainer { -webkit-transform: rotate(270deg); -webkit-transition: -webkit-transform 0.5s ease-in; } .west #arrowContainer { -webkit-transform: rotate(315deg); -webkit-transition: -webkit-transform 0.5s ease-in; } .northWest #arrowContainer { -webkit-transform: rotate(0deg); -webkit-transition: -webkit-transform 0.5s ease-in; } /* Wiggle Animation */ /* safari and chrome */ #-webkit-keyframes compass { 0% { -webkit-transform: rotate(0deg); } 100% { -webkit-transform: rotate(0deg); } } #-webkit-keyframes wiggle { 0% { -webkit-transform: rotate(4deg); } 50% { -webkit-transform: rotate(-4deg); } 100% { -webkit-transform: rotate(4deg); } } /* firefox */ #-moz-keyframes wiggle { 0% { -moz-transform: rotate(4deg); } 50% { -moz-transform: rotate(-4deg); } 100% { -moz-transform: rotate(4deg); } } #keyframes wiggle { 0% { transform: rotate(4deg); } 50% { transform: rotate(-4deg); } 100% { transform: rotate(4deg); } } /* Button Styles */ .buttons{ float: left; } <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="buttons"> <button onclick="changeDirection('north')">North</button> <button onclick="changeDirection('northEast')">NorthEast</button> <button onclick="changeDirection('east')">East</button> <button onclick="changeDirection('southEast')">South East</button> <button onclick="changeDirection('south')">South</button> <button onclick="changeDirection('southWest')">South West</button> <button onclick="changeDirection('west')">West</button> <button onclick="changeDirection('northWest')">North West</button> </div> <div id="compass" class="addClassHere"> <?xml version="1.0" encoding="utf-8"?> <!-- Generator: Adobe Illustrator 22.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <svg version="1.1" id="Layer_4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 116.3 144" style="enable-background:new 0 0 116.3 144;" xml:space="preserve"> <title>compass</title> <line id="N" class="st0" x1="58.2" y1="31.3" x2="58.2" y2="49.6"/> <line id="NW" class="st1" x1="18.5" y1="46.1" x2="31.4" y2="59"/> <line id="W" class="st0" x1="3.6" y1="85.7" x2="21.9" y2="85.7"/> <line id="SW" class="st1" x1="18.3" y1="125.5" x2="31.3" y2="112.5"/> <line id="S" class="st0" x1="58" y1="140.3" x2="58" y2="122"/> <line id="SE" class="st1" x1="97.7" y1="125.6" x2="84.8" y2="112.6"/> <line id="E" class="st0" x1="113.4" y1="85.9" x2="95.1" y2="85.9"/> <line id="NE" class="st1" x1="97.8" y1="46.2" x2="84.9" y2="59.1"/> <path id="compass" class="st2" d="M69.6,28.8c6.7-6.3,7-16.9,0.7-23.6s-16.9-7-23.6-0.7s-7,16.9-0.7,23.6c0.2,0.2,0.4,0.5,0.7,0.7 c-31.5,6.3-51.9,37-45.6,68.5s37,51.9,68.5,45.6c31.5-6.3,51.9-37,45.6-68.5C110.6,51.4,92.6,33.4,69.6,28.8z M58.2,6.5 c5.6,0,10.2,4.6,10.2,10.2H48C48,11.1,52.6,6.5,58.2,6.5z M58.2,138.3c-29,0-52.5-23.5-52.5-52.5s23.5-52.5,52.5-52.5 c29,0,52.5,23.5,52.5,52.5c0,0,0,0,0,0C110.6,114.8,87.1,138.3,58.2,138.3z"/> <path id="inner_compass" class="st2" d="M58.2,130.8c-24.9,0-45.2-20.2-45.2-45.2s20.2-45.2,45.2-45.2c24.9,0,45.2,20.2,45.2,45.1 c0,0,0,0,0,0C103.3,110.6,83.1,130.8,58.2,130.8z M58.2,43.8c-23.1,0-41.9,18.8-41.9,41.9s18.8,41.9,41.9,41.9s41.9-18.8,41.9-41.9 C100.1,62.6,81.3,43.8,58.2,43.8L58.2,43.8z"/> <g id="NNW" class="st3"> <path id="nnwPie" class="st4 green" d="M57.9,27.7v58.2l-41-41C27.8,33.9,42.5,27.7,57.9,27.7z"/> </g> <g id="WNW" class="st3"> <path id="wnwPie" class="st4 dgreen" d="M57.9,85.8H0.2v-0.2c0-15.3,6-30,16.8-40.8L57.9,85.8z"/> </g> <g id="WSW"> <path id="wswPie" class="st4" d="M57.9,85.8l-40.8,40.8c-10.8-10.8-16.9-25.5-17-40.8H57.9z"/> </g> <g id="SSW"> <path id="sswPie" class="st4" d="M57.9,85.8v57.8c-15.3,0-30-6.2-40.8-17L57.9,85.8z"/> </g> <g id="SSE"> <path id="ssePie" class="st4 red" d="M99,126.9c-10.8,10.8-25.5,16.8-40.8,16.8H58V85.8L99,126.9z"/> </g> <g id="ESE"> <path id="esePie" class="st4 dred" d="M116.2,85.8c0,15.4-6.2,30.2-17.2,41l-41-41H116.2z"/> </g> <g id="ENE"> <path id="enePie" class="st4" d="M116.2,85.7v0.2H57.9l41.2-41.2C110.1,55.5,116.2,70.3,116.2,85.7z"/> </g> <g id="NNE"> <path id="nnePie" class="st4" d="M99.1,44.6L57.9,85.8V27.7h0.2C73.5,27.6,88.3,33.7,99.1,44.6z"/> </g> <g id="arrowContainer"> <polygon id="arrow" class="st2 west" points="78.4,105.3 80.2,107.1 79.1,108.3 77.2,106.4 75.5,109.7 74.1,108.6 75.9,105.1 75.1,104.3 73.3,107.7 71.9,106.6 73.8,103 72.9,102.1 71.2,105.6 69.8,104.5 71.7,100.9 63.5,92.7 63.5,92.7 41.5,70.7 41.4,70.8 39,74.3 34.5,62.5 46.3,67.1 42.5,69.5 64.6,91.6 65.2,92.1 72.9,99.8 76.5,98 77.6,99.5 74.1,101.1 74.9,101.9 78.6,100 79.7,101.4 76.2,103.1 75.9,102.9 77.1,104 80.8,102.3 81.9,103.8 "/> </g> </svg> </div>
Reverse animation of SVG elements
I'm working on an animation which will be triggered when a class is added with jQuery after a click event. It has the be something like a toggle: After first click on button, animation 1 will be run https://codepen.io/thijs-webber/pen/dMBKRp After second click on same button reversed animation needs to be run Is there a way to reverse the chain of animations easily? .animation-container { width: 250px; position: relative; margin: 0 auto; margin-top: 50px; } .dot-pink-light { fill: #CE97AE; } .dot-pink { fill: #D82566; } .dot-green-light { fill: #AFBF99; } .dot-green { fill: #77BC1F; } /* ANIMATIONS */ #keyframes rotate_clockwise { 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); } 100% { -webkit-transform: rotate(45deg); transform: rotate(45deg); } } #keyframes rotate_anticlockwise { 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); } 100% { -webkit-transform: rotate(-90deg); transform: rotate(-90deg); } } #keyframes scale_down { 0% { -webkit-transform: scale(1); transform: scale(1); } 100% { -webkit-transform: scale(0.5); transform: scale(0.5); } } #keyframes pop_out_dots_top { 100% { transform: translate(0px, -80px); } } #keyframes pop_out_dots_bottom { 100% { transform: translate(0px, 80px); } } /* 1 */ .container.opened { animation: scale_down 250ms ease; transform-origin: 50% 50% 0; } /* 2 */ .container.opened .groups .extra-dot-top { animation: pop_out_dots_top 250ms ease; -webkit-animation-delay: 250ms; animation-delay: 250ms; transform-origin: 50% 50% 0; } .container.opened .groups .extra-dot-bottom { animation: pop_out_dots_bottom 250ms ease; -webkit-animation-delay: 250ms; animation-delay: 250ms; transform-origin: 50% 50% 0; } .container.opened .groups .group-2 { animation: rotate_anticlockwise 250ms ease; transform-origin: 50% 50% 0; -webkit-animation-delay: 250ms; animation-delay: 250ms; } /* 4 */ .container.opened .groups { animation: rotate_clockwise 250ms ease; transform-origin: 50% 50% 0; -webkit-animation-delay: 500ms; animation-delay: 500ms; } <div class="animation-container"> <div class="col-xs-12"> <?xml version="1.0" ?> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" enable-background="new 0 0 200 200"> <!-- Group 1 --> <g class="container opened"> <g class="groups"> <g class="group-1 pink"> <circle class="dot-pink-light extra-dot-top" cx="100" cy="21.4" r="21.4" /> <circle class="dot-pink-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" /> <circle class="dot-pink" cx="100" cy="21.4" r="21.4" /> <circle class="dot-pink" cx="100" cy="100" r="21.4" /> <circle class="dot-pink" cx="100" cy="178.6" r="21.4" /> </g> <!-- Group 2 --> <g class="group-2 green"> <circle class="dot-green-light extra-dot-top" cx="100" cy="21.4" r="21.4" /> <circle class="dot-green-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" /> <circle class="dot-green" cx="100" cy="21.4" r="21.4" /> <circle class="dot-green" cx="100" cy="100" r="21.4" /> <circle class="dot-green" cx="100" cy="178.6" r="21.4" /> </g> </g> </g> </svg> </div> </div>
Since you are looking for a toggle effect with only two distinct states, it is much better for you to use transitions instead of animations. Transitions can automatically produce the reverse effect when the class is removed. Demo with transitions: window.onload = function() { var btn = document.querySelector('button'); btn.addEventListener('click', function() { document.querySelector('.container').classList.toggle('opened'); }); } .animation-container { width: 250px; position: relative; margin: 0 auto; margin-top: 50px; } .dot-pink-light { fill: #CE97AE; } .dot-pink { fill: #D82566; } .dot-green-light { fill: #AFBF99; } .dot-green { fill: #77BC1F; } /* 1 */ .container { transform: scale(1); transition: transform 2.5s ease; transform-origin: 50% 50% 0; transition-delay: 5s; } .container.opened { transform: scale(0.5); transition-delay: 0s; } .container .groups .extra-dot-top { transform: translate(0px, 0px); transition: transform 2.5s ease; transition-delay: 2.5s; transform-origin: 50% 50% 0; } .container.opened .groups .extra-dot-top { transform: translate(0px, -80px); } .container .groups .extra-dot-bottom { transform: translate(0px, 0px); transition: transform 2.5s ease; transition-delay: 2.5s; transform-origin: 50% 50% 0; } .container.opened .groups .extra-dot-bottom { transform: translate(0px, 80px); } .container .groups .group-2 { transform: rotate(0deg); transition: transform 2.5s ease; transform-origin: 50% 50% 0; transition-delay: 2.5s; } .container.opened .groups .group-2 { transform: rotate(-90deg); } /* 4 */ .container .groups { transform: rotate(0deg); transition: transform 2.5s ease; transform-origin: 50% 50% 0; } .container.opened .groups { transform: rotate(45deg); transition-delay: 5s; } <div class="animation-container"> <div class="col-xs-12"> <?xml version="1.0" ?> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" enable-background="new 0 0 200 200"> <!-- Group 1 --> <g class="container"> <g class="groups"> <g class="group-1 pink"> <circle class="dot-pink-light extra-dot-top" cx="100" cy="21.4" r="21.4" /> <circle class="dot-pink-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" /> <circle class="dot-pink" cx="100" cy="21.4" r="21.4" /> <circle class="dot-pink" cx="100" cy="100" r="21.4" /> <circle class="dot-pink" cx="100" cy="178.6" r="21.4" /> </g> <!-- Group 2 --> <g class="group-2 green"> <circle class="dot-green-light extra-dot-top" cx="100" cy="21.4" r="21.4" /> <circle class="dot-green-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" /> <circle class="dot-green" cx="100" cy="21.4" r="21.4" /> <circle class="dot-green" cx="100" cy="100" r="21.4" /> <circle class="dot-green" cx="100" cy="178.6" r="21.4" /> </g> </g> </g> </svg> </div> </div> <button>Click</button> Animations on the other hand cannot automatically produce the reverse effect and code needs to be written. Even when the reverse animation's code is written, getting it work is complex (and cannot be done with pure CSS) because you will have to remove the "open" animation before adding the "close" animation and when the happens the element(s) will immediately snap to their original position before executing the reverse effect. The output wouldn't be as graceful as with transitions unless you put in a lot of messy code. Demo with animations: window.onload = function() { var btn = document.querySelector('button'); var container = document.querySelector('.container'); var groups = document.querySelector('.groups'); var group2 = document.querySelector('.group-2'); var extradtG = document.querySelector('.green .extra-dot-top'); var extradtP = document.querySelector('.pink .extra-dot-top'); var extradbG = document.querySelector('.green .extra-dot-bottom'); var extradbP = document.querySelector('.pink .extra-dot-bottom'); var opened = false; btn.addEventListener('click', function() { if (opened) { container.style.transform = 'scale(1)'; extradtG.style.transform = 'translate( 0px, 0px)'; extradtP.style.transform = 'translate( 0px, 0px)'; extradbG.style.transform = 'translate( 0px, 0px)'; extradbP.style.transform = 'translate( 0px, 0px)'; group2.style.transform = 'rotate(0deg);' groups.style.transform = 'rotate(0deg)'; container.classList.remove('opened'); container.clientHeight; // dummy call container.classList.add('closed'); } else { container.style.transform = 'scale(0.5)'; extradtG.style.transform = 'translate( 0px, -80px)'; extradtP.style.transform = 'translate( 0px, -80px)'; extradbG.style.transform = 'translate( 0px, 80px)'; extradbP.style.transform = 'translate( 0px, 80px)'; group2.style.transform = 'rotate(-90deg);' groups.style.transform = 'rotate(45deg)'; container.classList.remove('closed'); container.clientHeight; // dummy call container.classList.add('opened'); } opened = !opened; }); } .animation-container { width: 250px; position: relative; margin: 0 auto; margin-top: 50px; } .dot-pink-light { fill: #CE97AE; } .dot-pink { fill: #D82566; } .dot-green-light { fill: #AFBF99; } .dot-green { fill: #77BC1F; } /* ANIMATIONS */ #keyframes rotate_clockwise { 0% { transform: rotate(0deg); } 100% { transform: rotate(45deg); } } #keyframes rotate_anticlockwise { 0% { transform: rotate(0deg); } 100% { transform: rotate(-90deg); } } #keyframes scale_down { 0% { transform: scale(1); } 100% { transform: scale(0.5); } } #keyframes pop_out_dots_top { 0% { transform: translate(0px, 0px); } 100% { transform: translate(0px, -80px); } } #keyframes pop_out_dots_bottom { 0% { transform: translate(0px, 0px); } 100% { transform: translate(0px, 80px); } } /* 1 */ .container.opened { animation: scale_down 2.5s ease; transform-origin: 50% 50% 0; } .container.closed { animation: scale_down 2.5s ease reverse backwards; transform-origin: 50% 50% 0; animation-delay: 5s; } /* 2 */ .container.opened .groups .extra-dot-top { animation: pop_out_dots_top 2.5s ease backwards; animation-delay: 2.5s; transform-origin: 50% 50% 0; } .container.closed .groups .extra-dot-top { animation: pop_out_dots_top 2.5s ease reverse backwards; animation-delay: 2.5s; transform-origin: 50% 50% 0; } .container.opened .groups .extra-dot-bottom { animation: pop_out_dots_bottom 2.5s ease backwards; animation-delay: 2.5s; transform-origin: 50% 50% 0; } .container.closed .groups .extra-dot-bottom { animation: pop_out_dots_bottom 2.5s ease reverse backwards; animation-delay: 2.5s; transform-origin: 50% 50% 0; } .container.opened .groups .group-2 { animation: rotate_anticlockwise 2.5s ease backwards; transform-origin: 50% 50% 0; animation-delay: 2.5s; } .container.closed .groups .group-2 { animation: rotate_anticlockwise 2.5s ease reverse backwards; transform-origin: 50% 50% 0; animation-delay: 2.5s; } /* 4 */ .container.opened .groups { animation: rotate_clockwise 2.5s ease backwards; transform-origin: 50% 50% 0; animation-delay: 5s; } .container.closed .groups { animation: rotate_clockwise 2.5s ease reverse backwards; transform-origin: 50% 50% 0; } <div class="animation-container"> <div class="col-xs-12"> <?xml version="1.0" ?> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" enable-background="new 0 0 200 200"> <!-- Group 1 --> <g class="container"> <g class="groups"> <g class="group-1 pink"> <circle class="dot-pink-light extra-dot-top" cx="100" cy="21.4" r="21.4" /> <circle class="dot-pink-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" /> <circle class="dot-pink" cx="100" cy="21.4" r="21.4" /> <circle class="dot-pink" cx="100" cy="100" r="21.4" /> <circle class="dot-pink" cx="100" cy="178.6" r="21.4" /> </g> <!-- Group 2 --> <g class="group-2 green"> <circle class="dot-green-light extra-dot-top" cx="100" cy="21.4" r="21.4" /> <circle class="dot-green-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" /> <circle class="dot-green" cx="100" cy="21.4" r="21.4" /> <circle class="dot-green" cx="100" cy="100" r="21.4" /> <circle class="dot-green" cx="100" cy="178.6" r="21.4" /> </g> </g> </g> </svg> </div> </div> <button>Click</button> (The animation version has a dummy call container.clientHeight which is done to make sure that there is a repaint between the removal of one animation and addition of another. Else, it would look as though nothing happened. You can find more details in my answer here.)
CSS how to revert SVG animation on mouseout from current frame
I'm doing some button animation with SVG and can't make it to work exactly I want. I tried find same case but no luck. So I end up here, because I spend too much time on this already. Any help would be much appreciated. Here is the code: http://jsfiddle.net/wq4djg9z/2/ It works fine, but with one flaw. It's always starts animation from fixed value. #button-border { stroke-dasharray: 150; stroke-dashoffset: 150; stroke-width: 4px; -webkit-animation: dash-back 1.0s linear; fill: none; pointer-events: all; } #button-border:hover { -webkit-animation: dash 1.0s linear forwards; pointer-events: all; } #-webkit-keyframes dash { to { stroke-dashoffset: 0; } } #-webkit-keyframes dash-back { from { stroke-dashoffset: 0; } to { stroke-dashoffset: 150; } } Is there a way to start animation from current animation frame when mouse out the button to smooth animation?
What about using transitions instead of animations to do the reverse part ? #button-border { stroke-dasharray: 150; stroke-dashoffset: 150; stroke-width: 4px; -webkit-animation: dash-back 1.0s linear; animation: dash-back 1.0s linear; fill: none; pointer-events: all; transition: stroke-dashoffset 1s linear; -webkit-transition: stroke-dashoffset 1s linear; } #button-border:hover { stroke-dashoffset: 0; pointer-events: all; } #-webkit-keyframes dash-back { from { stroke-dashoffset: 0; } to { stroke-dashoffset: 150; } } #keyframes dash-back { from { stroke-dashoffset: 0; } to { stroke-dashoffset: 150; } } <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100.00000" height="50.00000" id="svg1" version="1.1" viewBox="0 0 100 50" enable-background="new 0 0 100 50" xml:space="preserve"> <style type="text/css"> <![CDATA[]]> </style> <g id="button-border"> <path class="path" style="fill:none;stroke:#000000;stroke-opacity:1" d="m 100,50.0 0,-50.00000 -100,00.00000" id="path2983" /> <path class="path" style="fill:none;stroke:#000000;stroke-opacity:1" d="m 0,0 0,50 100,0" id="path2984" /> <text x="30" y="30" font-family="Verdana" font-size="15" fill="blue">Hello</text> </g> </svg>