SVG Cubic Morph

The component that also covers SVG morphing, with similar functionality as for the SVG Morph component, but with a different implementation for value processing and animation setup.

Overview

Animate SVG paths with cubic-bezier path commands and improved performance.

The KUTE.js SVG Cubic Morph component enables animation for the d (description) presentation attribute and is the latest in all the SVG components.

The main difference with the other SVG Morph component is the fact that this components is using some path processing scripts borrowed from Raphael.js and other libraries to convert all path commands to cubicBezierTo path commands.

The component will process paths and out of the box will provide the closest possible interpolation by default. It also implements a series of solutions from Paper.js to determine paths draw direction and automatically reverse one of them for most accurate presentation and as a result the previously featured options reverseFirstPath and reverseSecondPath have been deprecated.

All path processing is powered by our SVGPathCommander starting KUTE.js version 2.0.14, which aims to modernize and improve the path processing and enable transition from closed to and from un-closed shapes.

Basic Example

The first morphing animation example is a transition from a rectangle into a star, just like for the other component.

<svg id="morph-example" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
  <path id="rectangle" class="bg-lime" d="M38.01,5.653h526.531c17.905,0,32.422,14.516,32.422,32.422v526.531 c0,17.905-14.517,32.422-32.422,32.422H38.01c-17.906,0-32.422-14.517-32.422-32.422V38.075C5.588,20.169,20.104,5.653,38.01,5.653z"/>
  <path id="star" style="visibility:hidden" d="M301.113,12.011l99.25,179.996l201.864,38.778L461.706,380.808 l25.508,203.958l-186.101-87.287L115.01,584.766l25.507-203.958L0,230.785l201.86-38.778L301.113,12.011"/>
</svg>

Now we can apply both .to() and fromTo() methods:

// the fromTo() method
var tween = KUTE.fromTo('#rectangle', {path: '#rectangle' }, { path: '#star' }).start();
// OR
// the to() method will take the path's d attribute value and use it as start value
var tween = KUTE.to('#rectangle', { path: '#star' }).start();
// OR
// simply pass in a valid path string without the need to have two paths in your SVG
var tween = KUTE.to('#rectangle', { path: 'M301.113,12.011l99.25,179.996l201.864,38.778L461.706,380.808l25.508,203.958l-186.101-87.287L115.01,584.766l25.507-203.958L0,230.785l201.86-38.778L301.113,12.011' }).start();

By default, the component will process the paths as authored and deliver its best without any option required, like for the first red rectangle below which applies to any of the above invocations:

The second blue shape and its corresponding end shape have been edited by adding additional curve points using a vector graphics editor to match the amount of points in both shapes as well as to optimize their travel distance during the animation. You can use the same technique on your shapes to control the animation to your style.

Chris Coyier wrote an excelent article in which he explains how SVG morphing animation works, from concept, terminology and workflow.

Morphing Unclosed Shapes To Closed Shapes

The next morphing animation example is a transition from a line into a circle and this example is to showcase the component's behavior when one of the paths is not closed (it doesn't have the Z path command), while the other path is closed.

<svg id="morph-example" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
  <path id="line" fill="transparent" stroke="orange" stroke-linejoin="round" stroke-width="10" d="M10 300L590 300"/>
  <path id="star" style="visibility:hidden" d="M10,300a290,290 0 1,0 580,0a290,290 0 1,0 -580,0z"/>
</svg>

Now we can apply both .to() and fromTo() methods:

// the fromTo() method
var tween = KUTE.fromTo('#line', {path: '#line' }, { path: '#circle' }).start();
// OR
// the to() method will take the path's d attribute value and use it as start value
var tween = KUTE.to('#line', { path: '#circle' }).start();

The functionality of this component is different from the svgMorph component in the sense that it will animate shapes as authored. In the above example, the orange line is closed while the green line is not, and the animation is different.

Subpath Example

In other cases, you may want to morph paths that have subpaths. Let's have a look at the following SVG:

<svg id="multi-morph-example" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
  <path id="w1" d="M412.23 511.914c-47.708-24.518-94.086-36.958-137.88-36.958-5.956 0-11.952 0.18-17.948 0.708-55.88 4.624-106.922 19.368-139.75 30.828-8.708 3.198-17.634 6.576-26.83 10.306l-89.822 311.394c61.702-22.832 116.292-33.938 166.27-33.938 80.846 0 139.528 30.208 187.992 61.304 22.962-77.918 78.044-266.09 94.482-322.324-11.95-7.284-24.076-14.57-36.514-21.32z 
    m116.118 79.156l-90.446 314.148c26.832 15.372 117.098 64.05 186.212 64.05 55.792 0 118.252-14.296 190.834-43.792l86.356-301.976c-58.632 18.922-114.876 28.52-167.464 28.52-95.95 0-163.114-31.098-205.492-60.95z 
    m-235.526-222.28c77.118 0.798 134.152 30.208 181.416 60.502l92.752-317.344c-19.546-11.196-70.806-39.094-107.858-48.6-24.386-5.684-50.02-8.616-77.204-8.616-51.796 0.976-108.388 13.946-172.888 39.8l-88.44 310.596c64.808-24.436 120.644-36.34 172.086-36.34 0.046 0.002 0.136 0.002 0.136 0.002z 
    m731.178-170.666c-58.814 22.832-116.208 34.466-171.028 34.466-91.686 0-159.292-31.802-203.094-62.366l-91.95 318.236c61.746 39.708 128.29 59.878 198.122 59.878 56.948 0 115.94-13.68 175.462-40.688l-0.182-2.222 3.734-0.886 88.936-306.418z"/>
  <path id="w2" d="M0 187.396l367.2-50.6v354.798h-367.2v-304.2z 
    m0 649.2v-299.798h367.2v350.398z 
    m407.6 56v-355.798h488.4v423.2z 
    m0-761.2l488.4-67.4v427.6h-488.4v-360.2z"/>
</svg>

Similar to the svgMorph component, this component doesn't provide multipath processing so we should split the sub-paths into multiple <path> shapes, analyze and associate them in a way that corresponding shapes are close and their points travel the least possible distance.

Now since we've worked with these paths before, the first example below showcases how the svgCubicMorph component handles it by default. The following example was made possible by editing the shapes with a vector graphics editor. The last example showcases a creative use of association between starting and end shapes. Let's have a look:

Make sure to check the markup here as well as the svgCubicMorph.js for a full code review.

Intersecting Paths Example

The same preparation apply here, however the outcome is a bit different with cubic-bezier path commands, as shown in the first example. For the next two examples, the shapes have been edited for a better outcome. Let's have a look:

So the technique involves creating <mask> elements, splitting multipath shapes into multiple <path> shapes, matching the amount of starting and ending shapes by duplicating an existing shape or by sampling another shape for the same purpose, editing shapes for more accurate point-to-point animation, as well as various options to optimize the visual presentation.

That's it, you now mastered the SVG Cubic Morph component.

Notes