如何使物体沿着曲线运动?

24
如果我有一个 <div id="curve" style="position:relative; height:100px; width:100px; /> 如何让它沿着曲线移动?我已经搜索了一切,但似乎找不到同时调用两个函数的另一个示例。这是我想要的代码,但并不起作用:
$('#curve').click(function () {
    $(this).animate(
        { 
            top: 400,
            left = $(this).left() + $(this).left()*$(this).left()
        },
        'slow',
        function() { $(this).animate( { left: 600 }, 'fast' ); }
    );
});
即使这不是正确的代码,我相信animate只接受要前往的“目标位置”,因此我认为动态目标位置不起作用。我需要什么才能使它工作?
编辑:我肯定会尝试那个插件,但我也想知道为什么这段代码不像我预期的那样工作。
这里是另一种尝试,使用for循环和延迟方法。
$('#curve').click(function () {
    for (var i=0; i<400; i++ )
    {
        $(this).delay(1000);
        $(this).css( { top: i, left: i*1.5 } );
    }
});

除了立即进入那个位置,没有任何延迟或其他东西。因此,如果它从[0,0]开始,我一点击它,它就瞬间传送到[400,600]。为什么延迟不起作用?


我认为jQuery中没有延迟函数,除非您使用延迟插件... - Adam Kiss
请确保您正在使用 jQuery 的 v1.4+ 版本。 - philfreo
尝试使用 $(this).delay(1000).css({ top: i, left: i*1.5 }); - philfreo
好吧,我猜它能工作。所以你没有用循环,而是用了递归。在JS中递归使用频率有多高? - Justen
啊,太酷了。所以问题就在于“+px”这一部分 =/。而且递归的部分也很有用。感谢你提供的所有帮助和示例。 - Justen
5个回答

16

jQuery.path插件是你想要的:

示例:沿着一个弧线进行动画

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

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

示例:沿正弦波动画

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});

@philfreo,jquery.path插件似乎不再起作用了。还有其他的方法吗? - alias51

16

我认为,这次你需要在javascript中逐部分重新计算动画曲线,然后通过移动小部分来完成(= 你可能可以找到插件,或者你要自己做所有的数学计算)

编辑2:之前添加的链接已经被移动=> http://foxparker.wordpress.com/2009/09/22/bezier-curves-and-arcs-in-jquery/。谢谢,Zach。

编辑1:这激起了我的兴趣,所以我进行了一些谷歌搜索——正如我所想的那样:可以使用插件,在此处准备就绪:http://foxparker.wordpress.com/2009/09/22/bezier-curves-and-arcs-in-jquery/


谢谢提供链接。它会非常有用,你能看看我的修改吗? - Justen
2
更新链接:http://foxparker.wordpress.com/2009/09/22/bezier-curves-and-arcs-in-jquery/ - Zach Lysobey

11
这是我写的一个简单小库,可以为动画路径提供任意三次贝塞尔曲线,甚至可以为您计算旋转角度。(该库尚未完善或文档化,但它展示了即使在页面中没有SVG元素时,如何轻松地站在SVG的DOM的肩膀上。) http://phrogz.net/SVG/animation_on_a_curve.html 网站截图 您可以编辑代码并观看曲线/动画变化,也可以编辑曲线并查看代码更新。 万一我的网站挂了,这里是相关的代码。
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;
};

我有些困惑:您的库是否可以用于沿着由bezierCurveTo定义的贝塞尔曲线进行动画,还是需要有一个SVG路径? - Thomas
1
@Thomas 如上所示,CurveAnimator 构造函数接受四个点并为您创建一个简单的路径。但是,如果您将动画器的 .path 属性设置为具有任意路径的 SVG 路径(不必在页面上),则可以实现您想要的效果。 - Phrogz

7

1

有一个很小的脚本,专门用于非直线动画,叫做pathAnimator

它非常非常小而且超级高效。而且您甚至不需要jQuery ;)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接