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.
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.
(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:
(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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With