// -------------------------- Field -------------------------- //
function Field( elem, particleCount, maxDisplacement ) {
this.elem = elem;
particleCount = particleCount || 100;
this.width = this.elem.offsetWidth;
this.height = this.elem.offsetHeight;
this.spacing = Math.floor( Math.sqrt( document.body.offsetWidth * document.body.offsetHeight / particleCount ) );
this.maxDisplacement = maxDisplacement || this.spacing;
this.cols = Math.floor( this.width / this.spacing );
this.rows = Math.floor( this.height / this.spacing );
// make some particles
this.particles = [];
var particle, x, y;
var frag = document.createDocumentFragment();
for ( var row=0; row < this.rows; row++ ) {
for ( var col=0; col < this.cols; col++ ) {
x = ( col + 0.5 ) * this.spacing;
y = ( row + 0.5 ) * this.spacing;
particle = new Particle( x, y, this.spacing, this.maxDisplacement );
this.particles.push( particle );
frag.appendChild( particle.elem );
}
}
this.elem.appendChild( frag );
this.elem.addEventListener( 'mousemove', this, false );
}
// allows for mousemoveHandler to be triggered after mousemove event
Field.prototype.handleEvent = function( event ) {
var handler = event.type + 'Handler';
if ( this[ handler ] ) {
this[ handler ]( event );
}
};
Field.prototype.mousemoveHandler = function( event ) {
var point = {
x: event.pageX,
y: event.pageY
};
this.eachParticleDo( 'reachFor', point );
};
Field.prototype.eachParticleDo = function( methodName ) {
var particle;
// pass in any other arguments after methodName
var args = Array.prototype.slice.call( arguments, 1 );
for ( var i=0, len = this.particles.length; i < len; i++ ) {
particle = this.particles[i];
// first argument, particle, is what this will be inside function
// second argument is the arguments for that function
particle[ methodName ].apply( particle, args );
}
};
// -------------------------- Particle -------------------------- //
function Particle( x, y, spacing, maxDisplacement ) {
this.spacing = spacing;
this.maxDisplacement = maxDisplacement;
this.elem = document.createElement('div');
this.size = this.spacing * 0.5;
this.elem.style.width = this.size + 'px';
this.elem.style.height = this.size + 'px';
this.elem.style.borderRadius = this.size * 0.5 + 'px';
this.elem.style.position = 'absolute';
this.origin = {
x: x,
y: y
};
this.position( x, y );
this.setColor('black');
}
Particle.prototype.setColor = function( color ) {
this.elem.style.backgroundColor = color;
};
Particle.prototype.position = function( x, y ) {
this.x = x;
this.y = y;
this.elem.style.left = ( this.x - this.size * 0.5 ) + 'px';
this.elem.style.top = ( this.y - this.size * 0.5 ) + 'px';
};
Particle.prototype.reachFor = function( point ) {
var dx = point.x - this.origin.x;
var dy = point.y - this.origin.y;
var distance = Math.sqrt( dx * dx + dy * dy );
distance = Math.min( distance, this.maxDisplacement );
var angle = Math.atan2( dy, dx );
var x = this.origin.x + Math.cos( angle ) * distance;
var y = this.origin.y + Math.sin( angle ) * distance;
this.position( x, y );
};
// -------------------------- init -------------------------- //
function init() {
var fieldArea = document.getElementById('field-area');
window.myField = new Field( fieldArea, 100 );
}
window.addEventListener( 'load', init, false );