Rotate the direction of motion of a rect using animateMotion in SVG - animation

I want the yellow rectangle to be rotated 45 degrees (which it is), but I also want the direction of motion to rotate, so that the yellow rectangle appear to go "downhill" (down the blue line). I don't want it to keep moving horizontally.
<svg width="800" height="400" viewBox="0 0 800 400"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" >
<!-- decorative circles for the ends of the blue line. -->
<g transform="rotate(45, 400, 200)">
<path id="myPath" d="M150,200 L650,200" fill="none"
stroke="blue" stroke-width="5.6" />
<circle cx="150" cy="200" r="8.94" fill="blue" />
<circle cx="650" cy="200" r="8.94" fill="blue" />
</g>
<g>
<rect x="0" y="0"
fill="yellow" stroke="red" width="84" height="56"></rect>
<animateMotion dur="4s" repeatCount="1" rotate="45"
path="M150,200 L650,200" >
</animateMotion>
</g>
</svg>
Another way to do this is to put <mpath xlink:href="#myPath" /> as a sub-element of the animateMotion SVG element. In that case you can leave out path="M150,200 L650,200".

You mean like this? I've moved the animateMotion so it only applies to the rect and added a transform to the containing <g> element. I could have just put the rect in the other <g> element I guess which would have been simpler.
<svg width="800" height="400" viewBox="0 0 800 400"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" >
<!-- decorative circles for the ends of the blue line. -->
<g transform="rotate(45, 400, 200)">
<path id="myPath" d="M150,200 L650,200" fill="none"
stroke="blue" stroke-width="5.6" />
<circle cx="150" cy="200" r="8.94" fill="blue" />
<circle cx="650" cy="200" r="8.94" fill="blue" />
</g>
<g transform="rotate(45, 400, 200)">
<rect x="0" y="0"
fill="yellow" stroke="red" width="84" height="56">
<animateMotion dur="4s" repeatCount="1"
path="M150,200 L650,200" >
</animateMotion>
</rect>
</g>
</svg>

Related

SVG animation (blinking) inside of animation (blinking)

So i have page 1 and page 2 which are animated, inside of page 2 there is also animation but problem is that this object shows when page 2 is "hidden". How to prevent that ??
Black square should only be visible when page 2 is visible, but it ignores parent style.
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 612 792" style="enable-background:new 0 0 612 792;" xml:space="preserve">
<rect x="0.5" y="0.167" fill="#ccc" stroke="#000" width="100" height="100"/>
<!-- square -->
<g>
<!-- page 1 -->
<g id="page_one" style="z-index:1">
<rect x="25" y="5" width="50" height="50" fill="red" style=""></rect>
</g>
<!-- page 2 -->
<g id="page_two" style="z-index:-1">
<rect x="25" y="5" width="50" height="50" fill="white" style=""></rect>
<g transform="scale(2.9) translate(6,0)">
<g transform="scale(0.205)translate(1,1)">
<!-- animation inside page 2 -->
<g style="z-index:-1">
<animate attributeName="visibility" dur="2" repeatCount="indefinite" keyTimes="0;0.5;1" values="visible;hidden;visible"></animate>
<rect x="25" y="15" width="50" height="50" fill="black" style=""></rect>
</g>
</g>
</g>
</g>
<!-- animate page 1 & 2 -->
<animate xlink:href="#page_one" attributeName="visibility" values="visible;hidden" dur="4s" begin="0s" repeatCount="indefinite"></animate>
<animate xlink:href="#page_two" attributeName="visibility" values="hidden;visible" dur="4s" begin="0s" repeatCount="indefinite"></animate>
</g>
</svg>
Tried some css styling, z-index but nothing solved issue.
animate the display property instead.
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 612 792" style="enable-background:new 0 0 612 792;" xml:space="preserve">
<rect x="0.5" y="0.167" fill="#ccc" stroke="#000" width="100" height="100"/>
<!-- square -->
<g>
<!-- page 1 -->
<g id="page_one" style="z-index:1">
<rect x="25" y="5" width="50" height="50" fill="red" style=""></rect>
</g>
<!-- page 2 -->
<g id="page_two" style="z-index:-1">
<rect x="25" y="5" width="50" height="50" fill="white" style=""></rect>
<g transform="scale(2.9) translate(6,0)">
<g transform="scale(0.205)translate(1,1)">
<!-- animation inside page 2 -->
<g style="z-index:-1">
<animate attributeName="display" dur="2" repeatCount="indefinite" keyTimes="0;0.5;1" values="block;none;block"></animate>
<rect x="25" y="15" width="50" height="50" fill="black" style=""></rect>
</g>
</g>
</g>
</g>
<!-- animate page 1 & 2 -->
<animate xlink:href="#page_one" attributeName="display" values="block;none" dur="4s" begin="0s" repeatCount="indefinite"></animate>
<animate xlink:href="#page_two" attributeName="display" values="none;block" dur="4s" begin="0s" repeatCount="indefinite"></animate>
</g>
</svg>

how to make wavy line animation inside svg circle

I have a loader gif, but I want this animation using svg
[1]: https://i.stack.imgur.com/h3oJC.gif
Enjoy:
<svg>
<rect fill="blue" x="0" y="0" width="300" height="140"/>
<circle fill="white" cx="150" cy="70" r="60" stroke="blue" stroke-width="5" />
<path fill="none" stroke="blue" stroke-width="10" d="M0,0 Q 30,-30 60,0 Q 90,30 120,0 Q 150,-30 180,0 210,30 240,0">
<animateTransform attributeName="transform"
attributeType="XML"
type="translate"
from="-30 70"
to="90 70"
dur="1s"
repeatCount="indefinite"/>
</path>
</svg>

How to set an origin point for svg's animateTransform

If you view this SVG, I'm animating the transform property, and it moves from the top left by default. How do I change it to animate from the center instead?
<svg width="400" height="400" viewBox="0 0 400 400">
<rect width="400" height="400" fill="#495ade"/>
<g>
<circle cx="50" cy="50" r="50" fill="#49de7d"/>
<animateTransform attributeName="transform"
type="scale"
values="1 1;.5 .5;1 1"
begin="0s"
dur="1.5s"
repeatCount="indefinite"
calcMode="spline"
keySplines="0.4 0 0.5 1; 0.5 0 0.5 1"
/>
</g>
</svg>
What I tried already:
This answer says to just throw X & Y coords after each of the values listed. So I tried values="1 1 50 50;.5 .5 50 50;1 1 50 50" but that kills the animation.
You can also use from and to instead of values, and include an X & Y origin, but I need 3 animation states, not two.
Instead of the animation animateTransform type =" scale ", you can use the animation of increasing the radius of the circle
In this case, it will not be necessary to define the transform-origin since the circle is in the center of the canvas.
<svg width="400" height="400" viewBox="0 0 400 400">
<rect width="400" height="400" fill="#495ade"/>
<g>
<circle cx="200" cy="200" r="50" fill="#49de7d">
<animate attributeName="r"
values="50;25;50"
begin="0s"
dur="1.5s"
repeatCount="indefinite"
calcMode="spline"
keySplines="0.4 0 0.5 1; 0.5 0 0.5 1"
/>
</circle>
</g>
</svg>
Pause animation in intermediate states
<svg width="400" height="400" viewBox="0 0 400 400">
<rect width="400" height="400" fill="#495ade"/>
<g>
<circle cx="200" cy="200" r="50" fill="#49de7d">
<animate attributeName="r"
values="50;25;25;50;50"
begin="0s"
dur="1.5s"
repeatCount="indefinite"
/>
</circle>
</g>
</svg>
Update
Consider Implementing CSS Animations
#crc1 {
transform-origin:center;
transform-box:fill-box;
animation: scale 1.5s infinite;
}
#keyframes scale {
0%{transform:scale(1);}
50%{transform:scale(.5);}
100%{transform:scale(1);}
}
<svg width="400" height="400" viewBox="0 0 400 400">
<rect width="400" height="400" fill="#495ade"/>
<g>
<circle id="crc1" cx="200" cy="200" r="50" fill="#49de7d"/>
</g>
</svg>
Upd2
SMIL animation
On excellent advice from #Sphinxxx, add css rules to the group tag, thus keeping the animateTransform SVG
<svg width="400" height="400" viewBox="0 0 400 400">
<rect width="400" height="400" fill="#495ade"/>
<g style="transform-origin: center; transform-box: fill-box;">
<circle cx="200" cy="200" r="50" fill="#49de7d"/>
<animateTransform attributeName="transform"
type="scale"
values="1 1;.5 .5;1 1"
begin="0s"
dur="1.5s"
repeatCount="indefinite"
calcMode="spline"
keySplines="0.4 0 0.5 1; 0.5 0 0.5 1"
/>
</g>
</svg>
It's easiest to have the circle at the origin, that way the scale works from its centre.
Then we need to translate the <g> element instead so the circle appears at the same place.
Finally we need to actually animate the circle and not the <g> element by wrapping the animateTransform by the <circle> element.
<svg width="400" height="400" viewBox="0 0 400 400">
<rect width="400" height="400" fill="#495ade"/>
<g transform="translate(50, 50)">
<circle cx="0" cy="0" r="50" fill="#49de7d">
<animateTransform attributeName="transform"
type="scale"
values="1 1;.5 .5;1 1"
begin="0s"
dur="1.5s"
repeatCount="indefinite"
calcMode="spline"
keySplines="0.4 0 0.5 1; 0.5 0 0.5 1"
/>
</circle>
</g>
</svg>
Alternatively we could transform the circle itself and then use additive="sum" to apply the transform animation on top.
<svg width="400" height="400" viewBox="0 0 400 400">
<rect width="400" height="400" fill="#495ade"/>
<g>
<circle cx="0" cy="0" r="50" fill="#49de7d" transform="translate(50, 50)">
<animateTransform attributeName="transform"
type="scale"
values="1 1;.5 .5;1 1"
begin="0s"
dur="1.5s"
repeatCount="indefinite"
calcMode="spline"
keySplines="0.4 0 0.5 1; 0.5 0 0.5 1"
additive="sum"
/>
</circle>
</g>
</svg>

SVG Scale Animation from Center Point instead of Upper-Left Corner

How do I use animateTransform in an SVG to scale an object from the center point instead of the upper-left corner?
Example:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100px" height="100px">
<circle style="fill:blue;" cx="50" cy="50" r="45">
<animateTransform attributeName="transform"
type="scale"
from="0 0"
to="1 1"
begin="0s"
dur="1s"
repeatCount="indefinite"
/>
</circle>
</svg>
(Codepen: http://codepen.io/anon/pen/wKwrPg?editors=100)
Change your scaling transform to use additive="sum" and apply an additional transform that translates the circle to the center of the image. So instead of defining the shape at the center of the image, define its center to be 0 0 and then use the transform attribute to translate it to 50, 50 (the exact center of your particular image).
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100px" height="100px">
<circle style="fill:blue;" cx="0" cy="0" r="45" transform="translate(50 50)">
<animateTransform attributeName="transform"
type="scale"
additive="sum"
from="0 0"
to="1 1"
begin="0s"
dur="1s"
repeatCount="indefinite"
/>
</circle>
</svg>
Here's another example using the defs and use tags to reuse the circle definition:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100px" height="100px">
<defs>
<circle id="def-circle" style="fill:blue;" cx="0" cy="0" r="45" />
</defs>
<use xlink:href="#def-circle" transform="translate(50 50)">
<animateTransform attributeName="transform"
type="scale"
additive="sum"
from="0 0"
to="1 1"
beg="0s"
dur="1s"
repeatCount="indefinite" />
</use>
</svg>
You could also have done that with the help of CSS styles and transform-origin property.
The benefit is that you do not have to calculate coordinates and translate your objects.
<svg version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<style>
#logo { transform-origin: center; }
</style>
<g id="logo">
<animateTransform attributeName="transform" begin="0s" type="scale" dur="2s" from="1" to=".5" repeatCount="indefinite"/>
<circle r="8" cx="12" cy="12" />
</g>
</svg>
#logo {
transform-origin: center;
}
<svg version="1.1" viewBox="0 0 24 24" width="100%" height="100px" xmlns="http://www.w3.org/2000/svg">
<g id="logo">
<animateTransform attributeName="transform" begin="0s" type="scale" dur="2s" from="1" to=".5" repeatCount="indefinite"/>
<circle r="8" cx="12" cy="12" />
</g>
</svg>
In your specific case, yet another way would be to animate the radius of the circle itself:
<circle r="0" cx="50" cy="50">
<animate attributeName="r" from="0" to ="10" begin="1s" dur="300ms" fill="freeze" />
</circle>
Thanks to Robert Longson for this answer.

Firefox SVG shape not printing when it has stroke

I am having an issue with SVG shapes that have a stroke and trying to get them to print in firefox.
This is the simplest example:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect x="0" y="0" rx="15" ry="15" width="300" height="400" style="stroke:black;stroke-width:5;" fill="black" />
<circle id="FirstCircle" cx="50" cy="50" r="30" stroke="black" stroke-width="2" fill="white" style="opacity:0.75;"/>
<circle id="SecondCircle" cx="50" cy="150" r="30" fill="white" style="opacity:0.75;"/>
</svg>
When I try and print this the first shape does one of two things:
It does not show up at all
It shows up off center in its bounding box.
The second shape with no stroke shows up as expected, where expected.
When displaying on the screen it shows as expected where expected. The issue olny arises when I try and print.
I have tried with different scale factors (50% - 100%) and the default shrink to fit.
Here is what I get when I try and print it:
Is this defined behavior or does anyone know how to correct for this?
I am not in love with the stroke on this shape and can easily layer shapes to get the same effect, bt it would be nice to know why this is happeneing.
EDIT:
As Robert Longson pointed out this appears to be a Firefox bug. A report was filed here and they are looking into it.
You need to specify the width and height of the svg element to fix this:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" height="400">
<rect x="0" y="0" rx="15" ry="15" width="300" height="400" style="stroke:black;stroke-width:5;" fill="black" />
<circle id="FirstCircle" cx="50" cy="50" r="30" stroke="black" stroke-width="2" fill="white" style="opacity:0.75;"/>
<circle id="SecondCircle" cx="50" cy="150" r="30" fill="white" style="opacity:0.75;"/>
</svg>

Resources