Just experimenting with some particles.
A Pen by Gary Constable on CodePen.
Just experimenting with some particles.
A Pen by Gary Constable on CodePen.
<!-- | |
just some more random particles and things.. | |
--> |
//utils and calcullations | |
var utils = { | |
lineLength : function(x, y, x0, y0){ | |
return Math.sqrt((x -= x0) * x + (y -= y0) * y); | |
} | |
} | |
//particle | |
var particle = function(opts){ | |
this.width = opts.width || 1; | |
this.height = opts.height || 1; | |
this.x_pos = opts.x_pos || 0; | |
this.y_pos = opts.y_pos || 0; | |
this.x_speed = opts.x_speed || Math.random()*10; | |
this.y_speed = opts.y_speed || Math.random()*10; | |
this.color = opts.color || 'rgb(255,255,255)'; | |
this.canvas_width = opts.canvas_width || 800; | |
this.canvas_height = opts.canvas_width || 500; | |
this.draw = opts.draw || 'dot'; | |
this.birth_state = this; | |
} | |
//the old move fuctions | |
particle.prototype.animate = function(width, height){ | |
W = width; | |
H = height; | |
p = this; | |
p.y_pos += p.y_speed; | |
if(p.y_pos < -50) p.y_pos = H+50; | |
if(p.y_pos > H+50) p.y_pos = -50; | |
p.x_pos += p.x_speed; | |
if(p.x_pos < -50) p.x_pos = W+50; | |
if(p.x_pos > W+50) p.x_pos = -50; | |
} | |
/* | |
//move up and down within the mask / bounds area | |
particle.prototype.animate = function(){ | |
p = this; | |
p.y_pos += p.y_speed; | |
} | |
*/ | |
//revese the speed (and so the direction) of the particle | |
particle.prototype.reverseSpeed = function(){ | |
//make negative | |
if(this.y_speed > 0){ | |
//(20) * (-1) | |
this.y_speed = (this.y_speed) * (-1); | |
}else{ | |
//(-20) * (-1) | |
this.y_speed = (this.y_speed) * (-1); | |
} | |
} | |
//https://raw2.github.com/garyconstable/cloaked-octo-hipster/develop/anchor.js | |
var anchor = function(opts){ | |
this.radius = opts.radius || 0; | |
this.x_pos = opts.x_pos || 0; | |
this.y_pos = opts.y_pos || 0; | |
this.draw = opts.draw || 'circle'; | |
this.lifespan = opts.draw || 2000; | |
this.created = new Date().getTime(); | |
this.canvas_width = opts.canvas_width || 800; | |
this.canvas_height = opts.canvas_width || 500; | |
this.animate = function(){} | |
this.birth = this; | |
} | |
//particle factory - were already thing expansions.... | |
var particleFactory = function(){}; | |
particleFactory.prototype.create = function ( options, type ) { | |
switch(type){ | |
case 'anchor' : return new anchor( options ); | |
default: return new particle( options ); | |
} | |
}; | |
//canvas | |
var Canvas = function(options){ | |
var self = this; | |
this.surface = options.surface || "canvas"; | |
this.surface = document.getElementById(this.surface); | |
this.width = this.surface.offsetWidth; | |
this.height = this.surface.offsetHeight; | |
this.bounds; | |
this.non_bounds; | |
this.mask = []; | |
var ctx = this.surface.getContext('2d'); | |
this.ctx = ctx; | |
} | |
//clear canvar | |
Canvas.prototype.clear = function(){ | |
ctx = this.ctx; | |
ctx.clearRect ( 0 , 0 , this.width , this.height ); | |
} | |
//pass to correct drawing function | |
Canvas.prototype.render = function(opts){ | |
switch(opts.draw){ | |
case 'dot' : this.dot(opts); break; | |
case 'circle' : this.circle(opts); break; | |
} | |
} | |
//draw point | |
Canvas.prototype.dot = function( opts ){ | |
ctx.fillStyle = opts.color || 'rgb(255,255,255)'; | |
ctx.fillRect(opts.x_pos,opts.y_pos,opts.width,opts.height); | |
} | |
//draw circle | |
Canvas.prototype.circle = function( opts ){ | |
radius = opts.radius || 10; | |
color = opts.color || 'rgb(255,0,0)'; | |
ctx.beginPath(); | |
ctx.fillStyle = color; | |
ctx.arc(opts.x_pos, opts.y_pos, radius, 0, Math.PI*2, true); | |
ctx.closePath(); | |
ctx.fill(); | |
} | |
Canvas.prototype.createBounds = function( opts ){ | |
ctx = this.ctx; | |
// this is the unicode hex of a heart | |
//str = "2764"; | |
str = "Hello...!"; | |
fontStr = "150pt Helvetica Arial, sans-serif"; | |
ctx.beginPath(); | |
ctx.font = fontStr; | |
ctx.textAlign = "center"; | |
ctx.fillStyle = "#ffffff"; | |
//ctx.fillText(String.fromCharCode(parseInt(str, 16)),this.width/2 ,this.height - 50); | |
ctx.fillText( str, this.width/2 ,this.height/2); | |
ctx.closePath(); | |
this.mask = ctx.getImageData(0,0,this.width,this.height); | |
area = []; | |
non_area =[]; | |
// save all white pixels, these will be used as the bounds for the particles | |
//http://falcon80.com/HTMLCanvas/PixelManipulation/getImageData.html | |
//https://github.com/ottis/canvas-particles/blob/master/js/particle_system.js | |
for (var i = 0; i < this.mask.data.length; i+=4) { | |
if (this.mask.data[i] == 255 && this.mask.data[i+1] == 255 && this.mask.data[i+2] == 255 && this.mask.data[i+3] == 255) { | |
area.push([this.toPosX(i,this.mask.width),this.toPosY(i,this.mask.width)]); | |
}else{ | |
//non_area.push([this.toPosX(i,mask.width),this.toPosY(i,mask.width)]); | |
} | |
} | |
this.bounds = area; | |
this.non_bounds = non_area; | |
} | |
Canvas.prototype.toPosX = function(i,w) { | |
return (i % (4 * w)) / 4; | |
} | |
Canvas.prototype.toPosY = function(i, w){ | |
return Math.floor(i / (4 * w)); | |
} | |
//get the color of the specifed pixel | |
Canvas.prototype.pixelColor = function(objectx, objecty){ | |
var imageData = this.mask | |
var inputData = imageData.data; | |
var pData = (~~objectx + (~~objecty * this.mask.width)) * 4; | |
var r = inputData[pData], | |
g = inputData[pData + 1], | |
b = inputData[pData + 2], | |
a = inputData[pData + 3]; | |
return [r,g,b,a]; | |
} | |
Canvas.prototype.addToMask = function(obj){ | |
var tc = Canvas; | |
console.log(tc); | |
var c = document.createElement('canvas'); | |
c.id = "tc"; | |
c.width = tc.width; | |
c.height = tc.height; | |
//this.canvas.bound.push(black pixel) | |
} | |
Canvas.prototype.removeFromMask = function(){ | |
//this.canvas.bound.remove(black pixel) | |
} | |
// i think it would be better to keep this seperate | |
var particleSystem = function(options){ | |
this.total_particles = 1000; | |
this.particles_drawn = 0; | |
this.particles = [ ]; | |
this.nodes = [ ]; | |
this.nodes_pointer = [ ]; | |
this.canvas = options.canvas; | |
this.createParticles(); | |
this.self = this; | |
} | |
//create the particles | |
particleSystem.prototype.createParticles = function(){ | |
pf = new particleFactory(); | |
w = this.canvas.width; | |
h = this.canvas.height; | |
x = 0; | |
y = 0; | |
/* | |
// create the particles, add base 2 number, higher = less particles | |
for(var i=0; i<this.canvas.bounds.length;i+=30){ | |
this.particles.push( pf.create({ | |
x_pos: this.canvas.bounds[i][0], | |
y_pos: this.canvas.bounds[i][1], | |
color: 'rgb(0,92,92)', | |
width: 3, | |
height: 3, | |
y_speed: Math.floor(Math.random() * 5) + 1 | |
}) ); | |
this.particles_drawn++; | |
} | |
*/ | |
// create the particles, add base 2 number, higher = less particles | |
for(var i=0; i<this.total_particles; i++){ | |
obj = pf.create({ | |
x_pos: this.canvas.width / 2, | |
y_pos: (this.canvas.height / 8) * 7, | |
color: 'rgb(0,92,92)', | |
width: 6, | |
height: 6, | |
//y_speed: -5, | |
//y_speed: Math.floor(Math.random() * 5) + 1 | |
}) | |
//random num -> | |
num = Math.floor(Math.random() * 100) + 1; | |
//x speed | |
if(num < 51){ | |
obj.x_speed = -(Math.floor(Math.random() * 5) + 1); | |
} | |
if(num > 50){ | |
obj.x_speed = (Math.floor(Math.random() * 5) + 1); | |
} | |
//y speed | |
if(num < 51){ | |
obj.y_speed = -(Math.floor(Math.random() * 5) + 1); | |
} | |
if(num > 50){ | |
obj.y_speed = (Math.floor(Math.random() * 5) + 1); | |
} | |
this.particles.push( obj ); | |
this.particles_drawn++; | |
} | |
} | |
//remove element from particle system array | |
particleSystem.prototype.remove = function(particle, index){ | |
if (typeof particle.lifespan != "undefined") { | |
if( (new Date().getTime() - particle.created) > particle.lifespan){ | |
return this.crop(index, particle.created); | |
} | |
} | |
return false; | |
} | |
//render loop clear canvas and redraw | |
particleSystem.prototype.render = function(self){ | |
var i=0; | |
this.canvas.clear(); | |
this.particles.forEach( function(particle) { | |
if( self.remove(particle, i) === false ){ | |
//change the particle in some way | |
if (typeof particle.animate !== "undefined") { | |
/* | |
//get the pixel color | |
var pc = self.canvas.pixelColor(particle.x_pos, particle.y_pos); | |
//if its a black pixel | |
if(pc[0] == 0 && pc[1] == 0 && pc[2] == 0 && pc[3] == 0){ | |
try{ | |
particle.reverseSpeed(); | |
}catch(ex){} | |
//contiune in the same direction.. | |
} | |
*/ | |
//move the particle | |
particle.animate( this.canvas.width, this.canvas.height ); | |
} | |
//render the particle | |
Canvas.render(particle); | |
}//eo remove | |
i++; | |
}); | |
} | |
//remove element from particles array | |
particleSystem.prototype.crop = function(index, ts){ | |
//remove from the drawing array | |
this.particles.splice(index, 1); | |
this.particles_drawn--; | |
//remove the node pointers to the node | |
var i = this.nodes_pointer.indexOf(ts); | |
if(i !== -1){ | |
this.nodes.splice(i, 1); | |
this.nodes_pointer.splice(i, 1); | |
//console.log(self.nodes); | |
} | |
return true; | |
} | |
//app | |
var App = function(options){ | |
//create a canvas and add to body | |
var c = document.createElement('canvas'); | |
c.id = "canvas"; | |
c.width = 800; | |
c.height = 500; | |
c.style.border = "1px solid white"; | |
document.getElementsByTagName("body")[0].style.background = 'black'; | |
document.getElementsByTagName("body")[0].appendChild(c); | |
//create canvas obj and mouselistener | |
Canvas = new Canvas({ 'surface' : 'canvas' }); | |
//create the shape | |
//Canvas.createBounds(); | |
//create the particle system obj | |
this.ps = new particleSystem({'canvas' : Canvas}) | |
self = this; | |
} | |
//render loop | |
App.prototype.run = function(){ | |
self.ps.render(self.ps); | |
requestAnimationFrame( self.run ); | |
} | |
//animation frame | |
window.requestAnimFrame = (function(){ | |
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || | |
function( callback ){ | |
window.setTimeout(callback, 1000 / 60); | |
}; | |
})(); | |
//init + animate + the go button.. | |
var app = new App().run(); |