Chris_Heu
Chris_Heu

Reputation: 139

Anime.js SVG Morph Animation Breaks Shape Path

I'm trying to morph an SVG of a circle (converted to a path in Illustrator using Object > Compound Path > Make) into an square (converted the same way) using Anime.js but when the timeline runs, the circle shape is distorted as if the path is not being interpreted properly.

The square shape looks fine though.

As a test, you can remove the target class of shape from the SVG in the markup to prevent Anime.js from running and the circle will appear correctly.

Why is Anime.js unable to read my circle?

const circlePath = 'M153.1,49.5c63.2,0,114.5,51.3,114.5,114.5s-51.3,114.5-114.5,114.5S38.6,227.2,38.6,164S89.9,49.5,153.1,49.5z';
const squarePath = 'M270.7,275.7H23.9V31h246.8V275.7z';

var timeline = anime.timeline({
  autoplay: true,
  direction: "alternate",
  loop: true
});

timeline.add({
  targets: ".shape",
  d: {
    value: [
      circlePath,
      squarePath
    ],
    duration: 1500,
    easing: "easeInOutQuad"
  },
  offset: 1500
});
svg {
  margin: 1rem;
  border: 2px solid #666;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.min.js"></script>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="300px" height="300px" viewBox="0 0 300 300" style="enable-background:new 0 0 300 300;" xml:space="preserve">
  <path class="shape" fill="blue" d="M153.1,49.5c63.2,0,114.5,51.3,114.5,114.5s-51.3,114.5-114.5,114.5S38.6,227.2,38.6,164S89.9,49.5,153.1,49.5z"/>
</svg>

Upvotes: 1

Views: 1532

Answers (1)

Alexandr_TT
Alexandr_TT

Reputation: 14545

To perform smooth morphing from one shape to another, several conditions must be met

  • The number of nodal points in the initial figure and the final figure must be the same
  • The same nodal points from the beginning of the path should have the same shape. (C, Q, T, S for bezier curves)

You can get paths that meet these requirements using any vector editor.
Let's say you want to realize smooth morphing a circle into a rectangle

Draw a circle in the vector editor

Add four more points along the diagonals, they will be needed to shift the contour of the circle into a square

enter image description here

Save the file in * .svg format and copy the path to another file. This will be the initial figure for morphing. Next, drag these four anchor points to the corners of the square and adjust the control points of the anchor points (blue arrows in the figure)

enter image description here

Save the file again in the vector editor and copy the second path it will be the final morph figure

Substitute path for the initial and final elements in your application:

const circlePath = 'm268.3 164.3c0 31.4-12.6 59.9-33 80.7-20.9 21.2-49.9 34.4-82 34.4-31.5 0-60.1-12.7-80.9-33.3-21.1-20.9-34.1-49.8-34.1-81.8 0-31.1 12.3-59.3 32.4-80 20.9-21.6 50.2-35.1 82.7-35.1 32.3 0 61.6 13.3 82.5 34.8 20.2 20.7 32.6 49 32.6 80.2z';
const squarePath = 'm268.3 164.3c0 31.4 0 86.7 0 115.1-26.6 0-82.9 0-115.1 0-31.5 0-73.4 0-114.2 0-0.9-26.3-0.9-83.1-0.9-115.1 0-31.1 0-87 0-115.1 26 0 82.6 0 115.1 0 32.3 0 91.9 0 115.1 0.9 0 30.9 0 83 0 114.2z';

var timeline = anime.timeline({
  autoplay: true,
  direction: "alternate",
  loop: true
});

timeline.add({
  targets: ".shape",
  d: {
    value: [
      circlePath,
      squarePath
    ],
    duration: 1500,
    easing: "easeInOutQuad"
  },
  offset: 500
});
svg {
  margin: 1rem;
  border: 2px solid #666;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.min.js"></script>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="300px" height="300px" viewBox="0 0 300 300" style="enable-background:new 0 0 300 300;" xml:space="preserve">
  <path class="shape" fill="blue" d="m268.3 164.3c0 31.4-12.6 59.9-33 80.7-20.9 21.2-49.9 34.4-82 34.4-31.5 0-60.1-12.7-80.9-33.3-21.1-20.9-34.1-49.8-34.1-81.8 0-31.1 12.3-59.3 32.4-80 20.9-21.6 50.2-35.1 82.7-35.1 32.3 0 61.6 13.3 82.5 34.8 20.2 20.7 32.6 49 32.6 80.2z"/>
</svg>

The most difficult thing was to get the correct path formulas. Having them, you can implement morphing without using Javascript using pure SVG

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
	  
     width="300" height="300" viewBox="0 0 300 300" >  
 <style>
  path {
  fill:dodgerblue;
  stroke:none;
  }
 </style>
 
<path  d="m268.3 164.3c0 31.4-12.6 59.9-33 80.7-20.9 21.2-49.9 34.4-82 34.4-31.5 0-60.1-12.7-80.9-33.3-21.1-20.9-34.1-49.8-34.1-81.8 0-31.1 12.3-59.3 32.4-80 20.9-21.6 50.2-35.1 82.7-35.1 32.3 0 61.6 13.3 82.5 34.8 20.2 20.7 32.6 49 32.6 80.2z" stroke="black" fill="dodgerblue">
   <animate attributeName="d"
     begin="0s"
	 dur="3s"
	 values="
	         m268.3 164.3c0 31.4-12.6 59.9-33 80.7-20.9 21.2-49.9 34.4-82 34.4-31.5 0-60.1-12.7-80.9-33.3-21.1-20.9-34.1-49.8-34.1-81.8 0-31.1 12.3-59.3 32.4-80 20.9-21.6 50.2-35.1 82.7-35.1 32.3 0 61.6 13.3 82.5 34.8 20.2 20.7 32.6 49 32.6 80.2z;
			 
			 m268.3 164.3c0 31.4 0 86.7 0 115.1-26.6 0-82.9 0-115.1 0-31.5 0-73.4 0-114.2 0-0.9-26.3-0.9-83.1-0.9-115.1 0-31.1 0-87 0-115.1 26 0 82.6 0 115.1 0 32.3 0 91.9 0 115.1 0.9 0 30.9 0 83 0 114.2z"
			 repeatCount="indefinite"
			 fill="freeze"
	/>		 
 </path> 
</svg>	

 

Reverse movement

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
	  
     width="300" height="300" viewBox="0 0 300 300" >  
 <style>
  path {
  fill:dodgerblue;
    }
 </style>
 
<path  d="m268.3 164.3c0 31.4-12.6 59.9-33 80.7-20.9 21.2-49.9 34.4-82 34.4-31.5 0-60.1-12.7-80.9-33.3-21.1-20.9-34.1-49.8-34.1-81.8 0-31.1 12.3-59.3 32.4-80 20.9-21.6 50.2-35.1 82.7-35.1 32.3 0 61.6 13.3 82.5 34.8 20.2 20.7 32.6 49 32.6 80.2z">
   <animate attributeName="d"
     begin="0s"
	 dur="5s"
	 values="
	         m268.3 164.3c0 31.4-12.6 59.9-33 80.7-20.9 21.2-49.9 34.4-82 34.4-31.5 0-60.1-12.7-80.9-33.3-21.1-20.9-34.1-49.8-34.1-81.8 0-31.1 12.3-59.3 32.4-80 20.9-21.6 50.2-35.1 82.7-35.1 32.3 0 61.6 13.3 82.5 34.8 20.2 20.7 32.6 49 32.6 80.2z;
			 
			 m268.3 164.3c0 31.4 0 86.7 0 115.1-26.6 0-82.9 0-115.1 0-31.5 0-73.4 0-114.2 0-0.9-26.3-0.9-83.1-0.9-115.1 0-31.1 0-87 0-115.1 26 0 82.6 0 115.1 0 32.3 0 91.9 0 115.1 0.9 0 30.9 0 83 0 114.2z;
			 
			 m268.3 164.3c0 31.4-12.6 59.9-33 80.7-20.9 21.2-49.9 34.4-82 34.4-31.5 0-60.1-12.7-80.9-33.3-21.1-20.9-34.1-49.8-34.1-81.8 0-31.1 12.3-59.3 32.4-80 20.9-21.6 50.2-35.1 82.7-35.1 32.3 0 61.6 13.3 82.5 34.8 20.2 20.7 32.6 49 32.6 80.2z;"
			 
			 repeatCount="indefinite"
			 fill="freeze" 	/>		 
			 
 </path> 

</svg>

Smooth morphing animation can also be done with SnapJS

var svg = document.getElementById("svg1");
var s = Snap(svg);

var simpleCup = Snap.select('#coffee-cup');
var fancyCup = Snap.select('#fancy-cup');

var simpleCupPoints = simpleCup.node.getAttribute('d');
var fancyCupPoints = fancyCup.node.getAttribute('d');


var toFancy = function(){
  simpleCup.animate({ d: fancyCupPoints }, 1000, mina.backout, toSimple);  
}

var toSimple = function(){
  simpleCup.animate({ d: simpleCupPoints }, 1000, mina.backout, toFancy); 
}


toSimple();
 <svg id="svg1" width="100" height="130" viewBox="0 0 75 47" xmlns="http://www.w3.org/2000/svg">
	<path id="coffee-cup" fill="#5F0C2D" stroke="#5F0C2D"  d="M0.4 5.9C0.4 6.3-0.3 17.8 4.3 31.2 5.3 32.4 6.1 37.9 7.5 43 10.4 53.6 10 58.2 10 58.2 10 58.2 10 59.1 10 62.2L10 63.4 15 65.7C20.1 67.8 34 67.6 38.6 65.7L44 64 44 62.2C44 60.3 44 61.2 44 59.6 44 59.6 44 58.2 44 58.2 44 58.2 44 56 44 56 44 56.1 44.2 52.2 44.2 52.2 44.2 52.2 44.5 49.3 44.5 49.3 44 47 46.8 39.1 47.6 38.8 48.4 38.6 52.8 37.6 55.4 37 62.3 36.7 68.5 30.5 68.5 26.9 68.5 25.1 68.5 20.3 66.1 17.8 63.5 14.8 60.4 14.1 56.7 14.2 54.2 14.3 54.2 12.8 54 12.6 53.8 12.5 54 12.6 54 10.8L53.3 6.7 51.3 4.6C49.8 3.6 47.5 3 44.7 2.2 38.3 0.5 20.1 0 12.7 1.4 7 2.4 0.4 4.7 0.4 5.9ZM64.8 22.9C64.8 25.9 65.5 27.9 60.6 31.8 59.6 32.6 64 30.3 62.9 30.8 60.9 31.9 53.6 32.7 52.4 31.8 51.6 31.1 51.1 29.8 51 28 51.3 24.6 52.1 22.1 53.6 20.4 57.4 16 64.8 19.2 64.8 22.9Z"  />
    <path opacity="0"  id="fancy-cup" fill="#5F0C2D" stroke="#5F0C2D"  d="M0 6.8C0 7.2 0.9 8.5 1.9 9.6 2.9 10.8 4.9 15.9 6.3 21 9.2 31.6 12.4 36.5 17.5 38.2 21.6 39.6 21.7 39.8 18.8 42.2L16.5 44 19.5 45.3C24.6 47.4 37 47.6 41.6 45.7L45.5 44.1 43.1 42.1C41 40.4 40.9 39.9 42.1 39.1 42.8 38.6 44.2 38.2 45.1 38.2 47 38.2 52.4 33.5 53.2 31.2 53.6 29.9 53.9 29.9 55.3 31 57.5 32.9 59.1 31.6 58.4 28.6 58 27 58.3 26.1 59.1 25.8 59.9 25.6 62.6 24.8 65.2 24.2 70.7 22.7 75 19 75 15.5 75 13.7 74.1 12.7 71.3 11.6 68 10.2 67.3 10.2 63.7 11.6 61.4 12.5 59.5 13 59.3 12.8 59.1 12.7 59.9 11.3 61 9.9L63.1 7.3 60.5 5.6C59 4.6 55.5 3.2 52.7 2.4 46.3 0.7 21.5-0.1 14.1 1.3 8.4 2.3 0 5.6 0 6.8ZM70 15.6C70 18.6 65.7 22.2 62.3 22.2 61 22.2 59 22.7 57.9 23.2 55.9 24.3 55.5 23.6 56.6 20.8 56.9 19.9 57.6 19.5 58.1 19.8 58.6 20.1 60.5 18.7 62.2 16.8 66 12.4 70 11.9 70 15.6Z"  />

</svg>
  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.5.1/snap.svg-min.js"></script>

Upvotes: 9

Related Questions