随机自然运动jquery

发布于 2024-09-25 20:12:08 字数 312 浏览 7 评论 0原文

如何使用 jquery 为图像重新创建这种类型的运动: http://www.istockphoto.com/stock-video-12805249-moving-articles-loop-soft-green-hd-1080.php

我打算将其用作网络页面背景。如果 jquery 无法实现,我将使用 flash as3。但我更喜欢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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

日久见人心 2024-10-02 20:12:09

我这边的答案很晚,但我想我可能会给出一种方法......

我个人会使用 svg 矢量图像。
创建一个接受不透明度、大小的 jquery 插件。并使它们朝随机方向移动。
然后执行一个 javascript 循环来创建一组这些粒子(其中不透明度和大小是随机的,加上起始位置是随机的)
然后让 jquery 插件在粒子卸载时启动其自身的新实例。

(如果您观看小电影,您会看到它们朝一个方向移动并淡出,然后另一个方向淡入。)

不透明效果将提供深度透视。

不确定我的回答是否有帮助,但我会朝那个方向走。

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.

一张白纸 2024-10-02 20:12:08

编辑: Raphael 绝对更适合这个,因为它支持 IE。 jQuery 的问题在于,由于 CSS 的限制,在 IE 中做圆角是一件很痛苦的事情……在 Raphael 中,跨浏览器圈子是不费吹灰之力的。

jsFiddle with Raphael - 所有浏览器:(

尽管它可能看起来更好在 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 ";
                }());
        }
    };
}());​

第一次尝试 jQuery解决方案如下:


这个 jQuery 尝试在 IE 中几乎失败,并且在 FF 中很慢。 Chrome 和 Safari 表现良好:

适用于所有浏览器的 jsFiddle 示例(IE 不太好)

(我没有在IE中实现淡入淡出,并且IE没有圆角...而且JS速度较慢,所以整体看起来很糟糕)

仅适用于 Chrome 和 Safari 的 jsFiddle 示例(粒子数量增加 4 倍)

(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 ";            
        });        
    });
}());
​

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 ";            
        });        
    });
}());
​
方圜几里 2024-10-02 20:12:08

[部分答案,仅用于物理学。]

[我刚刚看到了之前的答案,我的答案有点相同。]

您可以尝试模拟某种布朗运动,即导出的运动
来自随机力和粘性阻尼的组合。伪代码:

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
}

保持较长的阻尼时间(~ 1 秒)和较小的随机力幅度。否则动作可能会过于生涩。

对于易于实现的高斯随机数生成器,请在 Wikipedia 中查找 Box-Muller。

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

意犹 2024-10-02 20:12:08

对于它的数学,你给每个物体一个起始位置和速度。 “随机游走”是通过计算受一定量(实验)约束的随机角度来实现的。然后将速度矢量的角度改变这个角度。您还可以计算随机速度增量并按该量更改矢量的大小。因为你正在以速度工作,所以动作会有些平滑。一种稍微更先进的方法,可以直接使用加速度并根据加速度计算速度和位置。

对于随机转向值,二项分布优于均匀分布。二项式分布集中在 0 附近,而不是均匀分布。您可以只执行 random() - random() (伪代码)

矢量数学已被广泛记录,但如果您遇到困难,请发表评论。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文