Last active
January 30, 2018 04:58
-
-
Save cohnt/cffaf9d2485fa3e279502c2e1d1ac0b2 to your computer and use it in GitHub Desktop.
HTML/Javascript Swarm Animation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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