最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Random natural movement jquery - Stack Overflow

programmeradmin3浏览0评论

How can I recreate this type movement with jquery for images: .php

I'm planning to use it as a web page background. If it is not possible with jquery I'll go with flash as3. But I prefer jquery.

How can I recreate this type movement with jquery for images: http://www.istockphoto.com/stock-video-12805249-moving-particles-loop-soft-green-hd-1080.php

I'm planning to use it as a web page background. If it is not possible with jquery I'll go with flash as3. But I prefer jquery.

Share Improve this question edited Feb 14, 2011 at 19:47 HasanG asked Oct 1, 2010 at 8:50 HasanGHasanG 13.2k31 gold badges102 silver badges159 bronze badges 1
  • 3 [ Raphael ](raphaeljs.com) might be better suited for this than jQuery. – Peter Ajtai Commented Oct 1, 2010 at 9:14
Add a comment  | 

4 Answers 4

Reset to default 10

Edit: Raphael is definitely better suited for this, since it supports IE. The problem with jQuery is that the rounded corners are a pain to do in IE due to CSS constraints... in Raphael cross browser circles are no sweat.

jsFiddle with Raphael - all browsers:

(though it might look nicer speeded up in IE)

(function() {
    var paper, circs, i, nowX, nowY, timer, props = {}, toggler = 0, elie, dx, dy, rad, cur, opa;
    // Returns a random integer between min and max  
    // Using Math.round() will give you a non-uniform distribution!  
    function ran(min, max)  
    {  
        return Math.floor(Math.random() * (max - min + 1)) + min;  
    } 

    function moveIt()
    {
        for(i = 0; i < circs.length; ++i)
        {            
              // Reset when time is at zero
            if (! circs[i].time) 
            {
                circs[i].time  = ran(30, 100);
                circs[i].deg   = ran(-179, 180);
                circs[i].vel   = ran(1, 5);  
                circs[i].curve = ran(0, 1);
                circs[i].fade  = ran(0, 1);
                circs[i].grow  = ran(-2, 2); 
            }                
                // Get position
            nowX = circs[i].attr("cx");
            nowY = circs[i].attr("cy");   
               // Calc movement
            dx = circs[i].vel * Math.cos(circs[i].deg * Math.PI/180);
            dy = circs[i].vel * Math.sin(circs[i].deg * Math.PI/180);
                // Calc new position
            nowX += dx;
            nowY += dy;
                // Calc wrap around
            if (nowX < 0) nowX = 490 + nowX;
            else          nowX = nowX % 490;            
            if (nowY < 0) nowY = 490 + nowY;
            else          nowY = nowY % 490;

                // Render moved particle
            circs[i].attr({cx: nowX, cy: nowY});

                // Calc growth
            rad = circs[i].attr("r");
            if (circs[i].grow > 0) circs[i].attr("r", Math.min(30, rad +  .1));
            else                   circs[i].attr("r", Math.max(10,  rad -  .1));

                // Calc curve
            if (circs[i].curve > 0) circs[i].deg = circs[i].deg + 2;
            else                    circs[i].deg = circs[i].deg - 2;

                // Calc opacity
            opa = circs[i].attr("fill-opacity");
            if (circs[i].fade > 0) {
                circs[i].attr("fill-opacity", Math.max(.3, opa -  .01));
                circs[i].attr("stroke-opacity", Math.max(.3, opa -  .01)); }
            else {
                circs[i].attr("fill-opacity", Math.min(1, opa +  .01));
                circs[i].attr("stroke-opacity", Math.min(1, opa +  .01)); }

            // Progress timer for particle
            circs[i].time = circs[i].time - 1;

                // Calc damping
            if (circs[i].vel < 1) circs[i].time = 0;
            else circs[i].vel = circs[i].vel - .05;              

        } 
        timer = setTimeout(moveIt, 60);
    }

    window.onload = function () {
        paper = Raphael("canvas", 500, 500);
        circs = paper.set();
        for (i = 0; i < 30; ++i)
        {
            opa = ran(3,10)/10;
            circs.push(paper.circle(ran(0,500), ran(0,500), ran(10,30)).attr({"fill-opacity": opa,
                                                                           "stroke-opacity": opa}));
        }
        circs.attr({fill: "#00DDAA", stroke: "#00DDAA"});
        moveIt();
        elie = document.getElementById("toggle");
        elie.onclick = function() {
            (toggler++ % 2) ? (function(){
                    moveIt();
                    elie.value = " Stop ";
                }()) : (function(){
                    clearTimeout(timer);
                    elie.value = " Start ";
                }());
        }
    };
}());​

The first attempt jQuery solution is below:


This jQuery attempt pretty much failes in IE and is slow in FF. Chrome and Safari do well:

jsFiddle example for all browsers (IE is not that good)

(I didn't implement the fade in IE, and IE doesn't have rounded corners... also the JS is slower, so it looks pretty bad overall)

jsFiddle example for Chrome and Safari only (4x more particles)

(function() {
    var x, y, $elie, pos, nowX, nowY, i, $that, vel, deg, fade, curve, ko, mo, oo, grow, len;

    // Returns a random integer between min and max  
    // Using Math.round() will give you a non-uniform distribution!  
    function ran(min, max)  
    {  
        return Math.floor(Math.random() * (max - min + 1)) + min;  
    } 

    function moveIt()
    {
        $("div.spec").each(function(i, v) {
            $elie = $(v);
            if (! $elie.data("time"))
            {
                $elie.data("time", ran(30, 100));
                $elie.data("deg", ran(-179, 180));
                $elie.data("vel", ran(3, 10));  
                $elie.data("curve", ran(0, 1));
                $elie.data("fade", ran(0, 1));
                $elie.data("grow", ran(-2, 2));                
            }

            vel = $elie.data("vel");
            deg = $elie.data("deg");
            fade = $elie.data("fade");            
            curve = $elie.data("curve");
            grow = $elie.data("grow");

            len = $elie.width();
            if (grow > 0)
                len = Math.min(len + grow, 50);
            else
                len = Math.max(len + grow, 20);

            $elie.css("-moz-border-radius", len/2);
            $elie.css("border-radius", len/2);

            $elie.css("width", len);
            $elie.css("height", len);

            pos = $elie.position();            

            $elie.data("time", $elie.data("time") - 1);

            if (curve)
                $elie.data("deg", (deg + 5) % 180);
            else
                $elie.data("deg", (deg - 5) % 180);

            ko = $elie.css("-khtml-opacity");
            mo = $elie.css("-moz-opacity");
            oo = $elie.css("opacity");
            if (fade)
            {
                $elie.css("-khtml-opacity", Math.max(ko - .1, .5));
                $elie.css("-moz-opacity", Math.max(mo - .1, .5));
                $elie.css("opacity", Math.max(oo - .1, .5));
            } else
            {
                $elie.css("-khtml-opacity", Math.min(ko - -.1, 1));
                $elie.css("-moz-opacity", Math.min(mo - -.1, 1));
                $elie.css("opacity", Math.min(oo - -.1, 1));                
            }

            if (vel < 3)
                $elie.data("time", 0);
            else
                $elie.data("vel", vel - .2);            


            nowX = pos.left;
            nowY = pos.top;

            x = vel * Math.cos(deg * Math.PI/180);
            y = vel * Math.sin(deg * Math.PI/180);

            nowX = nowX + x;            
            nowY = nowY + y;

            if (nowX < 0)
                nowX = 490 + nowX;
            else
                nowX = nowX % 490;

            if (nowY < 0)
                nowY = 490 + nowY;
            else
                nowY = nowY % 490;            
            $elie.css("left", nowX);
            $elie.css("top",  nowY);
        });
    }
    $(function() {
        $(document.createElement('div')).appendTo('body').attr('id', 'box');
        $elie = $("<div/>").attr("class","spec");
        // Note that math random is inclussive for 0 and exclussive for Max
        for (i = 0; i < 100; ++i)
        {
            $that = $elie.clone();  
            $that.css("top", ran(0, 495));
            $that.css("left", ran(0, 495));            
            $("#box").append($that);            
        }          
        timer = setInterval(moveIt, 60);
        $("input").toggle(function() {
            clearInterval(timer);
            this.value = " Start ";
        }, function() {
            timer = setInterval(moveIt, 60);        
            this.value = " Stop ";            
        });        
    });
}());
​

[Partial answer, just for the physics.]

[I just saw the previous answer, mine is somewhat along the same lines.]

You may try to simulate some sort of Brownian motion, i.e. a movement deriving from the combination of a random force and a viscous damping. Pseudocode:

initialize:
    x = random_position();
    v_x = random_velocity();  // v_x = velocity along x
    // and same for y
for (each time step) {
    x += v_x;
    v_x += random_force() - time_step / damping_time * v_x;
    // and same for y
}

Keep the damping time long (~ 1 second) and the amplitude of the random force small. Otherwise the movement may be too jerky.

For an easy to implement Gaussian random number generator, look up Box-Muller in Wikipedia.

For the mathematics of it, you give every object a starting position and velocity. The "random walk" is achieved by computing a random angle that is constrained by some amount (experiment). Then change the angle of the velocity vector by this angle. You can also compute a random speed delta and change the magnitude of the vector by that amount. Because you're working with velocity, the movements will be somewhat smooth. A slightly more advanced approach to to work with acceleration directly and compute velocity and position based off that.

For your random steering value, a binomial distribution is preferable to a uniform one. Binomial distributions are concentrated around 0 instead of uniformly spread out. You can just do random() - random() (psuedocode)

Vector math is extensively documented but if you run into a snag, leave a comment.

very late answer from my side, but I thought I might give an approach...

I personally would use an svg vector image. Create a jquery plugin which accepts opacity, size. and makes them move in a random direction. Then do a javascript loop in creating a set of those particles (where opacity and size are random, plus the start location is random) Then make the jquery plugin to initiate a new instance of itself when the particle is unloaded.

(If you look at the little movie you will see that they move in 1 direction and fade out, then another fades in.)

The opacity effect will give the depth perspective.

Not sure if my answer helps, but I would go in that direction.

发布评论

评论列表(0)

  1. 暂无评论