How would you animate something so that it follows a curve?

If I have
<div id="curve" style="position:relative; height:100px; width:100px; />

How would I make it move on a curve? I've googled and everything but can't seem to find another example that would call two functions at once. This is the kind of code I would like, but doesn't work:

$('#curve').click(function () {
    $(this).animate(
        { 
            top: 400,
            left = $(this).left() + $(this).left()*$(this).left()
        },
        'slow',
        function() { $(this).animate( { left: 600 }, 'fast' ); }
    );
});

Even if that's not correct code, I believe animate only takes "destinations" for something to go to, so a dynamic destination wouldn't work I think. What am I looking for to make this work?

EDIT:: I'll definitely pick up that plugin, but I'm also wonder why this bit of code doesn't work as I'd expect it to.

Here's another attempt using a for loop and the delay method

$('#curve').click(function () {
    for (var i=0; i<400; i++ )
    {
        $(this).delay(1000);
        $(this).css( { top: i, left: i*1.5 } );
    }
});

Except it just instantly goes to that position, no delay or anything. so if it was starting at [0,0], as soon as I click it it teleports to [400,600]. Why doesn't the delay work?

Answers:

Answer

I think that this time, you have to recalculate animated curve part by part in js and then do it by moving by little parts (= you probably could find plugin OR you'll have to do all the math by yourself)

Edit 2: Previously added link was moved=> http://foxparker.wordpress.com/2009/09/22/bezier-curves-and-arcs-in-jquery/. Thanks, Zach.

Edit 1: this intrigued me, so I did little google research - just as I thought: plugin ready for use here: http://foxparker.wordpress.com/2009/09/22/bezier-curves-and-arcs-in-jquery/

Answer

The jQuery.path plugin is what you want:

Example: animate along an arc

var arc_params = {
    center: [285,185],  
    radius: 100,    
    start: 30,
    end: 200,
    dir: -1
};

$("my_elem").animate({path : new $.path.arc(arc_params)});

Example: animate along a sine wave

var SineWave = function() {
    this.css = function(p) {
        var s = Math.sin(p*20);
        var x = 500 - p * 300;
        var y = s * 50 + 150;
        var o = ((s+2)/4+0.1);
        return {top: y + "px", left: x + "px", opacity: o};
    } 
};

$("my_elem").animate({path : new SineWave});
Answer

Here's a simple little library I wrote that allows arbitrary cubic Bézier curves for an animation path, and even calculates the rotation angle for you. (The library isn't polished or documented yet, but it shows how easy it is to stand on the shoulders of SVG's DOM even when you have no SVG elements in your page.)

http://phrogz.net/SVG/animation_on_a_curve.html

Screenshot of website

You can either edit the code and watch the curve/animation change, or edit the curve and see the code update.

In case my site is down, here's the relevant code for posterity:

function CurveAnimator(from,to,c1,c2){
  this.path = document.createElementNS('http://www.w3.org/2000/svg','path');
  if (!c1) c1 = from;
  if (!c2) c2 = to;
  this.path.setAttribute('d','M'+from.join(',')+'C'+c1.join(',')+' '+c2.join(',')+' '+to.join(','));
  this.updatePath();
  CurveAnimator.lastCreated = this;
}
CurveAnimator.prototype.animate = function(duration,callback,delay){
  var curveAnim = this;
  // TODO: Use requestAnimationFrame if a delay isn't passed
  if (!delay) delay = 1/40;
  clearInterval(curveAnim.animTimer);
  var startTime = new Date;
  curveAnim.animTimer = setInterval(function(){
    var elapsed = ((new Date)-startTime)/1000;
    var percent = elapsed/duration;
    if (percent>=1){
      percent = 1;
      clearInterval(curveAnim.animTimer);
    }
    var p1 = curveAnim.pointAt(percent-0.01),
        p2 = curveAnim.pointAt(percent+0.01);
    callback(curveAnim.pointAt(percent),Math.atan2(p2.y-p1.y,p2.x-p1.x)*180/Math.PI);
  },delay*1000);
};
CurveAnimator.prototype.stop = function(){
  clearInterval(this.animTimer);
};
CurveAnimator.prototype.pointAt = function(percent){
  return this.path.getPointAtLength(this.len*percent);
};
CurveAnimator.prototype.updatePath = function(){
  this.len = this.path.getTotalLength();
};
CurveAnimator.prototype.setStart = function(x,y){
  var M = this.path.pathSegList.getItem(0);
  M.x = x; M.y = y;
  this.updatePath();
  return this;
};
CurveAnimator.prototype.setEnd = function(x,y){
  var C = this.path.pathSegList.getItem(1);
  C.x = x; C.y = y;
  this.updatePath();
  return this;
};
CurveAnimator.prototype.setStartDirection = function(x,y){
  var C = this.path.pathSegList.getItem(1);
  C.x1 = x; C.y1 = y;
  this.updatePath();
  return this;
};
CurveAnimator.prototype.setEndDirection = function(x,y){
  var C = this.path.pathSegList.getItem(1);
  C.x2 = x; C.y2 = y;
  this.updatePath();
  return this;
};
Answer

Are you using jQuery 1.4?

$(this).animate({
    left: [500, 'easeInSine'],
    top: 500
});

You'll require the easing plugin for this to work: http://gsgd.co.uk/sandbox/jquery/easing/jquery.easing.1.3.js

E.g. http://jsbin.com/ofiye3/2

Answer

There's a tiny script, just for animation which isn't in straight lines, called pathAnimator

It's very very small and super efficient. and you don't even need jQuery ;)

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.