Javascript 您将如何为某些内容设置动画以使其遵循曲线?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2240052/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 23:24:57  来源:igfitidea点击:

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

javascriptjqueryanimation

提问by Justen

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

如果我有
<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?

即使那不是正确的代码,我相信 animate 只需要“目的地”才能到达目的地,所以我认为动态目的地是行不通的。我在寻找什么来完成这项工作?

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

这是使用 for 循环和延迟方法的另一种尝试

$('#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?

除了它立即进入那个位置,没有延迟或任何东西。所以如果它从 [0,0] 开始,只要我点击它,它就会传送到 [400,600]。为什么延迟不起作用?

采纳答案by Adam Kiss

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)

我认为这一次,您必须在 js 中逐部分重新计算动画曲线,然后通过小部分移动来完成(= 您可能可以找到插件,或者您必须自己完成所有数学运算)

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

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

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/

编辑 1:这引起了我的兴趣,所以我做了很少的谷歌研究 - 正如我所想的:插件准备在这里使用:http: //foxparker.wordpress.com/2009/09/22/bezier-curves-and-arcs-in -jquery/

回答by philfreo

The jQuery.path pluginis what you want:

jQuery.path插件是你想要什么:

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

回答by Phrogz

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.)

这是我编写的一个简单的小库,它允许为动画路径使用任意三次贝塞尔曲线,甚至可以为您计算旋转角度。(该库尚未完善或记录,但它表明即使您的页面中没有 SVG 元素,站在 SVG DOM 的肩膀上是多么容易。)

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

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

回答by James

Are you using jQuery 1.4?

你在使用 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

你需要缓动插件才能工作:http: //gsgd.co.uk/sandbox/jquery/easing/jquery.easing.1.3.js

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

例如http://jsbin.com/ofiye3/2

回答by vsync

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

有一个小脚本,仅用于非直线的动画,称为pathAnimator

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

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