/hacks/Swarm/Swarm.js
/* Copyright 2011 The Dominion of Awesome
* See COPYING for licensing information */
enyo.kind({
name: "Pixel",
constructor: function(canvas) {
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.vx = Math.random() * 20.0 - 10.0;
this.vy = Math.random() * 20.0 - 10.0;
this.lastupdate = (new Date()).getTime();
},
accel: function(x, y) {
this.vx += x;
if (this.vx > 200.0)
this.vx = 200.0;
else if (this.vx < -200.0)
this.vx = -200.0;
this.vy += y;
if (this.vy > 200.0)
this.vy = 200.0;
else if (this.vy < -200.0)
this.vy = -200.0;
},
update: function() {
var now = (new Date()).getTime();
var dt = (now - this.lastupdate) / 75.0;
this.x += this.vx * dt;
this.y += this.vy * dt;
this.lastupdate = now;
},
draw: function(ctx) {
ctx.beginPath();
ctx.moveTo(this.x,this.y);
ctx.lineTo(this.x - this.vx / 4.0, this.y - this.vy / 4.0);
ctx.stroke();
ctx.closePath();
}
});
enyo.kind({
name: "Swarm",
kind: "Hack",
align: "stretch",
pack: "stretch",
components: [
{name: "canvas", nodeTag: "canvas", style: "background-color: gray",
onmousemove: "mouseMove", onmousedown: "mouseDown"}
],
npixels: 100,
pixels: [],
rendered: function() {
this.canvas = this.$.canvas.hasNode();
this.resize();
this.mx = this.canvas.width / 2;
this.my = this.canvas.width / 2;
for (var x = 0; x < this.npixels; x++)
this.pixels.push(new Pixel(this.canvas));
//this.stopTime = (new Date()).getTime();
this.engine();
},
start: function() {
if (this.stopTime) {
var delta = (new Date()).getTime() - this.stopTime;
for (var i = 0; i < this.npixels; i++)
this.pixels[i].lastupdate += delta;
this.stopTime = null;
}
if (!this.timer)
this.timer = setInterval(this.engine.bind(this), 20);
},
stop: function() {
this.stopTime = (new Date()).getTime();
clearInterval(this.timer);
this.timer = null;
},
resize: function(w, h) {
this.canvas.width = w;
this.canvas.height = h;
//this.canvas.style.width = w + 'px';
//this.canvas.style.height = h + 'px';
this.context = this.canvas.getContext('2d');
this.context.strokeStyle = '#000000';
this.context.lineCap = 'round';
this.context.lineWidth = 1.5;
},
mouseMove: function(inSender, inEvent) {
this.mx = inEvent.clientX;
this.my = inEvent.clientY;
},
mouseDown: function(inSender, inEvent) {
this.mouseMove(inSender, inEvent);
// Apply force to each pixel outwards from the mouse
for (var i = 0; i < this.npixels; i++) {
// Get the direction
var dx = this.pixels[i].x - inEvent.clientX;
var dy = this.pixels[i].y - inEvent.clientY;
var mag = Math.sqrt(dx*dx + dy*dy);
dx /= mag;
dy /= mag;
// Apply force.
this.pixels[i].accel(dx * 40.0, dy * 40.0);
}
},
engine: function() {
// Clear the canvas
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
// Update all pixel objects
for (var i = 0; i < this.npixels; i++) {
// Get distance
var dx = this.mx - this.pixels[i].x;
var dy = this.my - this.pixels[i].y;
var d = Math.sqrt(dx*dx + dy*dy);
// Apply acceleration to pixels towards the mouse cursor
var ax = dx / 50.0;
var ay = dy / 50.0;
// Apply a drag proportional to the distance from the cursor
if (d > 100.0) {
ax += -this.pixels[i].vx * (d - 100.0) / 2000.0;
ay += -this.pixels[i].vy * (d - 100.0) / 2000.0;
}
// And a "chaotic" acceleration inversely proportional
// to the distance from the cursor
ax += (Math.random() * 160.0 - 80.0) / d;
ay += (Math.random() * 160.0 - 80.0) / d;
this.pixels[i].accel(ax,ay);
this.pixels[i].update();
this.pixels[i].draw(this.context);
}
this.context.strokeRect(this.mx - 10, this.my - 10, 20, 20);
}
});