SVG Transform

The component that covers transform animation on SVGElement targets, solves browser inconsistencies and provides a similar visual presentation as with other transform based components on non-SVGElements targets.

Overview

Animate 2D transform functions on SVG elements on any SVG enabled browser.

The KUTE.js SVG Transform component enables animation for the transform presentation attribute on any SVGElement target.

The SVG Transform is an important part of the SVG components for some reasons:

  • It was developed to solve most browser inconsistencies of the time for transform animation. Nowadays modern browsers are Chromium browsers that work with regular 2D transform functions.
  • The unique way to normalize translation to produce the kind of animation that is just as consistent as for CSS3 transforms on non-SVGElement targets.
  • The value processing is consistent with the current W3 draft.

Keep in mind that the transform attribute accepts no measurement units such as degrees or pixels, but it expects rotation / skew angles to be in degrees, and translations in lengths measured around the parent <svg> element viewBox attribute.

Options

Keep everything under control and handle any situation with a single option.

The only component that keeps the transformOrigin option because it's required to compute transform functions in the SVG cooordinates system.

  • transformOrigin: ['50%','50%'] sets the much needed origin. Eg: transformOrigin:[50,50]. The default value is 50% 50% of the target element box, which is contrary with the SVG draft.

Keep in mind that the component will disregard the current SVG default origin of 0px 0px of the target's parent, even if the browsers' default transformOrigin have been normalized over the years.

The transformOrigin tween option can also be used to set coordinates of a parent <svg> element (in the second example below). Values like top left values are also accepted, but will take the target element's box as a reference, not the parent's box.

2D Transform

Examples

As explained with the Transform Matrix component, the DOMMatrix API will replace webkitCSSMatrix and SVGMatrix and on this page we intend to put the two components head to head, the elements on the left will be using Transform Matrix component and equivalent 2D transform functions, while the elements on the right will be using 2D functions of the SVG Transform component.

The SVG Transform component comes with a reliable set of scripts that work on all browsers, making use of the SVGMatrix API for some origin calculation, the transform presentation attribute and the svgTransform tween property with a familiar and very easy notation:

// using the svgTransform property works in all SVG enabled browsers
var tween2 = KUTE.to(
  'shape',                // target
  {                       // to
    svgTransform: { 
      translate: [150,100], 
      rotate: 45, 
      skewX: 15, skewY: 20, 
      scale: 1.5 
    }
  }
);

// transformMatrix can animate SVGElement targets on modern browsers
// requires adding styling like `transform-origin:50% 50%` to the target element
var tween1 = KUTE.to(
  'shape',            // target
  {                   // to
    transform: { 
      translate3d: [150,100,0], 
      rotate3d: [0,0,45], 
      skew: [15,20], 
      scale3d: [1.5,1.5,1] 
    } 
  }
);

Let's see some examples and explain each case.

SVG Rotation

Our first chapter of the SVG transform is all about rotations, perhaps the most important part here. The svgTransform will only accept single value for the angle value rotate: 45, the rotation will go around the shape's center point by default, again, contrary to the browsers' default value and you can set a transformOrigin tween option to override the behavior.

The argument for this implementation is that this is something you would expect from regular HTML elements rotation and probably most needed, not to mention the amount of savings in the codebase department. Let's have a look at a quick demo:

For the first element, the Transform Matrix creates the rotation animation via rotate3d[0,0,360] tween property around the element center coordinate, as we've set transform-origin:25% 50% to the element's style; this animation doesn't work in IE browsers, while in older versions Firefox the animation is inconsistent. The second element uses the rotate: 360 function of the SVG Transform component and the rotation animation is around the element's own central point without any option, an animation that DO WORK in all SVG enabled browsers.

When for non-SVG elements' transform we could have used values such as center bottom as transformOrigin (also not supported in all modern browsers for SVGs), the entire processing falls to the browser, however when it comes to SVGs our component here will compute the transformOrigin tween option value accordingly to use the shape's .getBBox() value to determine for instance the coordinates for 25% 75% position or center top.

In other cases you may want to rotate shapes around the center point of the parent <svg> or <g> element, and we use it's .getBBox() to determine the 50% 50% coordinate, so here's how to deal with it:

// rotate around parent svg's "50% 50%" coordinate as transform-origin
// get the bounding box of the parent element
var svgBB = element.ownerSVGElement.getBBox(); // returns an object of the parent <svg> element

// we need to know the current translate position of the element [x,y]
// in our case is:
var translation = [580,0];

// determine the X point of transform-origin for 50%
var OriginX = svgBB.width * 50 / 100 - translation[0];

// determine the Y point of transform-origin for 50%
var OriginY = svgBB.height * 50 / 100 - translation[1];

// set your rotation tween with "50% 50%" transform-origin of the parent <svg> element
var rotationTween = KUTE.to(element, {svgTransform: {rotate: 150}}, { transformOrigin: [OriginX, OriginY]} );

Same as the above example, the first element is rotated by the Transform Matrix component and is using transform-origin: 50% 50%; styling, while the second element is rotated by the SVG Transform component with the above calculated transform-origin.

SVG Translation

In this example we'll have a look at translations, so when setting translate: [150,0], the first value is X (horizontal) coordinate to which the shape will translate to and the second value is Y (vertical) coordinate for translation. When translate: 150 notation is used, the script will understand that's the X value and the Y value is 0 just like for the regular HTML elements transformation. Let's have a look at a quick demo:

The first element uses the Transform Matrix translate3d: [580,0,0] function, while the second tween uses the translate: [0,0] as svgTransform value. For the second example the values are unitless and are relative to the viewBox attribute.

SVG Skew

For skews we have: skewX: 25 or skewY: -25 as SVGs don't support the skew: [X,Y] function. Here's a quick demo:

The first tween skews the shape on both X and Y axes in a chain via Transform Matrix skew:[-15,-15] function and the second tween skews the shape on X and Y axes via the svgTransform functions skewX:15 and skewY:15 tween properties. You will notice translation kicking in to set the transform origin.

SVG Scaling

Another transform example for SVGs is the scale. Unlike translations, for scale animation the component only accepts single value like scale: 1.5, for both X (horizontal) axis and Y (vertical) axis, to keep it simple and even if SVGs do support scale(X,Y). But because the scaling on SVGs depends very much on the shape's position, the script will always try to adjust the translation to make the animation look as we would expect. A quick demo:

The first tween scales the shape at scale: 1.5 via Transform Matrix component and it's scale3d:[1.5,1.5,1] function, and the second tween scales down the shape at scale: 0.5 value via svgTransform. If you inspect the elements, you will notice for the second shape translation is involved, and this is to keep transform-origin at an expected 50% 50% of the shape box. A similar case as with the skews.

Mixed SVG Transform Functions

Our last transform example for SVG Transform is the mixed transformation. Just like for the other examples the component will try to adjust the rotation transform-origin to make it look as you would expect it from regular HTML elements. Let's combine 3 functions at the same time and see what happens:

Both shapes are scaled at scale: 1.5, translated to translate: 250 and skewed at skewX: -15. If you inspect the elements, you will notice the second shape's translation is different from what we've set in the tween object, and this is to keep transform-origin at an expected 50% 50% value. This means that the component will also compensate rotation transform origin when skews are used, so that both CSS3 transform property and SVG transform attribute have an identical animation.

Chained SVG Transform

The SVG Transform does not work with SVG specific chained transform functions right away (do not confuse with tween chain), Ana Tudor explains best here, but if your SVG elements only use this feature to set a custom transform-origin, it should look like this:

<svg>
    <circle transform="translate(150,150) rotate(45) scale(1.2) translate(-150,-150)" r="20"></circle>
</svg>

In this case I would recommend using the values of the first translation as transformOrigin for your tween built with the .fromTo() method like so:

// a possible workaround for animating a SVG element that uses chained transform functions
KUTE.fromTo(element,
    {svgTransform : { translate: 0, rotate: 45, scale: 0.5 }}, // we asume the current translation is zero on both X & Y axis
    {svgTransform : { translate: 450, rotate: 0, scale: 1.5 }}, // we will translate the X to a 450 value and scale to 1.5
    {transformOrigin: [150,150]} // tween options use the transform-origin of the target SVG element
).start();

Before you hit the Start button, make sure to check the transform attribute value. The below tween will reset the element's transform attribute to original value when the animation is complete.

This way we make sure to count the real current transform-origin and produce a consistent animation with the SVG coordinate system, just as the above example showcases.

Notes