jQuery animating along a sine wave

2019-02-24 12:41发布

I've spent a couple days at this and I give up.

I'm trying to get an object to animate along a sine wave infinitely. It should not end after the first period.

Main Problem: The cycle ends at approx 1 1/3 Pi rather than just Pi. This extra movement ruins the animation.

I'm stuck here: http://jsfiddle.net/WPnQG/12/. After each period, it skips about 40 pixels and then continues along its path. This is the problem I can't get past -- the value it ends at and proceeds to restart at are not equal, so the object appears to skip around. Could anyone help a man out? Thanks

I am using the jQuery Path Plugin to perform the path of the animation -- the sine wave in question.

enter image description here


Source:

function float(dir){
    var x_current = $("div").offset().left;
    var y_current = $("div").offset().top;
    var SineWave = function() {
        this.css = function(p) {
            var s = Math.sin(Math.abs(p-1)*10);
            if (!dir){// flip the sin wave to continue traversing
               s = -s;
            }
            var x =  300 -p * 300;
            var y = s * 100 + 150;
            //var o = ((s+2)/4+0.1); //opacity change
            last_x = x;
            // add the current x-position to continue the path, rather than restarting
            return {top: y + "px", left: x_current + x + "px"};
        } 
    };

    $("div").stop().animate({
        path: new SineWave
    }, 5000, 'linear', function(){
        // avoid exceeding stack
        setTimeout(function(){float(!dir)}, 0);
    });

}

6条回答
我命由我不由天
2楼-- · 2019-02-24 13:23
姐就是有狂的资本
3楼-- · 2019-02-24 13:28

I must confess i was a bit confused about how this was written however i do understand you got it from the wiki. It just struck me as odd that the sin wave went beyond 2 pi before restarting. Typically a sin wave is from 0 to 2pi for a complete loop. I have some updated javascript taking this into account and the hiccup is now gone.

function float(dir){
var x_current = $("div").offset().left;
var y_current = $("div").offset().top;
var SineWave = function() {
    this.css = function(p) {
        var pi2 = (3.1415927 * 2);
        var a = p * pi2;
        var s = Math.sin((pi2 - a)*2);
        var x =  300 * (1 - p);
        var y = s * 100 + 150;
        //var o = ((s+2)/4+0.1); //opacity change
        last_x = x;
        // add the current x-position to continue the path, rather than restarting
        return {top: y + "px", left: x_current + x + "px"};
    }
};

$("div").stop().animate({
    path: new SineWave
}, 5000, 'linear', function(){
    // avoid exceeding stack
    setTimeout(function(){float(!dir)}, 0);
});

}

float(true);

Note: you can tell it how many sin waves to complete by changing the constant in s (1 is one full sin wave, 2 is two full sin waves, etc.) Also, there is no more need to "reverse" the wave.

JSFiddle link: http://jsfiddle.net/P5vqG/8/

查看更多
不美不萌又怎样
4楼-- · 2019-02-24 13:30

When I comment out this line:

setTimeout(function(){float(!dir)}, 0);

the element stops motion precisely on the line marked It skips here.

It appears that when you reset the motion to // avoid exceeding stack it resets the position of the element to to y=0, while preserving the x value of the element as well as its path of motion.

This hypothesis is further validated in that when ever a skip occurs (anywhere on the y axis) the element always resumes its motion from y=0. Sometimes its y value is > y = 0 while sometimes it is < y = 0 -- thus the random looking "skipping around."

Edit

Going back to the source sine demo, it seems you can get near infinite scrolling, by manipulating the x= ... line. After some looking at the original source, it appears that the demo script was only written to accommodate that one specific example and fixed width problems.

Here is a working example.

By manipulating the numbers on line 1 and 2 you can specify the number of pixels for the path to traverse, and the slow the path down on line 3 to make it the same speed as the original demo. So, not mathematically infinite, but it took a good 45 seconds to complete on my computer. By manipulating these specific lines you can make it as "infinite" as you need.

window.SineWave = SineWave = function() {
    this.css = function(p) {
        s = Math.sin((p-1)*500);  // 1
        x = (5000 - p*5000) * 10; // 2
        y = s * 100 + 150;
        return {top: y + "px", left: x + "px"};
    } 
}

  $("#nyan").stop().animate(
        {path: new SineWave}, 
        50000, // 3
        "linear"
  );
查看更多
【Aperson】
5楼-- · 2019-02-24 13:38

You can use PathAnimator to animate anything along any path. you only need the SVG coordinates that describe your path.

Demo Page

查看更多
Summer. ? 凉城
6楼-- · 2019-02-24 13:38

Here's a solution (demonstrated in this fiddle) to making a Sinusoidal Wave just by using Jquery's four .animate parameters:

    $("div").animate({ left: [ '+=8%', 'linear' ],  
                       top:  [ '+=5%' , 'swing'  ]  }, 1000, null, function() {
        $(this).animate({ left: [ '+=8%', 'linear' ],  
                          top:  [ '-=5%' , 'swing'  ]  }, 1000, null, function() {
            $(this).animate({ left: [ '+=8%', 'linear' ],  
                                  top:  [ '+=5%' , 'swing'  ]  }, 1000, null, function() {
                $(this).animate({ left: [ '+=8%', 'linear' ],  
                                      top:  [ '-=5%' , 'swing'  ]  }, 1000, null, function() {

                        //(etc.)
                })                                                                                  

            })
        })
    })
查看更多
贼婆χ
7楼-- · 2019-02-24 13:40

Change

 return {top: y + "px", left: current_x + x + "px"}; 

to

  return {top: y + "px", left: last_x + x + "px"};

See an updated fiddle

查看更多
登录 后发表回答