/**
* Download by http://www.codefans.net.
* @param canvasid DOM id of the canvas used for rendering
* @param sourceid DOM id of the image element used as background image
* @param width width of the rendering
* @param height height of the rendering
* @param opacity opacity attribute value of the glass canvas (default: 1)
* @param blur blur radius (default: 20)
*/

function RainyDay(canvasid, sourceid, width, height, opacity, blur) {
this.canvasid = canvasid;
this.canvas = document.getElementById(canvasid);

this.sourceid = sourceid;
this.img = document.getElementById(sourceid);

// draw and blur the backgroiund image
this.prepareBackground(blur ? blur : 20, width, height);
this.w = this.canvas.width;
this.h = this.canvas.height;

// create the glass canvas
this.prepareGlass(opacity ? opacity : 1);

// assume default reflection mechanism
this.reflection = this.REFLECTION_MINIATURE;

// assume default trail mechanism
this.trail = this.TRAIL_DROPS;

// assume default gravity
this.gravity = this.GRAVITY_NON_LINEAR;

// drop size threshold for the gravity algorhitm
this.VARIABLE_GRAVITY_THRESHOLD = 3;

// gravity angle
this.VARIABLE_GRAVITY_ANGLE = Math.PI / 2;

// frames per second animation speed
this.VARIABLE_FPS = 25;

// context fill style when no REFLECTION_NONE is used
this.VARIABLE_FILL_STYLE = '#8ED6FF';

// collisions enabled by default
this.VARIABLE_COLLISIONS = false;

// assume default collision algorhitm
this.collision = this.COLLISION_SIMPLE;
}

/**
* Create the helper canvas for rendering raindrop reflections.
*/
RainyDay.prototype.prepareReflections = function() {
// new canvas
this.reflected = document.createElement('canvas');
this.reflected.width = this.canvas.width;
this.reflected.height = this.canvas.height;

var ctx = this.reflected.getContext('2d');

// rotate by 180 degress
ctx.translate(this.reflected.width / 2, this.reflected.height / 2);
ctx.rotate(Math.PI);

ctx.drawImage(this.img, -this.reflected.width / 2, -this.reflected.height / 2, this.reflected.width, this.reflected.height);
};

/**
* Create the glass canvas and position it directly over the main one.
* @param opacity opacity attribute value of the glass canvas
*/
RainyDay.prototype.prepareGlass = function(opacity) {
this.glass = document.createElement('canvas');
this.glass.width = this.canvas.width;
this.glass.height = this.canvas.height;
this.glass.style.position = "absolute";
this.glass.style.top = this.canvas.offsetTop;
this.glass.style.left = this.canvas.offsetLeft;
this.glass.style.zIndex = this.canvas.style.zIndex + 100;
this.canvas.parentNode.appendChild(this.glass);
this.context = this.glass.getContext('2d');
this.glass.style.opacity = opacity;
};

/**
* Creates a new preset object with given attributes.
* @param min minimum size of a drop
* @param base base value for randomizing drop size
* @param quan probability of selecting this preset (must be between 0 and 1)
* @returns present object with given attributes
*/
RainyDay.prototype.preset = function(min, base, quan) {
return {
"min": min,
"base": base,
"quan": quan
}
};

/**
* Main function for starting rain rendering.
* @param presets list of presets to be applied
* @param speed speed of the animation (if not provided or 0 static image will be generated)
*/
RainyDay.prototype.rain = function(presets, speed) {
// prepare canvas for drop reflections
if (this.reflection != this.REFLECTION_NONE) {
this.prepareReflections();
}

if (speed > 0) {
// animation
this.presets = presets;

this.PRIVATE_GRAVITY_FORCE_FACTOR_Y = (this.VARIABLE_FPS * 0.005) / 25;
this.PRIVATE_GRAVITY_FORCE_FACTOR_X = ((Math.PI / 2) - this.VARIABLE_GRAVITY_ANGLE) * (this.VARIABLE_FPS * 0.005) / 50;

// prepare gravity matrix
if (this.VARIABLE_COLLISIONS) {

// calculate max radius of a drop to establish gravity matrix resolution
var maxDropRadius = 0;
for (var i = 0; i < presets.length; i++) {
if (presets[i].base + presets[i].min > maxDropRadius) {
maxDropRadius = Math.floor(presets[i].base + presets[i].min);
}
}

if (maxDropRadius > 0) {
// initialize the gravity matrix
var mwi = Math.ceil(this.w / maxDropRadius);
var mhi = Math.ceil(this.h / maxDropRadius);
this.matrix = new CollisionMatrix(mwi, mhi, maxDropRadius);
} else {
this.VARIABLE_COLLISIONS = false;
}
}

setInterval(
(function(self) {
return function() {
var random = Math.random();
// select matching preset
var preset;
for (var i = 0; i < presets.length; i++) {
if (random < presets[i].quan) {
preset = presets[i];
break;
}
}
if (preset) {
self.putDrop(new Drop(self, Math.random() * self.w, Math.random() * self.h, preset.min, preset.base));
}
}
})(this),
speed
);
} else {
// static picture
for (var i = 0; i < presets.length; i++) {
var preset = presets[i];
for (var c = 0; c < preset.quan; ++c) {
this.putDrop(new Drop(this, Math.random() * this.w, Math.random() * this.h, preset.min, preset.base));
}
}
}
};

/**
* Adds a new raindrop to the animation.
* @param drop drop object to be added to the animation
*/
RainyDay.prototype.putDrop = function(drop) {
drop.draw();
if (this.gravity && drop.r1 > this.VARIABLE_GRAVITY_THRESHOLD) {

if (this.VARIABLE_COLLISIONS) {
// put on the gravity matrix
this.matrix.update(drop);
}

drop.animate();
}
};

/**
* Imperfectly approximates shape of a circle.
* @param iterations number of iterations applied to the size approximation algorithm
* @returns list of points approximating a circle shape
*/
RainyDay.prototype.getLinepoints = function(iterations) {
var pointList = {};
pointList.first = {
x: 0,
y: 1
};
var lastPoint = {
x: 1,
y: 1
}
var minY = 1;
var maxY = 1;
var point;
var nextPoint;
var dx, newX, newY;

pointList.first.next = lastPoint;
for (var i = 0; i < iterations; i++) {
point = pointList.first;
while (point.next != null) {
nextPoint = point.next;

dx = nextPoint.x - point.x;
newX = 0.5 * (point.x + nextPoint.

Next
Pg.: 1 2 3 4 5


Back to home | File page

Subscribe | Register | Login | N