Reputation: 7360
I want to move SVG elements across their container using CSS keyframes.
If I had just a <circle />
, I could simply use the cx
/ cy
properties in the keyframe definition. But what if I had an arbitrary group (<g />
)? A group doesn't have cx
/ cy
, and it seems that I have to define a unit (like px
) if I wanted to use CSS' transform: translate(x,y)
.
MWE (how do I animate the bar
group?):
svg {
padding: 5px;
width: 150px;
height: 150px;
border: 1px solid #000;
}
.foo {
animation-duration: 3s;
animation-iteration-count: infinite;
animation-name: moveFoo;
}
.bar {
animation-duration: 3s;
animation-iteration-count: infinite;
animation-name: moveBar;
}
@keyframes moveFoo {
from {
cx: 10;
cy: 10;
}
to {
cx: 90;
cy: 90;
}
}
/* how to define this? */
@keyframes moveBar { }
<svg viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<circle class="foo" r="5" fill="red" />
<g class="bar" transform="translate(90 10)">
<circle r="5" fill="blue" />
<text
y="1"
text-anchor="middle"
fill="white"
font-family="monospace"
font-size="5">
AB
</text>
</g>
</svg>
Upvotes: 6
Views: 744
Reputation: 29463
it seems that I have to define a unit (like px) if I wanted to use CSS' transform: translate(x,y).
Yes, it's true, you do.
But that won't be an issue, if you have already declared a viewbox
attribute in the <svg>
element.
If you have declared a viewbox
, 1px
will represent 1 viewbox unit.
Working Example:
svg {
padding: 5px;
width: 150px;
height: 150px;
border: 1px solid #000;
}
.foo {
fill: red;
transform: translate(10px, 10px);
animation-duration: 3s;
animation-iteration-count: infinite;
animation-name: moveFoo;
}
.bar {
transform: translate(90px, 10px);
animation-duration: 3s;
animation-iteration-count: infinite;
animation-name: moveBar;
}
.bar circle {
fill: blue;
}
.bar text {
fill: white;
font-family: monospace;
font-size: 5px;
text-anchor: middle;
}
@keyframes moveFoo {
0% {transform: translate(10px, 10px);}
50% {transform: translate(90px, 90px);}
100% {transform: translate(10px, 10px);}
}
@keyframes moveBar {
0% {transform: translate(90px, 10px);}
50% {transform: translate(10px, 90px);}
100% {transform: translate(90px, 10px);}
}
<svg viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<circle class="foo" r="5" />
<g class="bar">
<circle r="5" />
<text y="1">AB</text>
</g>
</svg>
Upvotes: 2
Reputation: 33044
If you need to use @keyframes
instead of animating the cx and cy attributes you have to animate from transform:translate(0,0)
to transform:translate(90px,90px)
(for example.)
Otherwise Temani Afif's answer is perfectly valid. `
svg {
padding: 5px;
width: 150px;
height: 150px;
border: 1px solid #000;
}
.foo {
transform:translate(0,0);
animation-duration: 3s;
animation-iteration-count: infinite;
animation-name: moveFoo;
}
.bar {
transform:translate(0,0);
animation-duration: 3s;
animation-iteration-count: infinite;
animation-name: moveBar;
}
@keyframes moveFoo {
from {
transform:translate(0,0)
}
to {
transform:translate(90px,90px)
}
}
/* how to define this? */
@keyframes moveBar {
from {
transform:translate(0,0)
}
to {
transform:translate(90px,90px)
}
}
<svg viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<circle class="foo" r="5" fill="red" />
<g class="bar" >
<circle r="5" fill="blue" cx="10" cy="10" />
<text
x="10"
y="11"
text-anchor="middle"
fill="white"
font-family="monospace"
font-size="5">
AB
</text>
</g>
</svg>
Upvotes: 1
Reputation: 272909
Use animateTransform
to do this:
svg {
padding: 5px;
width: 150px;
height: 150px;
border: 1px solid #000;
}
<svg viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<circle class="foo" r="5" fill="red" />
<g id="bar" transform="translate(90 10)">
<circle r="5" fill="blue" />
<text
y="1"
text-anchor="middle"
fill="white"
font-family="monospace"
font-size="5">
AB
</text>
</g>
<animateTransform xlink:href="#bar"
attributeName="transform"
type="translate"
from="90,10" to="90,90"
dur="2" repeatCount="indefinite"/>
</svg>
Upvotes: 4