SVG animateMotion (calcMode spline) not working in FF and Safari - animation

I want to move a circle along a path inside an svg with different easing. I wanted to use animateMotion but have never used it before. Using JS is not an option in this case.
It works fine in Chrome and Opera, but not in Safari and Firefox.
<animateMotion
dur="4s"
repeatCount="indefinite"
calcMode="spline"
keySplines="0 0 0.5 1 ; 0 0 0.5 1 ; 0.3 0 1 1"
keyTimes="0 ; 0.3 ; 0.6 ; 1"
path="M54,183.8c0-86.5,128.5-87.2,128.5,0c0-86.5,116.9-87.2,116.9,0c0-86.5,115.1-87.2,115.1,0
c0-86.5,55.5-123.5,55.5,111" />
If I remove calcMode, keySplines and keyTimes it works in all browsers.
I would also appreciate any alternative solution for moving an element on rounded curves with different easings.

Solution
I figured out, that two things were independently from each other creating the issue:
Safari does not accept spaces between KeyTimes Values (all other browsers do, and Safari also does within KeySplines).
Firefox seems to need one more value for KeyTimes and KeySplines. So I added one value to each line.
Fixed Code:
keySplines="0 0 0.5 1 ; 0 0 0.5 1 ; 0 0 0.5 1 ; 0 0 0.5 1"
keyTimes="0;0.2;0.4;0.6;1"
Full Example:
<svg version="1.1" id="Layer_5" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 500 500" style="enable-background:new 0 0 500 500;" xml:space="preserve">
<g>
<circle r="13.5" fill="black">
<animateMotion
dur="4s"
repeatCount="indefinite"
calcMode="spline"
keySplines="0 0 0.5 1 ; 0 0 0.5 1 ; 0 0 0.5 1 ; 0 0 0.5 1"
keyTimes="0;0.2;0.4;0.6;1"
path="M54,183.8c0-86.5,128.5-87.2,128.5,0c0-86.5,116.9-87.2,116.9,0c0-86.5,115.1-87.2,115.1,0c0-86.5,55.5-123.5,55.5,111" />
</circle>
<path stroke="red" fill="none" d="M54,183.8c0-86.5,128.5-87.2,128.5,0c0-86.5,116.9-87.2,116.9,0c0-86.5,115.1-87.2,115.1,0c0-86.5,55.5-123.5,55.5,111"/>
</g>
</svg>

Related

What am I doing wrong trying to rotate some SVG through an animateTransform tag with "spline" calcmode?

I'm trying to animate a triangle so that its rotation accelerates (and later comes to a stop after a full rotation) and I am trying to use the animateTransform SVG tag, with the calcmode attribute set to "spline".. I can easily get the triangle to rotate with a continuous motion, but it's not the smooth acceleration I'm looking for.
Here is the code I'm using - when viewing this in Firefox it shows no animation at all :
<svg xml:lang="fr" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<style type="text/css">
<![CDATA[
*{
fill:none;
stroke:black;
}
]]>
</style>
<g class="triangle">
<path d="M 349.9999999999999 163.3974596215561 L 200 250.00000000000006 " />
<path d="M 200 250.00000000000006 L 350 336.60254037844385 " />
<path d="M 350 336.60254037844385 L 349.9999999999999 163.3974596215561 " />
<animateTransform
attributeName="transform"
type="rotate"
from="0 300 250" to="360 300 250"
begin="0s" dur="10s"
repeatCount="indefinite"
calcmode="spline"
keyTimes="0; 0.25; 0.5; 0.75; 1"
keySplines="0.5 0 0.5 1; 0.5 0 0.5 1; 0.5 0 0.5 1; 0.5 0 0.5 1"
/>
</g>
</svg>
What am I doing wrong? Should I use CSS animations instead? Any kind of non-continuous rotation would be a win.
I tried various value combinations for the keyTimes / keySplines attributes, but the only result I got was a continuous rotation - for example, with
keyTimes="0; 1"
keySplines="0.5 0 0.5 1"
The SVG specification says:
For animations specified with a ‘values’ list, the ‘keyTimes’ attribute if specified must have exactly as many values as there are in the ‘values’ attribute. For from/to/by animations, the ‘keyTimes’ attribute if specified must have two values.
So we either need to reduce the number of keyTimes values or move to using values and then have a matching number of values.
I've set some example values below and the shape now rotates at various speeds.
html, body {
width: 100%;
height: 100%;
}
svg {
width: 100%;
height: 200%;
transform: translate(-100px, -130px);
}
<svg xml:lang="fr" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<style type="text/css">
<![CDATA[
path {
fill:none;
stroke:black;
stroke-width:10px;
}
]]>
</style>
<g class="triangle">
<path d="M 349.9999999999999 163.3974596215561 L 200 250.00000000000006 " />
<path d="M 200 250.00000000000006 L 350 336.60254037844385 " />
<path d="M 350 336.60254037844385 L 349.9999999999999 163.3974596215561 " />
<animateTransform
attributeName="transform"
type="rotate"
values="0 300 250;100 300 250;130 300 250;200 300 250;360 300 250"
begin="0s" dur="10s"
repeatCount="indefinite"
calcmode="spline"
keyTimes="0; 0.25; 0.5; 0.75; 1"
keySplines="0.5 0 0.5 1; 0.5 0 0.5 1; 0.5 0 0.5 1; 0.5 0 0.5 1"
/>
</g>
</svg>

how to make a shape in svg or with figma

This is the image which I need to create.
I need to make this image with svg or with figma in png format. the black portion will be transparent. please help me. thanks
This is a very simple path.
M 0 100
Move to (0, 100) (bottom left)
H 100
Horizontal line to bottom right
V 0
Vertical line to top right
A 100 100 0 0 1 0 100
Semicircular arc of radius 100, clockwise, to (0, 100) (bottom right).
Z
Close path
svg {
width: 200px;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<path d="M 0 100 H 100 V 0 A 100 100 0 0 1 0 100 Z" fill="black"/>
</svg>
You can create a rectangle that is masked off by a circle.
body {
background-color: silver;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="200">
<defs>
<mask id="m1">
<rect width="100" height="100" fill="white" />
<circle r="100" fill="black"/>
</mask>
</defs>
<rect width="100" height="100" fill="white" mask="url(#m1)"/>
</svg>

Svg animation without css

I want to create an animation like this that revolves around the two shapes. And I want to achieve it in SVG with no external CSS. Can anyone help me out on how to do it?
This is my code
<svg xmlns="http://www.w3.org/2000/svg" width="542" height="542" viewBox="0 0 542 542">
<g id="svg" transform="translate(-655 -265)">
<circle id="Ellipse_3" data-name="Ellipse 3" cx="271" cy="271" r="271" transform="translate(655 265)" fill="none"/>
<path id="Path_1" data-name="Path 1" d="M818.25,412.875l.71.931c116.417,110.219-.023,204.664-.382,205.428-.045.089-.2.312-.375.672-2.758,5.713,3.239,3.015,3.594,2.858,147.217-64.969,210.869-212.39,210.672-213.249-.359-1.7-3.069-1.088-3.344-.781-4.366,4.893-81.574,88.727-207.317.617-.169-.118.317.2-.673-.473s-2.369-1.12-3.148-.181-.909,2.256.388,4.35" fill="none" stroke="#707070" stroke-width="1"/>
<path id="Path_2" data-name="Path 2" d="M927.651,569.319s69.788,5.194,99.3,51.994c.017.04,4.351,6.826,5.406-.172a1.6,1.6,0,0,0,.069-.516,5.747,5.747,0,0,0-.21-2.031c-3.036-7.836-31.037-76.552-54.932-98.845-.009-.009-35.627,38.007-49.635,49.57" fill="none" stroke="#707070" stroke-width="1"/>
<g id="Ellipse_1" data-name="Ellipse 1" transform="translate(655 496)" fill="#f90a2a" stroke="#000" stroke-width="1">
<circle cx="34.5" cy="34.5" r="34.5" stroke="none"/>
<circle cx="34.5" cy="34.5" r="34" fill="none"/>
<animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0" to="360" dur="10s" repeatCount="indefinite"/>
</g>
</g>
</svg>
If you load your file into a vector editor, we will see that the shapes are outside the SVG canvas.
Because of this, you were forced to use transform commands to bring the forms back to the custom viewport.
Practical advice
It is necessary to draw in a vector editor so that the shapes do not go beyond the boundaries of the SVG canvas.
After redrawing in a vector editor and cleaning the file:
To get a segment, use stroke-dasharray="251,1004",
where 251 -
dash, 1004 - gap
To animate the rotation, it was necessary, in addition to the angle,
to additionally specify the coordinates of the rotation center
<animateTransform attributeName="transform" attributeType="XML" type="rotate"
from="0,266,278" to="360,266,278" dur="4s" repeatCount="indefinite"/>
.container {
width:75vw;
height:auto;
}
<div class="container">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="svg5" width="50%" height="50%" viewBox="0 0 542 542" >
<defs>
<linearGradient id="Lg" x1="0" x2="0" y1="1" y2="0">
<stop offset="0" stop-color="#DC143C" />
<stop offset="0.8" stop-color="white" stop-opacity="0.05" />
</linearGradient>
</defs>
<g id="g820" transform="translate(-658 -238)" fill="none" stroke="#707070" stroke-width="1">
<path id="Path_1" fill="black" stroke="black" d="m818 413 1 1c116 110 0 204 0 205l-1 1c-3 6 3 3 4 3a446 446 0 0 0 210-213c0-2-3-2-3-1-4 5-81 88-207 0h-4v4" data-name="Path 1" />
<path id="Path_2" fill="#DC143C" d="M928 569s69 6 99 52c0 0 4 7 5 0a6 6 0 0 0 0-2c-3-8-31-77-55-99 0 0-35 38-49 49" data-name="Path 2" />
</g>
<circle id="Ellipse_3" data-name="Ellipse 3" stroke="url(#Lg)" cx="266" cy="278" r="220" fill="none" stroke="#DC143C" stroke-width="45" stroke-dasharray="251,1004" stroke-linecap="round" >
<animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0,266,278" to="360,266,278" dur="4s" repeatCount="indefinite"/>
</circle>
</svg>
</div>
The experimental <sprite-meister> Web Component can generate the CSS for you
After cleaning up your SVG: no translates, no self-closing tags
You are left with the first frame of your animation
this is not SVG, but a String Template Literal you can program
Sprite-Meister generates the other steps=48 frames for you
the circlepath function calculates an x,y position for every frame
each <circle cx="${v1.x}" cy="${v1.y}" doesn't rotate the circle;
it draws the circle at different positions in each frame
and animates the generated SVG sprite-sheet with CSS
<script src="//sprite-meister.github.io/element.js"></script>
<script>console.log=()=>{/*don't bloat SO snippet console*/}</script>
<sprite-meister duration="5s" w="542" h="542" width="180px" steps="48">
${ setv1( circlepath({ radius:200 }) , "yellow circle position" )}
<text y="10%" font-size="50px">frame: ${framenr} </text>
<path fill="green" d="m163 158 1 1c116 110 0 204 0 205l-1 1c-3 6 3 3 4 3a446 446 0 0 0 210-213c0-2-3-2-3-1-4 5-81 88-207 0h-4v4m105 150s69 6 99 52c0 0 4 7 5 0a6 6 0 0 0 0-2c-3-8-31-77-55-99 0 0-35 38-49 49"></path>
<circle cx="${v1.x}" cy="${v1.y}" r="34" fill="yellow" stroke="blue"></circle>
</sprite-meister>
Sources:
https://dev.to/dannyengelman/create-svg-spritesheet-animations-with-1-template-literal-string-3hee
https://sprite-meister.github.io/
https://sprite-meister.github.io/documentation.html
<sprite-meister> is NOT version 1.0
You need a decent amount of SVG knowlegde, and learn (at least the basics) of SVG SMIL animations first, so you understand the difference with sprite-sheet animations

Coordinates for a svg bezier curve of length 0

I want to animate 2 svg paths.
for this thy need similiar nodes.
if path1 has a bezier, path2 must have it too at same node.
So I insert c0 0 0 0 0 0 to path2.
but it changes the 2nd shape.
What can I do?
<html>
<title>Page Title</title>
</head>
<body>
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="400.000000pt" height="400.000000pt" viewBox="0 0 400.000000 400.000000"
preserveAspectRatio="xMidYMid meet">
<g
fill="#000000" stroke="none">
<path fill ="red" d= "m50 50 50 50 100 100 50 100" />
<path d= "m0 0 50 50 100 100 50 100" />
<path fill = "blue" d= "m0 0 c0 0 0 0 0 0 50 50 100 100 50 100" />
</g>
</svg>
</body>
</html>
The path definition
m 0 0 50 50 100 100 50 100
Is equivalent to
m 0 0
l 50 50
l 100 100
l 50 100
An equivalent bezier curve to that might be
m 0 0
c 0 0 50 50 50 50
c 0 0 100 100 100 100
c 0 0 50 100 50 100"
I am choosing to put the first control point at the start of the line/bezier. And the second at the end. I could have chosen to put them both at the start, or both at the end.
If you were using the path for animated motion, you should place the control points at the 1/3 and 2/3 point along the line. Eg.:
m 0 0
c 16.7 16.7 33.3 33.3 50 50
c 33.3 33.3 66.7 66.7 100 100
c 0 0 16.7 33.3 33.3 66.7 50 100"
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="400.000000pt" height="400.000000pt" viewBox="0 0 400.000000 400.000000"
preserveAspectRatio="xMidYMid meet">
<g fill="#000000" stroke="none">
<path fill ="red" d= "m50 50 50 50 100 100 50 100" />
<path d= "m0 0 50 50 100 100 50 100" />
<path fill = "blue" d= "
m 0 0
c 0 0 50 50 50 50
c 0 0 100 100 100 100
c 0 0 50 100 50 100" />
</g>
</svg>

Animate SVG path d=... coordinates without stroke

I'm trying to animate the following GIF in SVG.
Code:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" width="100" height="100">
<path d="M18.53.359h.225A16.684 16.684 0 0130.56 5.12a16.902 16.902 0 014.813 12.007A18.372 18.372 0 0130.18 29.66l-.671.672a18.215 18.215 0 01-11.99 5.163l-.436.012h-.13A16.757 16.757 0 015.12 30.662a16.845 16.845 0 01-4.74-12.08A18.35 18.35 0 015.513 6.114l.307-.311A18.203 18.203 0 0118.095.371l.435-.012zM16.413 2.6c-3.508 0-6.778 1.443-9.558 4.253-3.306 3.299-4.719 7.273-4.102 11.522.495 3.425 2.323 6.938 5.012 9.63l.31.303c4.452 4.235 13.288 7.796 20.265 1.086l.248-.244.236-.248.354-.344a12.592 12.592 0 003.686-11.167 17.578 17.578 0 00-4.95-9.618c-2.689-2.699-6.17-4.532-9.597-5.032-.63-.093-1.267-.14-1.904-.141z">
<animate
attributeName="d"
from="start_path"
to="end_path"
dur="0.66s"
fill="freeze"
repeatCount="indefinite"
/>
</path>
</svg>
The solution I have is using clip-path but just wanna try using path coordinates if possible.
Perhaps the simplest solution is to use a circle as a mask. Then animate the dash array of the circle.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" width="100" height="100">
<defs>
<mask id="wipe">
<circle cx="18" cy="18" r="16"
fill="none" stroke="white" stroke-width="5" stroke-dasharray="100.6" stroke-dashoffset="100.6"
transform="rotate(-35,18,18)">
<animate attributeName="stroke-dashoffset"
from="100.6"
to="0"
dur="0.66s"
repeatCount="indefinite"/>
</circle>
</mask>
</defs>
<path d="M18.53.359h.225A16.684 16.684 0 0130.56 5.12a16.902 16.902 0 014.813 12.007A18.372 18.372 0 0130.18 29.66l-.671.672a18.215 18.215 0 01-11.99 5.163l-.436.012h-.13A16.757 16.757 0 015.12 30.662a16.845 16.845 0 01-4.74-12.08A18.35 18.35 0 015.513 6.114l.307-.311A18.203 18.203 0 0118.095.371l.435-.012zM16.413 2.6c-3.508 0-6.778 1.443-9.558 4.253-3.306 3.299-4.719 7.273-4.102 11.522.495 3.425 2.323 6.938 5.012 9.63l.31.303c4.452 4.235 13.288 7.796 20.265 1.086l.248-.244.236-.248.354-.344a12.592 12.592 0 003.686-11.167 17.578 17.578 0 00-4.95-9.618c-2.689-2.699-6.17-4.532-9.597-5.032-.63-.093-1.267-.14-1.904-.141z" mask="url(#wipe)"/>
</svg>
You'll probably want to tweak the animation to add a short pause at the end. And to fade the colours as per your GIF version.
Here is path d solution with 2 arcs, whithout stroke, only fill:
let r = 90,
rx = 70/90,
ry = 85/90,
circ = Math.PI*2;
requestAnimationFrame(draw)
function draw(t) {
t = (t/1000)%1;
let a = t*circ,
la = a % circ > Math.PI?1:0,
x = r * Math.cos(a),
y = r * Math.sin(a);
path.setAttribute("d", [
"M", r, 0,
"A", r, r, 0, la, 1, x, y,
"L", rx*x, ry*y,
"A", r*rx, r*ry, 0, la, 0, r*rx, 0,
"Z"
].join(" "));
path.setAttribute("opacity", 1-t);
requestAnimationFrame(draw);
}
<svg width=90vw height=90vh viewBox="-100,-100,200,200" >
<path id="path" transform=rotate(-45) ></path>
</svg>

Resources