valentin vannay

valentincognito

[jQuery] Animate objects along a circular path

2015-11-20

Designers always come up with brilliant but challenging design ideas. I recently had to animate a div along a circular path when clicking on links and that was a little tricky for many reasons. So I felt the need to share it with anyone out there who is trying to achieve the same thing ! I obviously know that this can be entirely done with CSS3 animations but you know... Internet Explorer...

Demo

Here is a jsfiddle for a demonstration of what we are trying to achieve here.

Explanations

To make this animation possible I used a little plugin called jqueery.path. It is a quite old plugin but it did the job !

1. HTML

<body>
    <button onclick="driveTo(270);">270</button>
    <button onclick="driveTo(180);">180</button>
    <button onclick="driveTo(90);">90</button>
    <button onclick="driveTo(0);">0</button>
    <div class="wrapper">
        <div class="road"></div>
        <div class="car"></div>
    </div>
    <input id="pre_value" type="hidden" value="0">
</body>
The HTML is very basic. You have a few action button to called the anim function and move the object to a certain value. The wrapper contains the road and our moving object( the car). And not to forget an hidden input to store the current value of the car position. (from 0 to 360)

2. Javascript

// We initialize our object position to 360 when the document is ready
$(document).ready(function(){
    driveTo(360);
  });

// The animation function
// Take a degree as a paramater
  function driveTo(new_value){

      // Speeed of the animation
      var speedFactor = 5;

      // Value of the previous position of the car
      pre_value = document.getElementById("pre_value").value;

      // If the new value is bigger than the previous value it means that 
      // the object has to travel more than a full circle(>360). So we have to calculate
      // a few more things
      if (new_value > pre_value) {
        var diffToZero = pre_value;
        var speedToZero = diffToZero * speedFactor;
        var diff = 360 - new_value;
        var speed = diff * speedFactor;

        var arc_params = {
               	center: [180,180],
                   radius: 180,
                   start: pre_value,
                   end: 0,
                   dir: -1
              	}
    	  $(".car").animate({path : new $.path.arc(arc_params)},speedToZero,"linear")
        var arc_params = {
               	center: [180,180],
                   radius: 180,
                   start: 360,
                   end: new_value,
                   dir: -1
              	}
    	  $(".car").animate({path : new $.path.arc(arc_params)},speed,"linear")
      }

      // if the car doesn't have to travel more than a full circle that's
      // the easy case you just have to set the value of the starting and ending
      // point within the parameters of the arc.
      else{
        var diff = pre_value - new_value;
        var speed = diff * speedFactor;
        var arc_params = {
               	center: [180,180],
                   radius: 180,
                   start: pre_value,
                   end: new_value,
                   dir: -1
              	}
    	  $(".car").animate({path : new $.path.arc(arc_params)},speed,"linear")
      }
    document.getElementById("pre_value").value = new_value;
  }
The javascript is actually not that complicate but the problem is that if the object has to travel more than 360 degrees it gets crazy for some reasons... I don't know if the problem is related to the plugin but I have searched answers for many hours but never found a quick fix. Here you can see what happen without the fix: demo So how did I fix it ? Pretty simple, I check if the new value is bigger than the previous one. If true the object has to go to the position 0 first and then continue to the new value. And it works ! But with this solution we have to remove the easing effects otherwise the object travels to zero and decreases his speed a little when it reaches zero and then accelarates again to go to the final destination. I am pretty sure we could improve the code to fix this but I personnally didn't need any easing effects ! Hope this will help someone one day :)