x);
newY = 0.5 * (point.y + nextPoint.y);
newY += dx * (Math.random() * 2 - 1);

var newPoint = {
x: newX,
y: newY
};

//min, max
if (newY < minY) {
minY = newY;
} else if (newY > maxY) {
maxY = newY;
}

//put between points
newPoint.next = nextPoint;
point.next = newPoint;

point = nextPoint;
}
}

//normalize to values between 0 and 1
if (maxY != minY) {
var normalizeRate = 1 / (maxY - minY);
point = pointList.first;
while (point != null) {
point.y = normalizeRate * (point.y - minY);
point = point.next;
}
} else {
point = pointList.first;
while (point != null) {
point.y = 1;
point = point.next;
}
}

return pointList;
};

/**
* Defines a new raindrop object.
* @param rainyday reference to the parent object
* @param centerX x position of the center of this drop
* @param centerY y position of the center of this drop
* @param min minimum size of a drop
* @param base base value for randomizing drop size
*/

function Drop(rainyday, centerX, centerY, min, base) {
this.x = Math.floor(centerX);
this.y = Math.floor(centerY);
this.r1 = (Math.random() * base) + min;
this.rainyday = rainyday;
var iterations = 4;
this.r2 = 0.8 * this.r1;
this.linepoints = rainyday.getLinepoints(iterations);
this.context = rainyday.context;
this.reflection = rainyday.reflected;
}

/**
* Draws a raindrop on canvas at the current position.
*/
Drop.prototype.draw = function() {
var phase = 0;
var point;
var rad, theta;
var x0, y0;

this.context.save();
this.context.beginPath();
point = this.linepoints.first;
theta = phase;
rad = this.r2 + 0.5 * Math.random() * (this.r2 - this.r1);
x0 = this.x + rad * Math.cos(theta);
y0 = this.y + rad * Math.sin(theta);
this.context.lineTo(x0, y0);
while (point.next != null) {
point = point.next;
theta = (Math.PI * 2 * point.x) + phase;
rad = this.r2 + 0.5 * Math.random() * (this.r2 - this.r1);
x0 = this.x + rad * Math.cos(theta);
y0 = this.y + rad * Math.sin(theta);
this.context.lineTo(x0, y0);
}

this.context.clip();

if (this.rainyday.reflection) {
this.rainyday.reflection(this);
}

this.context.restore();
};

/**
* Clears the raindrop region.
* @param force force stop
* @returns true if the animation is stopped
*/
Drop.prototype.clear = function(force) {
this.context.clearRect(this.x - this.r1 - 1, this.y - this.r1 - 1, 2 * this.r1 + 2, 2 * this.r1 + 2);
if (force) {
// forced
clearInterval(this.intid);
return true;
}
if (this.y - this.r1 > this.rainyday.h) {
// over the bottom edge, stop the thread
clearInterval(this.intid);
return true;
}
if ((this.x - this.r1 > this.rainyday.w) || (this.x + this.r1 < 0)) {
// over the right or left edge, stop the thread
clearInterval(this.intid);
return true;
}
return false;
};

/**
* Moves the raindrop to a new position according to the gravity.
*/
Drop.prototype.animate = function() {
this.intid = setInterval(
(function(self) {
return function() {
var stopped = self.rainyday.gravity(self);
if (!stopped && self.rainyday.trail) {
self.rainyday.trail(self);
}
if (self.rainyday.VARIABLE_COLLISIONS) {
var collision = self.rainyday.matrix.update(self, stopped);
if (collision) {
self.rainyday.collision(self, collision.drop);
}
}
}
})(this),
Math.floor(1000 / this.rainyday.VARIABLE_FPS)
);
};

/**
* TRAIL function: no trail at all
* @param drop raindrop object
*/
RainyDay.prototype.TRAIL_NONE = function(drop) {
// nothing going on here
};

/**
* TRAIL function: trail of small drops (default)
* @param drop raindrop object
*/
RainyDay.prototype.TRAIL_DROPS = function(drop) {
if (!drop.trail_y || drop.y - drop.trail_y >= Math.random() * 10 * drop.r1) {
drop.trail_y = drop.y;
this.putDrop(new Drop(this, drop.x, drop.y - drop.r1 - 5, 0, Math.ceil(drop.r1 / 5)));
}
};

/**
* GRAVITY function: no gravity at all
* @param drop raindrop object
* @returns true if the animation is stopped
*/
RainyDay.prototype.GRAVITY_NONE = function(drop) {
return true;
};

/**
* GRAVITY function: linear gravity
* @param drop raindrop object
* @returns true if the animation is stopped
*/
RainyDay.prototype.GRAVITY_LINEAR = function(drop) {
if (drop.clear()) {
return true;
}

if (drop.yspeed) {
drop.yspeed += this.PRIVATE_GRAVITY_FORCE_FACTOR_Y * Math.floor(drop.r1);
drop.xspeed += this.PRIVATE_GRAVITY_FORCE_FACTOR_X * Math.floor(drop.r1);
} else {
drop.yspeed = this.PRIVATE_GRAVITY_FORCE_FACTOR_Y;
drop.xspeed = this.PRIVATE_GRAVITY_FORCE_FACTOR_X;
}

drop.y += drop.yspeed;
drop.draw();
return false;
};

/**
* GRAVITY function: non-linear gravity (default)
* @param drop raindrop object
* @returns true if the animation is stopped
*/
RainyDay.prototype.GRAVITY_NON_LINEAR = function(drop) {
if (drop.clear()) {
return true;
}

if (!drop.seed || drop.seed < 0) {
drop.seed = Math.floor(Math.random() * this.VARIABLE_FPS);
drop.skipping = drop.skipping == false ? true : false;
drop.slowing = true;
}

drop.seed--;

if (drop.yspeed) {
if (drop.slowing) {
drop.yspeed /= 1.1;
drop.xspeed /= 1.1;
if (drop.yspeed < this.PRIVATE_GRAVITY_FORCE_FACTOR_Y) {
drop.slowing = false;
}
} else if (drop.skipping) {
drop.yspeed = this.PRIVATE_GRAVITY_FORCE_FACTOR_Y;
drop.xspeed = this.PRIVATE_GRAVITY_FORCE_FACTOR_X;
} else {
drop.yspeed += 10 * this.PRIVATE_GRAVITY_FORCE_FACTOR_Y * Math.floor(drop.r1);
drop.xspeed += 10 * this.PRIVATE_GRAVITY_FORCE_FACTOR_X * Math.floor(drop.r1);
}
} else {
drop.yspeed = this.PRIVATE_GRAVITY_FORCE_FACTOR_Y;
drop.xspeed = this.PRIVATE_GRAVITY_FORCE_FACTOR_X;
}

drop.y += drop.yspeed;
drop.x += drop.xspeed;

drop.draw();
return false;
};

/**
* REFLECTION function: no reflection at all
* @param drop raindrop object
*/
RainyDay.prototype.REFLECTION_NONE = function(drop) {
this.context.fillStyle = this.VARIABLE_FILL_STYLE;
this.context.fill();
};

/**
* REFLECTION function: miniature reflection (default)
* @param drop raindrop object
*/
RainyDay.prototype.REFLECTION_MINIATURE = function(drop) {

Prev | Next
Pg.: 1 2 3 4 5


Back to home | File page

Subscribe | Register | Login | N