How to animate clipping paths defined in SVG elements? - html

I know how to animate a clip-path defined directly in CSS, but I don't understand how to do it when the clip-path is referenced from an SVG clipPath element.
I have been experimenting with simple clip-path animations using just CSS, until I realized you can't define a compound-path as a clip-path directly there, so I turned to SVG's clipPath which allows defining multiple paths. But then the animation doesn't work, that is, there is no smooth transition.
Here is what I'm trying...
HTML
<svg>
<defs>
<clipPath id="shape--start">
<polygon points="0,100 22.222,133.333 8.333,147.222 -13.889,113.889 -47.222,91.667 -33.333,77.778"/>
</clipPath>
<clipPath id="shape--end">
<polygon points="144.444,-44.444 166.667,-11.111 152.778,2.778 130.556,-30.556 97.222,-52.778 111.111,-66.667"/>
</clipPath>
</defs>
</svg>
CSS
#keyframes shape {
0% { clip-path: url(#shape--start) }
100% { clip-path: url(#shape--end) }
}
To clarify more, if I use something like
CSS
#keyframes shape {
0% { clip-path: polygon(-44% 5%, -14% 5%, 15% 95%, -15% 95%) }
100% { clip-path: polygon(90% 5%, 120% 5%, 149% 95%, 119% 95%) }
}
it works as expected, but I would like to use SVG for the more complex compound paths.
Thanks for your time and any help in advance!

You need to animate the SVG itself using animate
.box {
width:300px;
height:200px;
background:red;
clip-path: url(#shape--start);
}
<svg width=0 height=0>
<defs>
<clipPath id="shape--start">
<polygon points="0,100 22.222,133.333 8.333,147.222 -13.889,113.889 -47.222,91.667 -33.333,77.778">
<animate attributeType="XML" attributeName="points"
from="0,100 22.222,133.333 8.333,147.222 -13.889,113.889 -47.222,91.667 -33.333,77.778"
to="144.444,-44.444 166.667,-11.111 152.778,2.778 130.556,-30.556 97.222,-52.778 111.111,-66.667"
dur="2s" repeatCount="indefinite"/>
</polygon>
</clipPath>
</defs>
</svg>
<div class="box">
</div>

Animation option using animateTransform
.box {
width:300px;
height:200px;
background:red;
clip-path: url(#shape--start);
}
<svg width="0" height="0">
<defs>
<clipPath id="shape--start">
<polygon points="0,100 22.222,133.333 8.333,147.222 -13.889,113.889 -47.222,91.667 -33.333,77.778">
<animateTransform attributeType="XML" attributeName="transform" type="translate"
values="0,100;144.444,-44.444"
dur="2s" repeatCount="indefinite"/>
</polygon>
</clipPath>
</defs>
</svg>
<div class="box">
</div>
Roundtrip animation
.box {
width:300px;
height:200px;
background:red;
clip-path: url(#shape--start);
}
<svg width="0" height="0">
<defs>
<clipPath id="shape--start">
<polygon points="0,100 22.222,133.333 8.333,147.222 -13.889,113.889 -47.222,91.667 -33.333,77.778">
<animateTransform attributeType="XML" attributeName="transform" type="translate"
values="0,100;144.444,-44.444;0,100"
dur="2s" repeatCount="indefinite"/>
</polygon>
</clipPath>
</defs>
</svg>
<div class="box">
</div>

Related

How to make an animation visible only within certain areas of an SVG?

I hope you can help me out. I am trying to add a "shine" animation to my SVG, but I only want the animation to be visible in certain parts of my SVG, and I'm not sure how to go about doing this.
I have posted what I have so far below.
I want the white "shine" animation to only be visible within the blue arrow polygons, and not visible in the orange background.
Any help would be appreciated! Thanks!
.shine {
background: orange -webkit-gradient(linear, left top, right top, from(#222), to(#222), color-stop(0.5, #fff)) 0 0 no-repeat;
background-image: -webkit-linear-gradient(-40deg, transparent 0%, transparent 40%, #fff 50%, transparent 60%, transparent 100%);
-webkit-background-size: 200%;
-webkit-animation-name: shine;
-webkit-animation-duration: 3s;
-webkit-animation-iteration-count: infinite;
}
#-webkit-keyframes shine {
0% {
background-position: 150%
}
100% {
background-position: -50%
}
}
<svg class='shine'>
<polygon fill="blue" class='arrow-top' points='37.6,27.9 1.8,1.3 3.3,0 37.6,25.3 71.9,0 73.7,1.3'></polygon>
<polygon fill="blue" class='arrow-middle' points='37.6,45.8 0.8,18.7 4.4,16.4 37.6,41.2 71.2,16.4 74.5,18.7'></polygon>
<polygon fill="blue" class='arrow-bottom' points='37.6,64 0,36.1 5.1,32.8 37.6,56.8 70.4,32.8 75.5,36.1'></polygon>
</svg>
Here is an example where I use <animate> on a <linearGradient>. The gradient is used on a mask that masks off the three polygons.
<svg width="200" viewBox="0 0 75.5 65" class="shine" fill="url(#g1)">
<defs>
<linearGradient id="g1" x1="-100" x2="-50" gradientTransform="rotate(40)" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="#fff" />
<stop offset="50%" stop-color="#222" />
<stop offset="100%" stop-color="#fff" />
<animate
attributeName="x1"
values="-100;100"
dur="3s"
repeatCount="indefinite" />
<animate
attributeName="x2"
values="-50;250"
dur="3s"
repeatCount="indefinite" />
</linearGradient>
<mask id="m1">
<rect transform="translate(0 0)" width="100%" height="100%" fill="url(#g1)"/>
</mask>
</defs>
<g mask="url(#m1)">
<polygon fill="blue" class='arrow-top' points='37.6,27.9 1.8,1.3 3.3,0 37.6,25.3 71.9,0 73.7,1.3'></polygon>
<polygon fill="blue" class='arrow-middle' points='37.6,45.8 0.8,18.7 4.4,16.4 37.6,41.2 71.2,16.4 74.5,18.7'></polygon>
<polygon fill="blue" class='arrow-bottom' points='37.6,64 0,36.1 5.1,32.8 37.6,56.8 70.4,32.8 75.5,36.1'></polygon>
</g>
</svg>

how to make an svg colour change with time

I have this SVG path line down below that has two circles moving with a specific duration of time from one end to another. Is is possible to change the colour of the blue circle so it would be blue in the start, after 20s, it would start going white, then it would go to orange(from white)when it has 20 more seconds to go to reach the end, while the red circle would change its own colour depending on the colour of the circle and then adding a glow behind the current blue moving circle that would be the color of the current blue circle?
Does this mean the whole has to be made with javascript or how do I have to amend the HTML so it would function such way as described?
<svg width="450" height="450">
<path id="motionPath2"
d="M 50 200 L 400 200 "
stroke="
none" fill="transparent" />
<circle class="circle" r=20 fill=#ff0000 z-index=55>
<animateMotion dur="100s" repeatCount="indefinite"
rotate="auto">
<mpath href="#motionPath2" />
</animateMotion>
</circle>
<path id="motionPath"
d="M 50 200 L 400 200 "
stroke="
black" fill="transparent" />
<circle class="circle" r=5 fill=#45b6fe z-index=55>
<animateMotion dur="100s" repeatCount="indefinite"
rotate="auto">
<mpath href="#motionPath" />
</animateMotion>
</circle>
</svg>
You can introduce CSS animation where you can easily handle the coloration.
Here is a basic example to illustrate the idea:
#keyframes color {
from {
fill: red;
}
to {
fill: green;
}
}
#big {
animation: color 20s linear infinite;
}
<svg width="450" height="450">
<path id="motionPath2"
d="M 50 200 L 400 200 "
stroke="
none" fill="transparent" />
<circle class="circle" id="big" r=20 fill=#ff0000 z-index=55>
<animateMotion dur="20s" repeatCount="indefinite"
rotate="auto">
<mpath href="#motionPath2" />
</animateMotion>
</circle>
<path id="motionPath"
d="M 50 200 L 400 200 "
stroke="
black" fill="transparent" />
<circle class="circle" r=5 fill=#45b6fe z-index=55>
<animateMotion dur="20s" repeatCount="indefinite"
rotate="auto">
<mpath href="#motionPath" />
</animateMotion>
</circle>
</svg>
and since it's about a simple geometry you can easily do this using only CSS without SVG
.box {
margin:100px;
height:2px;
background:green;
position:relative;
}
.box:before,
.box:after{
content:"";
position:absolute;
width:80px;
height:80px;
border-radius:50%;
left:0;
top:0;
transform:translate(-50%,-50%);
background:red;
animation:move 10s linear infinite alternate;
animation-name:move,color,glow;
}
.box:after {
width:20px;
height:20px;
background:blue;
}
#keyframes move {
to {
left:100%;
}
}
#keyframes color {
to {
background:yellow;
}
}
#keyframes glow {
to {
box-shadow:0 0 30px yellow;
}
}
<div class="box">
</div>
This is a partial answer to your question because I understand it only in part. I hope after seeing the answer you'll be able to formulate a better question.
Changes I've made:
You are using an animation for every circle but since the path is the same and the animation are identical I've putted both circles in a group and I'm animating the circle.
Also since the path is a line I could have used animateTransform ... type="translate" instead. However you may want to change the path to something more complicated so I'm sticking with animateMotion.
In order to animate the color you can use <animate> to animate the fill, and use the values attribute for the colors: values="red;white;orange"
Since you mention that the last color should apear 20seconds before the animation ends I'm using keyTimes= "0; 0.8; 1". Please note that the keyTimes attribute has the same number of values as the values attribute and represents a list of time values used to control the pacing of the animation.
<svg width="450" height="450">
<path id="motionPath2" d="M 50 200 L 400 200 "
stroke="black" fill="transparent" />
<g>
<circle class="circle" r="20" fill="#ff0000"></circle>
<circle class="circle" r=5 fill="#45b6fe" >
<animate
attributeName="fill"
attributeType="XML"
values="#45b6fe;white;orange"
keyTimes= "0; 0.8; 1"
dur="100s"
repeatCount="indefinite"/>
</circle>
<animateMotion dur="100s" repeatCount="indefinite">
<mpath href="#motionPath2" />
</animateMotion>
</g>
</svg>

Flexible rotating centered SVG

I need flexible rotating centered SVG.
Problem is if use
<svg width="100%">
with rotation, browser window start resizing itself on svg rotation.
If i delete "width="100%"", than SVG will svg will not shrink on horizontal window resize.
Any ideas how to fix it?
Codesandbox example.
Putting the animation inside the svg is a solution.
<svg
viewBox="0 0 29.892 29.892"
width="100%"
height="100vh"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<g>
<path
d="m14.946 0c-8.254 0-14.946 6.692-14.946 14.946 0 8.255 6.692 14.946 14.946 14.946s14.946-6.691 14.946-14.946c-1e-3 -8.254-6.692-14.946-14.946-14.946zm0 26.58c-6.425 0-11.634-5.208-11.634-11.634 0-6.425 5.209-11.634 11.634-11.634s11.633 5.209 11.633 11.634c0 6.426-5.208 11.634-11.633 11.634z"
opacity=".2"
/>
<path d="m20.758 4.878 1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012v3.312c2.119 0 4.1 0.576 5.812 1.566z"/>
<animateTransform repeatCount="indefinite" begin="0s" dur="5s" attributeName="transform" type="rotate" from="0 14.946 14.946" to="360 14.946 14.946" />
</g>
</svg>
If you want css to control the animation, you'd still have to group the paths within the svg. You can then target the group in css like below.
#circle {
animation: rotate 2s linear infinite;
transform-origin: 50% 50%
}
#keyframes rotate {
to {
transform: rotate(360deg);
}
}
<svg
viewBox="0 0 29.892 29.892"
width="100%"
height="100vh"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<g id="circle">
<path
d="m14.946 0c-8.254 0-14.946 6.692-14.946 14.946 0 8.255 6.692 14.946 14.946 14.946s14.946-6.691 14.946-14.946c-1e-3 -8.254-6.692-14.946-14.946-14.946zm0 26.58c-6.425 0-11.634-5.208-11.634-11.634 0-6.425 5.209-11.634 11.634-11.634s11.633 5.209 11.633 11.634c0 6.426-5.208 11.634-11.633 11.634z"
opacity=".2"
/>
<path d="m20.758 4.878 1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012v3.312c2.119 0 4.1 0.576 5.812 1.566z" />
</g>
</svg>

How to animate a SVG polygon to fill?

I have a SVG letter (A) that consists of two polygon and a rectangle. I want to animate them in a way that the first polygon grows to visible and then the second one. After that, the rectangle will grow to be visible. Before the start of the animation, the SVG will not be visible.
I have tried keyframe strokes but as they are not path based but points of polygon, it didn't work.
<svg height="600" width="800">
<polygon points="34 537,150 536,289 130,314 53,196 51"/>
<animate attributeName="points" dur="5s" fill="freeze" />
<polygon points="411 537,528 537,364 118,354 91,348 72,341 53,327 53,223 55"/>
<rect x="120" y="320" stroke-miterlimit="10" width="270" height="120"/>
</svg>
Here is a pen if you want to work on it : https://codepen.io/anon/pen/vMxXaP
You can still draw the (A) letter by using polygons with stroke instead of fill. The following example uses two keyframe animations on stroke-dasharray to draw the A letter in two steps :
First step for the top left and top right line (first polygon element in the svg)
Second step for the horizontal line closing the A (second polygon in the svg element)
.letter {
width:200px;height:auto;
stroke-width:2.5;
stroke:#000;
fill:none;
stroke-dasharray: 0 24;
}
.animateFirst { animation: 0.5s animateFirst ease-in forwards; }
.animateSecond { animation: 0.2s 0.45s animateSecond ease-out forwards; }
#keyframes animateFirst {
to { stroke-dasharray: 24 24; }
}
#keyframes animateSecond {
to { stroke-dasharray: 6 24; }
}
<svg class="letter" viewbox="0 0 12 10">
<polygon class="animateFirst" points="1,11.5 6,0 11,11.5" />
<polygon class="animateSecond" points="3,6.5 9,6.5" />
</svg>
Bonus version. Here i turned your paths into mask and added background animation.
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 600 800">
<style>
svg {
height:160px;
background: url(https://i.imgur.com/Pr8tfnT.png);
background-position: 0px 111px;
background-repeat: repeat-x;
background-size: 100%;
animation: water 10s forwards;
}
#keyframes water {
100% {
background-position: 2000px 0px;
}
}
</style>
<mask id="mask" fill="black">
<rect fill="white" width="600" height="800"/>
<polygon id="right" points="411 537,528 537,364 118,354 91,348 72,341 53,327 53,223 55"/>
<polygon id="left" points="34 537,150 536,289 130,314 53,196 51"/>
<rect id="rect1" x="120" y="320" stroke-miterlimit="10" width="270" height="120"/>
</mask>
<rect fill="white" width="600" height="800" mask="url(#mask)"/>
</svg>
SVG solution
Rotation and appearance animation
.container {
width:35%;
height:35%;
}
<div class="container">
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 600 800">
<g fill="black" fill-opacity="0" >
<polygon
id="left" transform="rotate(72 306 200)" points="34 537,150 536,289 130,314 53,196 51">
<animateTransform
attributeName="transform"
type="rotate"
values="72 306 200;0 306 200"
begin="svg1.click"
dur="0.5s"
fill="freeze" />
<animate
id="an_op1"
attributeName="fill-opacity"
from="0"
to="1"
begin="svg1.click"
dur="0.5s"
fill="freeze" />
</polygon>
<polygon id="right" transform="rotate(-69 457.5 200)"
points="411 537,528 537,364 118,354 91,348 72,341 53,327 53,223 55">
<animateTransform
attributeName="transform"
type="rotate"
values="-69 457.5 200;0 457.5 200"
begin="an_op1.end"
dur="0.5s"
fill="freeze" />
<animate
id="an_op2"
attributeName="fill-opacity"
from="0"
to="1"
begin="an_op1.end"
dur="0.5s"
fill="freeze" />
</polygon>
<rect id="rect1" x="800" y="320" width="270" height="120">
<animate
attributeName="x"
from="800"
to="120"
begin="an_op2.end"
dur="0.5s"
fill="freeze" />
<animate
id="an_op3"
attributeName="fill-opacity"
from="0"
to="1"
begin="an_op2.end"
dur="0.5s"
fill="freeze" />
</rect>
</g>
<text x="0" y="80" font-size="50" fill="purple">Click me</text>
</svg>
</div>
Second solution
All animation elements are invisible at the beginning. fill-opacity="0"
Item appearance Animation:
<animate
id="an_left"
attributeName="fill-opacity"
begin="1s"
from="0"
to="1"
dur="0.3s"
fill="freeze"/>
Below is the full code:
.container {
width:35%;
height:35%;
}
<div class="container">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 600 800">
<polygon id="right" fill="#008080" fill-opacity="0"
points="411 537,528 537,364 118,354 91,348 72,341 53,327 53,223 55">
<animate
id="an_right"
attributeName="fill-opacity"
begin="an_left.end"
from="0"
to="1"
dur="0.3s"
fill="freeze"/>
</polygon>
<polygon id="left" fill="#008080" fill-opacity="0" points="34 537,150 536,289 130,314 53,196 51">
<animate
id="an_left"
attributeName="fill-opacity"
begin="0.2s"
from="0"
to="1"
dur="0.3s"
fill="freeze"/>
</polygon>
<rect x="120" y="320" fill="#008080" fill-opacity="0" stroke-miterlimit="10" width="270" height="120">
<animate
id="an_rect"
attributeName="fill-opacity"
from="0"
to="1"
begin="an_right.end"
dur="0.3s"
fill="freeze"/>
</rect>
</svg>
</div>
The sequence of animations is achieved by a chain of conditions in the attribute - begin="an_left.end"
Such a record means that the animation of the right rectangle will begin only after the end of the animation of the left polygon.
CSS solution
.container {
width:35%;
height:35%;
}
#left,#right, #rect1 {
fill-opacity:0;
fill:#008080;
}
#left {
animation:anLeft 0.3s ease forwards;
animation-delay: 0.1s;
}
#keyframes anLeft {
100% {
fill-opacity:1;
}
}
#right {
animation:anRight 0.3s ease forwards;
animation-delay: 0.4s;
}
#keyframes anRight {
100% {
fill-opacity:1;
}
}
#rect1 {
animation:anRect 0.3s ease forwards;
animation-delay:0.7s;
}
#keyframes anRect {
100% {
fill-opacity:1;
}
}
<div class="container">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 600 800">
<polygon id="right"
points="411 537,528 537,364 118,354 91,348 72,341 53,327 53,223 55"/>
<polygon id="left" points="34 537,150 536,289 130,314 53,196 51"/>
<rect id="rect1" x="120" y="320" stroke-miterlimit="10" width="270" height="120"/>
</svg>
</div>
I solved this using CSS keyframes, is this what you're looking for?
#keyframes fade {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#right {
animation-delay: 1s;
}
#center {
animation-delay: 2s;
}
.shape {
opacity: 0;
animation-fill-mode: forwards;
animation-iteration-count: 1;
animation-name: fade;
animation-duration: 1s;
}
<svg id="abcdef" height="600" width="800">
<polygon class="shape" points="34 537,150 536,289 130,314 53,196 51"/>
<polygon id="right" class="shape" points="411 537,528 537,364 118,354 91,348 72,341 53,327 53,223 55"/>
<rect id="center" class="shape" x="120" y="320" filter="#008080" stroke-miterlimit="10" width="270" height="120"/>
</svg>
If you want to tweak the duration of the animation you have to look at changing the values of animation-delay and animation-duration.
Here an example with pure javascript and changing opacity by delta time
let left = document.querySelector('#left')
let right = document.querySelector('#right')
let rect1 = document.querySelector('#rect1')
let time = 3000; // animation time
let delay = 1000; // animation delay
// dt - time from animation start
function animate(dt) {
let v = dt - delay;
opacity(left, v/time*3);
opacity(right, v/time*3 - 1);
opacity(rect1, v/time*3 - 2);
dt < time + delay + 50 && requestAnimationFrame(animate)
}
function opacity(el, v) {
v = Math.min(1, Math.max(v, 0)); // clamp to 0-1
el.setAttribute('opacity', v)
}
requestAnimationFrame(animate);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" height="175" viewBox="0 0 600 800">
<g fill="#008080">
<polygon id="right" opacity="0" points="411 537,528 537,364 118,354 91,348 72,341 53,327 53,223 55"/>
<polygon id="left" opacity="0" points="34 537,150 536,289 130,314 53,196 51"/>
<rect id="rect1" opacity="0" x="120" y="320" stroke-miterlimit="10" width="270" height="120"/>
</g>
</svg>
You can indeed use keyframes, in there there a lot of things to do besides just the opacity. You can animate drawing the outlines with stroke-dashoffset and stroke-dasharray. There are also ways to let them fade in from let and right with translateX or translateY. Also rotation animations.
take a look at the css in the pen i made: https://codepen.io/YilmazTut/pen/JzaQEy .
there also is a series on svg's from css tricks: https://css-tricks.com/lodge/svg/
i used that to create the logo in my pen. from about tutorial 16 he explains how animations and later on also pathdrawing works. I hope you can find your way there!

Rotating SVG with CSS from bottom of group

I am trying create some kind of gauge animation. I added two simple gauges inside a rectangel . When I try to rotate a needle it doesn't rotate around its bottom part. Instead it rotates around another point even though I state to rotate around bottom center. What should I do to rotate the needle from bottom? Thanks.
EDIT:
Here is the animation I am trying to achieve
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<style>
#Gaugaetip2 {
animation: dance 2s infinite alternate;
}
#keyframes dance {
100% {
transform-origin: bottom center;
transform: rotate(-25deg);
}
}
</style>
</head>
<body>
<svg width="135px" height="135px" viewBox="0 0 135 135" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>test</title>
<defs>
<path d="M17.6298701,13.9630295 L17.6298701,4.43831169 L15.6298701,4.43831169 L15.6298701,13.9630295 C14.6733943,14.3565661 14,15.2976952 14,16.3961039 C14,17.8485411 15.177433,19.025974 16.6298701,19.025974 C18.0823073,19.025974 19.2597403,17.8485411 19.2597403,16.3961039 C19.2597403,15.2976952 18.5863459,14.3565661 17.6298701,13.9630295 L17.6298701,13.9630295 Z" id="path-1"></path>
<path d="M18.91403,13.9099151 L18.91403,4.38519729 L16.91403,4.38519729 L16.91403,13.9099151 C15.9575542,14.3034517 15.2841598,15.2445808 15.2841598,16.3429895 C15.2841598,17.7954267 16.4615928,18.9728596 17.91403,18.9728596 C19.3664671,18.9728596 20.5439001,17.7954267 20.5439001,16.3429895 C20.5439001,15.2445808 19.8705058,14.3034517 18.91403,13.9099151 L18.91403,13.9099151 Z" id="path-3"></path>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="test" transform="translate(-30.000000, -30.000000)">
<g transform="translate(30.000000, 30.000000)">
<rect id="background" fill="#4BBCE9" x="0" y="0" width="135" height="135" rx="8"></rect>
<g id="Gauge" transform="translate(5.136364, 8.642857)">
<g id="Group-3" transform="translate(0.149351, 0.383117)">
<ellipse id="Oval-3" stroke="#D8D8D8" fill="#FFFFFF" cx="16.6298701" cy="16.3961039" rx="15.7792208" ry="15.7792208"></ellipse>
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="Gaugaetip2" fill="#D8D8D8" xlink:href="#path-1"></use>
</g>
</g>
<g id="Gauge-Copy-3" transform="translate(95.551948, 9.642857)">
<ellipse id="Oval-3" stroke="#D8D8D8" fill="#FFFFFF" cx="15.7792208" cy="15.7792208" rx="15.7792208" ry="15.7792208"></ellipse>
<mask id="mask-4" fill="white">
<use xlink:href="#path-3"></use>
</mask>
<use id="Gaugetip" fill="#D8D8D8" transform="translate(17.914030, 11.679028) rotate(25.000000) translate(-17.914030, -11.679028) " xlink:href="#path-3"></use>
</g>
</g>
</g>
</g>
</svg>
</body>
</html>
Try adding the transform-origin to the element itself. As this is a fixed property that does not change over time, it shouldn't be part of the keyframes.
#Gaugaetip2 {
animation: dance 2s infinite alternate;
transform-origin: center 84%;
transform-box: fill-box;
}
#keyframes dance {
100% {
transform: rotate(-25deg);
}
}
I also adjusted the origin position a little to stay centered on the round part.
Result: https://jsfiddle.net/dowm6eff/