Skip to content

Instantly share code, notes, and snippets.

@cohnt
Last active January 30, 2018 04:58
Show Gist options
  • Save cohnt/cffaf9d2485fa3e279502c2e1d1ac0b2 to your computer and use it in GitHub Desktop.
Save cohnt/cffaf9d2485fa3e279502c2e1d1ac0b2 to your computer and use it in GitHub Desktop.
HTML/Javascript Swarm Animation
<!DOCTYPE html>
<html>
<head>
<style>
canvas {
border: 1px dotted black;
}
</style>
</head>
<body>
<canvas id="canvas" width="800px" height="800px"></canvas>
<script type="text/javascript" src="./test.js"></script>
</body>
</html>
//Indentation is off because I used an online editor. Don't ask me to fix it.
///////////////////////////////////////////
/// CONSTANTS
///////////////////////////////////////////
var canvasDimensions = [null, null]; //Populated in setup()
var pointSize = 4; //In pixels
var pullTowardsCenterConst = 0.25;
var maxVelocity = 4;
var velocityMaxChange = 0.5;
var swarmMaxSize = 100;
var swarmCount = 25;
var frameTime = 40;
///////////////////////////////////////////
/// GLOBAL VARIABLES
///////////////////////////////////////////
var html = {}; //An object containing every html element on the page.
var context; //The to-be-created 2D canvas context.
var overCanvas = false; //Whether or not the mouse pointer is over the canvas.
var mouseLocation = [0, 0]; //Current mouse page location (x,y).
var oldMouseLocation = [0, 0]; //Old mouse page location (x,y).
var mouseCoords = [0, 0]; //Current mouse canvas coordinates.
var swarm = []; //List of particle objects in the swarm.
var currentAnimationInterval;
///////////////////////////////////////////
/// CLASSES
///////////////////////////////////////////
function particle() {
this.position = [0, 0];
this.velocity = [0, 0];
this.color = "#000000";
}
///////////////////////////////////////////
/// FUNCTIONS
///////////////////////////////////////////
function setup() {
html.canvas = document.getElementById("canvas"); //<canvas id="canvas">
html.canvas.addEventListener("mouseenter", function(event) { mouseEnterCanvas(event); });
html.canvas.addEventListener("mouseleave", function(event) { mouseLeaveCanvas(event); });
document.addEventListener("mousemove", function(event) { mouseMoved(event); });
//The raw output of getAttribute is "####px", so we need to shave off the px and parse to a number.
canvasDimensions[0] = Number(html.canvas.getAttribute("width").slice(0,-2));
canvasDimensions[1] = Number(html.canvas.getAttribute("height").slice(0,-2));
context = html.canvas.getContext("2d"); //Create a 2D context.
metaTransformations();
}
function clearScreen() {
context.setTransform(1, 0, 0, 1, 0, 0);
context.clearRect(0, 0, canvasDimensions[0], canvasDimensions[1]);
metaTransformations();
}
function metaTransformations() {
context.transform(1, 0, 0, 1, canvasDimensions[0]/2, canvasDimensions[1]/2); //Put the origin in the center of the canvas.
context.transform(1, 0, 0, -1, 0, 0); //Flip it so y+ is up.
}
function pullTowardsCenter(vel, pos) {
var d = [];
d[0] = pos[0] - mouseCoords[0];
d[1] = pos[1] - mouseCoords[1];
var dist = Math.sqrt((d[0]*d[0])+(d[1]*d[1]));
var ratio = dist/swarmMaxSize;
var result = vel.slice();
result[0] += (-(d[0]/Math.abs(d[0])))*ratio*pullTowardsCenterConst;
result[1] += (-(d[1]/Math.abs(d[1])))*ratio*pullTowardsCenterConst;
return result;
}
function mouseMoved(event) {
mouseLocation[0] = event.clientX;
mouseLocation[1] = event.clientY;
mouseCoords[0] = (mouseLocation[0] - html.canvas.offsetLeft) - (canvasDimensions[0] / 2);
mouseCoords[1] = (canvasDimensions[1] / 2) - (mouseLocation[1] - html.canvas.offsetTop);
if(oldMouseLocation.length == 0) {
for(var i=0; i<mouseLocation.length; ++i) {
oldMouseLocation[i] = mouseLocation[i];
}
}
var delta = [mouseLocation[0]-oldMouseLocation[0], mouseLocation[1]-oldMouseLocation[1]];
for(var i=0; i<swarm.length; ++i) {
swarm[i].position[0] += delta[0];
swarm[i].position[1] -= delta[1];
}
for(var i=0; i<mouseLocation.length; ++i) {
oldMouseLocation[i] = mouseLocation[i];
}
}
function randVelChange() {
//
return (Math.random() * velocityMaxChange * 2) - velocityMaxChange;
}
function loadSwarm() {
var list = [];
for(var i=0; i<swarmCount; ++i) {
list.push(new particle());
list[i].color = randomColor();
do {
list[i].position[0] = (Math.random() * swarmMaxSize * 2) - swarmMaxSize + mouseCoords[0];
list[i].position[1] = (Math.random() * swarmMaxSize * 2) - swarmMaxSize + mouseCoords[1];
}
while(!(list[i].position[0] >= -canvasDimensions[0]/2 && list[i].position[0] <= canvasDimensions[0]/2 && list[i].position[1] >= -canvasDimensions[1]/2 && list[i].position[1] <= canvasDimensions[1]/2));
list[i].velocity[0] = (Math.random() * maxVelocity * 2) - maxVelocity;
list[i].velocity[1] = (Math.random() * maxVelocity * 2) - maxVelocity;
}
return list;
}
function animate() {
for(var i=0; i<swarm.length; ++i) {
swarm[i].position[0] += swarm[i].velocity[0];
swarm[i].position[1] += swarm[i].velocity[1];
var distFromCenter = [];
distFromCenter[0] = swarm[i].position[0] - mouseCoords[0];
distFromCenter[1] = swarm[i].position[1] - mouseCoords[1];
if(distFromCenter[0] > swarmMaxSize) {
swarm[i].position[0] = mouseCoords[0] + swarmMaxSize;
}
else if(distFromCenter[0] < -swarmMaxSize) {
swarm[i].position[0] = mouseCoords[0] - swarmMaxSize;
}
if(distFromCenter[1] > swarmMaxSize) {
swarm[i].position[1] = mouseCoords[1] + swarmMaxSize;
}
else if(distFromCenter[1] < -swarmMaxSize) {
swarm[i].position[1] = mouseCoords[1] - swarmMaxSize;
}
swarm[i].velocity[0] += randVelChange();
swarm[i].velocity[1] += randVelChange();
swarm[i].velocity = pullTowardsCenter(swarm[i].velocity, swarm[i].position);
if(swarm[i].velocity[0] > maxVelocity) {
swarm[i].velocity[0] = maxVelocity;
}
else if(swarm[i].velocity[0] < -maxVelocity) {
swarm[i].velocity[0] = -maxVelocity;
}
if(swarm[i].velocity[1] > maxVelocity) {
swarm[i].velocity[1] = maxVelocity;
}
else if(swarm[i].velocity[1] < -maxVelocity) {
swarm[i].velocity[1] = -maxVelocity;
}
}
//console.log(delta);
clearScreen();
/*context.beginPath();
context.moveTo(mouseCoords[0], mouseCoords[1]);
context.lineTo(0, 0);
context.stroke();*/
for(var i=0; i<swarm.length; ++i) {
context.beginPath();
context.fillStyle = swarm[i].color;
context.moveTo(swarm[i].position[0], swarm[i].position[1]);
context.arc(swarm[i].position[0], swarm[i].position[1], pointSize, 0, 2*Math.PI);
context.fill();
}
}
function mouseEnterCanvas(e) {
overCanvas = true;
swarm = loadSwarm();
currentAnimationInterval = window.setInterval(animate, frameTime);
}
function mouseLeaveCanvas(e) {
overCanvas = false;
window.clearInterval(currentAnimationInterval);
swarm = [];
clearScreen();
}
function randomColor() {
var r = Math.floor(Math.random()*256).toString(16); r = ("0" + r).slice(-2);
var g = Math.floor(Math.random()*256).toString(16); g = ("0" + g).slice(-2);
var b = Math.floor(Math.random()*256).toString(16); b = ("0" + b).slice(-2);
var color = "#" + r + g + b;
return color;
}
///////////////////////////////////////////
/// EXECUTED CODE
///////////////////////////////////////////
setup();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment