// The time in milliseconds
// between calls to draw
// the animation:
var N_TIME = new Number(
100
);
// Canvas dimensions:
var N_DIM = new Number(
300
);
// One half the canvas dimension:
var N_DIM_HALF = new Number(
150
);
// Initial opacity of each particle:
var N_OPACITY = new Number(
0.01
);
// Maximum opacity of each particle:
var N_OPACITY_MAX = new Number(
0.4
);
// The circumference of one radial
// gradient equals a full circle:
var CIRCUM = new Number(
Math.PI*2
);
// The maximum random
// value for coordinates:
var N_RANDOM = new Number(
50
);
// The number of particles:
// Keep particle count down
// dfor mobile devices.
var N_PARTICLE_LENGTH = new Number(
30
);
// The increase in radial distance
// for each call to draw particles:
var N_RAD_INCREASE = new Number(
1.4
);
// The initial radius:
var N_RAD_MIN = new Number(
1.5
);
// X and Y offsets from the
// browser window, to the canvas.
var nXOffset = new Number(
0
);
var nYOffset = new Number(
0
);
var canvas,context,eDebug = null;
// Associative Array with
// x,y coordinates for location:
var aaLoc = {x:0, y:0};
// Array of particles:
var arrayParticles = [];
// Timer for animating particles:
var timer = null;
// Starting radius for three
// concentric circles of particles:
var aCirclePositions = [
8,
32,
64
];
// Starting radius for each radial gradient:
var aCircleDimensions = [
20,
32,
40
];
/***
* function loadGame()
* obtains references to the canvas,
* 2D context, and HTML element
* for debugging.
* Then obtains the bounding box of
* the canvas, and creates
* our array of particles.
***/
function loadGame(){
canvas = document.getElementById(
"cv"
);
context = canvas.getContext(
"2d"
);
// Debug output for the developer:
eDebug = document.getElementById(
"eDebug"
);
var bb = canvas.getBoundingClientRect();
// Obtain the position of the
// canvas's bounding box for
// calculating offsets to taps:
nXOffset = bb.left;
nYOffset = bb.top;
context.fillStyle = "black";
// Make an Array of radial gradients.
for(var i = 0; i < N_PARTICLE_LENGTH; i++)
{
arrayParticles.push(
new radGrad(
i
)
d);
}
}
/***
* function onMouseClick()
* offsets the mouse click or
* mobile device tap,
* by the X and Y offset of
* the canvas's location.
* assigns X and Y coordinates
* to the associative array 'aaLoc'.
* resets the particle array
* then starts the animation.
***/
function onMouseClick(e)
{
var nX = e.pageX - (nXOffset + N_DIM_HALF);
var nY = e.pageY - nYOffset - N_DIM_HALF;
aaLoc.x = nX;
aaLoc.y = nY;
resetParticles();
startParticles();
}
Radial Gradient Particle Creation
/**
* function radGrad()
* creates one particle with
* a radial gradient, location,
* opacity, and color.
*/
function radGrad(n)
{
var nAngle = n * 12;
var j = n % 3;
var nPosition = new Number(
aCirclePositions[j]
);
var nY = Math.sin(nAngle) * nPosition + N_DIM_HALF;
var nX = Math.cos(nAngle) * nPosition + N_DIM_HALF;
this.nRadius = new Number(
aCircleDimensions[j]
);
this.aaLocation = {x: nX, y: nY};
this.nOpacity = N_OPACITY;
// We preset the colors
// based on what looked good
// in Photoshop:
if(j % 2 == 0){
this.r = 0xdc;
this.g = 0x59;
this.b = 0x19;
}
else {
this.r = 0xee;
this.g = 0x3b;
this.b = 0x3e;
}
this.nRadIncrease = N_RAD_MIN;
}
/**
* function draw()
* is called repeatedly during the
* animation.
* Obtains each particle from
* the array of particles.
* Sets the location of each
* particle based on
* the last mouse click.
* Note Math.cos() and Math.sin()
* for X,Y coordinates,
* based on a circle.
*/
function draw()
{
context.fillRect(
0,
0,
N_DIM,
N_DIM
);
var nRandom = null;
for(var i = 0; i < N_PARTICLE_LENGTH; i++)
{
//Angle
var j = i * 3;
// Calculate a random
// value for X and Y coordinates
// of each particle:
nRandom = Math.random() * N_RANDOM;
// Obtain a reference to a particle:
var p = arrayParticles[i];
// Calculate the new X,Y
// coordinates
// of the particle.
var nX = new Number(
p.aaLocation.x + aaLoc.x
)
+ nRandom + Math.cos(j)
* p.nRadIncrease;
var nY = new Number(
p.aaLocation.y + aaLoc.y
)
+ nRandom + Math.sin(j)
* p.nRadIncrease;
// Try-catch block for errors.
// We left this in for those who
// might modify and test the code.
try {
var gradient;
context.beginPath();
gradient = context.createRadialGradient(
dnX,
nY,
0,
nX,
nY,
p.nRadius
);
gradient.addColorStop(
0,
"rgba("+p.r+", "+p.g+", "+p.b+", "+p.nOpacity+")"
);
gradient.addColorStop(
1,
"rgba("+p.r+", "+p.g+", "+p.b+", 0)"
);
// Fill the canvas with
// the gradient.
context.fillStyle = gradient;
// 'nX,nY' : Draw an arc, starting at X,Y.
// 'p.nRadius: Radius of the arc.
// 'CIRCUM': Enclose a circle with the arc.
context.arc(
nX,
nY,
p.nRadius,
0,
CIRCUM
);
context.fill();
// Increase opacity for each
// cycle through the particles:
p.nOpacity += 0.005;
// Increase the radius for each
// cycle through the particles:
p.nRadIncrease *= N_RAD_INCREASE;
}
catch (e){
// Display output for the developer.
eDebug.innerHTML +=" <br />"+e.toString()
eDebug.innerHTML +=",p.aaLocation.x:"+p.aaLocation.x;
eDebug.innerHTML +=",p.aaLocation.y:"+p.aaLocation.y;
eDebug.innerHTML +=",nRadius:"+p.nRadius;
stopParticles();
}
//Reset arrayParticles
if(p.nOpacity >= N_OPACITY_MAX)
{
stopParticles();
resetParticles();
}
}
}
/***
* function resetParticles()
* fills the canvas with black,
* then resets the default opacity,
* and radius increase for each particle.
***/
function resetParticles(){
// Set globalCompositeOperation to
// the default 'source-over'.
// Which will draw completely over
// anything prior.
context.globalCompositeOperation = "source-over";
context.fillStyle = "black";
context.fillRect(
0,
0,
N_DIM,
N_DIM
);
for(var i = 0; i < N_PARTICLE_LENGTH; i++){
arrayParticles[i].nOpacity = N_OPACITY;
arrayParticles[i].nRadIncrease = N_RAD_MIN;
}
// Set the globalCompositeOperation to
// 'lighter' which adds colors together
// with those displaying previously
// in the same position.
context.globalCompositeOperation = "lighter";
}
// Stop the animation.
// If the timer isn't null,
// then clear it.
// Fill the canvas with black.
function stopParticles(){
if (timer != null){
clearInterval(
timer
);
timer = null;
}
context.fillRect(
0,
0,
N_DIM,
N_DIM
);
}
// function startParticles()
// resets particles to defaults,
// then starts the timer, if
// it's not already running.
function startParticles(){
resetParticles();
if (timer == null){
timer = setInterval(
draw,
N_TIME
);
}
}