Rotating elements


June 18, 2011 Code on Github

Introduction

The page explains how to animate simple SVG transformations using the <animateTransform> tag. The code for the example can be found by following the Github link above.

Square rotating about its centre

[NOTE: SVG's SMIL animations are deprecated and you should probably use CSS transformations instead.]

Animating a square

This is the code for the animated square at the top of this page:

<rect x="160" y="20" width="60" height="60" fill="#007bff">
  <animateTransform
    attributeName="transform"
    type="rotate"
    from="0 190 50"
    to="360 190 50"
    dur="4s"
    repeatCount="indefinite" />
  </rect>

The important points to note are:

  • The <animateTransform> element is a child of the <rect> element.
  • The type is "rotate" (could also be "translate", "scale", "skewX" or "skewY").
  • The from and to are in the form "n1 n2 n3".
  • The rotation starts at 0 degrees and changes to 360 degrees (the n1 values).
  • The centre of rotation is at (n2, n3) and doesn't change (it could if you wanted).
  • The dur is "4s", meaning a full rotation takes 4 second.
  • The repeatCount is "indefinite", but can be a number, even a decimal, if you want the animation to stop after it has repeated some number of times.
  • You can also use begin and end attributes to determine when to start and stop the animation.

Rotating arbitrary elements

I was first inspired to tackle this problem after seeing this question on Stack Overflow. So I found a tutorial for how to draw gears using Inkscape (here) and tried to animate them.

In order to rotate an element about its centre, you first need to know its centre. For <circle> or <rect> elements that's easy, but for a path, it's not so straightforward.

(EDIT: As Jim says in the comments, you could draw the elements so their center is at the origin, and then translate them to where you want. This simplifies things at lot, but sometimes you don't get to draw the image yourself.)

The only way I could find to determine the centre of a path, short of writing my own program to parse the coordinates, was to use Javascript and the getBBox() function to find the bounding box of the element.

Below is a function that takes an element id, a duration (seconds to complete one rotation), and a direction (1 for clockwise, -1 for anti-clockwise). It then finds the element with that id, determines its centre with getBBox(). It then builds an <animateTransform> element from scratch and adds it to the chosen element. Finally, it calls beginElement() to start the animation.

function addRotateTransform(target_id, dur, dir) {
  var my_element = svg.getElementById(target_id);
  var a = svg.createElementNS("http://www.w3.org/2000/svg", "animateTransform");

  var bb = my_element.getBBox();
  var cx = bb.x + bb.width/2;
  var cy = bb.y + bb.height/2;

  a.setAttributeNS(null, "attributeName", "transform");
  a.setAttributeNS(null, "attributeType", "XML");
  a.setAttributeNS(null, "type", "rotate");
  a.setAttributeNS(null, "dur", dur + "s");
  a.setAttributeNS(null, "repeatCount", "indefinite");
  a.setAttributeNS(null, "from", "0 "+cx+" "+cy);
  a.setAttributeNS(null, "to", 360*dir+" "+cx+" "+cy);

  my_element.appendChild(a);
  a.beginElement();
}

addRotateTransform requires an svg element to be defined in order to create the animateTransform element. We can get the svg element by adding onload="init(evt)" to the SVG element and defining an init function to extract the svg from the evt (which is an object representing the onload event).

This function can be added within the SVG itself in the following <script> element:

<script type="text/javascript">
  var svg;

  function init(evt) {
    if (window.svgDocument == null) {
      svg = evt.target.ownerDocument;
    }
    addRotateTransform('gear-1', 12, 1);
    addRotateTransform('gear-2', 16, -1);
  }

  function addRotateTransform(target_id, dur, dir) {
    ...
  }
</script>

This is also where you can call the addRotateTransform function. Here I've called it twice to target elements with ids "gear-1" and "gear-2". It might seem like a lot of code just to rotate some elements, but you just need to add it to the top of your SVG and then it's easy to rotate any of the elements you chose by selecting the relevant ids.

Comments (14)

Andrea on Oct. 17, 2013, 1:55 p.m.

Hello ! How can I rotate an object (ex. a rectangle) only when a variable is set at TRUE ? (When the variable is FALSE the rectangle has to stop). Thanks very much

Chris Cuevas on Nov. 16, 2013, 12:32 a.m.

This is brilliant! This is exactly what I have been looking for!

Jim Higson on Dec. 26, 2013, 12:39 p.m.

A little advice: if you draw all the cogs in inkscape at the origin (so their centres are at (0,0) it is much easier to position and rotate them.

Jim

Peedy on March 1, 2015, 7:45 p.m.

THANK YOU FOR PROVIDING THIS PIECE OF CAKE !!!

With your code-snippet I was able to rotate my fan-blades ... :-))

Chapeau ... Peedy

Anonymous on April 19, 2015, 3:53 p.m.

It took me hours to get this to work, until I found this.. Thanks for the script!

Alex Latenko on Aug. 6, 2015, 2:38 p.m.

Thank you a lot, Peter for this perfect script!

Thats exactly the thing I have being looking for!

Alex

Anonymous on March 10, 2016, 11:28 p.m.

In chrome I got this warning.

"SVG's SMIL animations (<animate>, <set>, etc.) are deprecated and will be removed. Please use CSS animations or Web animations instead."

Stefan Fröhlich on June 3, 2016, 10:30 a.m.

Brilliant solution! The rotating_gears.svg unfortunately isn't working on IE9-11 and Edge. Even though it should be possible, right?

Any ideas to get it running on MS's offspring?

Cheers,

Stefan.

Warre Buysse on June 5, 2016, 12:44 p.m.

This post might be five years old but it helped me understand svg animateTransform rotation, thank you.

kione on June 27, 2016, 1:13 p.m.

Still very helpful! Thanks for the share

Andrea on July 15, 2017, 9:30 p.m.

Hello ! How can I rotate an object (ex. a rectangle) only when a variable is set at TRUE ? (When the variable is FALSE the rectangle has to stop). Thanks very much

Robert on Aug. 8, 2017, 10:37 p.m.

I am using VueJS and trying to do this. I didn't want to use inline JS. For my particular purpose, I was trying to get a circular geo icon to rotate when as user clicks "Find nearby businesses." ... I was able to work around this by rotating the entire SVG box with CSS and not just the path. However, I can see how this wouldn't work unless your viewbox is perfectly square, all sides same length. Since my image was circular, it works for me.

James Briano on March 12, 2018, 4:29 p.m.

Thank you.

jumanja on Sept. 12, 2018, 9:03 p.m.

Thanks a lot for your site, really helpgul. Regarding SMIL deprecation, it seems Google attempted to deprecate it, but they suspended their attempt, as you can read in this thread: https://stackoverflow.com/questions/30965580/deprecated-smil-svg-animation-replaced-with-css-or-web-animations-effects-hover

Thanks again

Leave a comment

cancel reply