Skip to content

Instantly share code, notes, and snippets.

@lilgreenland
Last active March 9, 2016 02:31
Show Gist options
  • Save lilgreenland/7898fd740c4730d10097 to your computer and use it in GitHub Desktop.
Save lilgreenland/7898fd740c4730d10097 to your computer and use it in GitHub Desktop.
magnetic field particle motion
<canvas id="myCanvas" style="position : fixed;"> </canvas>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
var physics = {
B: -0.2, // Magnetic field directed into or outof screen
friction: 1, //slows particles 1 is off 0.99 is a bit
totalStars: 0, //spawns stars at start
pause: false, // pauses the simulation
}
var addStar = 0;
var container = {
x: 0,
y: 0,
width: canvas.width,
height: canvas.height
};
var stars = [];
var mousePos = {
x: container.width * 0.5,
y: container.height * 0.5
};
window.onresize = function(event) {
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
container.height = window.innerHeight;
container.width = window.innerWidth;
};
//adds a new star objects to array stars
function pushStar() {
stars.push({
x: mousePos.x + 20 * (Math.random() - 0.5),
y: mousePos.y + 20 * (Math.random() - 0.5),
Vx: (Math.random() - 0.5) * 10,
Vy: (Math.random() - 0.5) * 10,
r: 20 * Math.random() + 3, // mass, and radius of circle
color: '#' + Math.floor(Math.random() * 16777216).toString(16), //random color
charge: (Math.round(Math.random()) * 2 - 1) * Math.ceil(Math.random() * 3), //1,2,3 or -1,-2,-3
});
}
//spawns stars at the start
for (var i = 0; i < physics.totalStars; i++) {
pushStar();
}
//looks for key presses and logs them
var keys = [];
document.body.addEventListener("keydown", function(e) {
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function(e) {
keys[e.keyCode] = false;
});
function keyChecks() {
if (keys[38]) {
physics.B += 0.005;
} else if (keys[40]) {
physics.B -= 0.005;
}
if (keys[32]) {
togglePause();
}
}
function togglePause() {
if (physics.pause) {
physics.pause = false;
} else {
physics.pause = true;
}
}
document.addEventListener("mousedown", function() {
/*//push away if mouse down
for (var i = 0; i < stars.length; i++) {
stars[i].Vx += 3 * Math.cos(Math.atan2(stars[i].y - mousePos.y, stars[i].x - mousePos.x));
stars[i].Vy += 3 * Math.sin(Math.atan2(stars[i].y - mousePos.y, stars[i].x - mousePos.x));
}*/
//if mouse in upper right corner delete all stars
if (mousePos.x > container.width - 20 && mousePos.y < 20) {
togglePause()
} else {
addStar = 1;
}
//if mouse in upper right corner delete all stars
if (mousePos.x < 20 && mousePos.y < 20) {
addStar = -1;
}
});
//gets mouse position
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
// waits for mouse move and then updates position
document.addEventListener('mousemove', function(evt) {
mousePos = getMousePos(canvas, evt);
}, false);
function attractedToMouse(i) {
// attraction to the mouse
stars[i].Vx += -0.03 * Math.cos(Math.atan2(stars[i].y - mousePos.y, stars[i].x - mousePos.x));
stars[i].Vy += -0.03 * Math.sin(Math.atan2(stars[i].y - mousePos.y, stars[i].x - mousePos.x));
}
var pause = false;
var fontSize = 20;
ctx.font = "20px Georgia";
ctx.textAlign = "center";
function printVariables(i) {
ctx.fillStyle = "#000000";
ctx.font = "15px Arial";
if (i === 0) {
ctx.fillText("B = " + physics.B.toFixed(5).substring(0, 5), container.width * 0.5, fontSize);
}
ctx.fillText("x = " + stars[i].x.toFixed(5).substring(0, 5) + "px", stars[i].x, stars[i].y + stars[i].r + fontSize);
ctx.fillText("y = " + stars[i].y.toFixed(5).substring(0, 5) + "px", stars[i].x, stars[i].y + stars[i].r + fontSize * 2);
//ctx.fillText("Vx = "+Math.round(stars[i].Vx),stars[i].x,stars[i].y+stars[i].r+fontSize*3);
//ctx.fillText("Vy = "+Math.round(stars[i].Vy),stars[i].x,stars[i].y+stars[i].r+fontSize*4);
var speed = Math.sqrt(stars[i].Vx * stars[i].Vx + stars[i].Vy * stars[i].Vy);
ctx.fillText("speed = " + speed.toFixed(5).substring(0, 5), stars[i].x, stars[i].y + stars[i].r + fontSize * 3);
ctx.fillText("q = " + Math.round(stars[i].charge), stars[i].x, stars[i].y + stars[i].r + fontSize * 4);
ctx.fillText("KE = " + (0.5 * stars[i].r * speed * speed).toFixed(5).substring(0, 5), stars[i].x, stars[i].y + stars[i].r + fontSize * 5);
ctx.fillText("p = " + (stars[i].r * speed).toFixed(5).substring(0, 5), stars[i].x, stars[i].y + stars[i].r + fontSize * 6);
}
function wallBounce(i) {
if (stars[i].x > container.width - stars[i].r) {
stars[i].Vx *= -physics.friction;
stars[i].x = container.width - stars[i].r;
} else if (stars[i].x < stars[i].r) {
stars[i].Vx *= -physics.friction;
stars[i].x = stars[i].r;
}
if (stars[i].y > container.height - stars[i].r) {
stars[i].Vy *= -physics.friction;
stars[i].y = container.height - stars[i].r;
} else if (stars[i].y < stars[i].r) {
stars[i].Vy *= -physics.friction;
stars[i].y = stars[i].r;
}
}
function magneticForce(i) {
var dir = Math.atan2(stars[i].Vy, stars[i].Vx);
var speed = Math.sqrt(stars[i].Vx * stars[i].Vx + stars[i].Vy * stars[i].Vy);
stars[i].Vx = speed * Math.cos(dir - physics.B * stars[i].charge / stars[i].r);
stars[i].Vy = speed * Math.sin(dir - physics.B * stars[i].charge / stars[i].r);
}
function drawMagField() {
ctx.fillStyle = "grey";
var text
if (physics.B < 0) {
ctx.font = "10px Arial";
text = "X"
} else if (physics.B > 0) {
ctx.font = "30px Arial";
text = "."
} else {
text = " "
}
for (var i = 0; i < container.width; i += 10 / Math.abs(physics.B)) {
for (var j = 0; j < container.height; j += 10 / Math.abs(physics.B)) {
ctx.fillText(text, i, j);
}
}
}
function moveStar(i) {
//change position, velocity, size of object elements for each location in array
stars[i].x += stars[i].Vx;
stars[i].y += stars[i].Vy;
//friction slows velocity
stars[i].Vx *= physics.friction;
stars[i].Vy *= physics.friction;
}
//recursive draw function
function draw() {
keyChecks();
ctx.globalCompositeOperation = 'source-over';
ctx.clearRect(container.x, container.y, container.width, container.height);
// show where you can clear particles
ctx.fillStyle = "#00FFFF";
ctx.fillRect(container.width - 20, 0, 20, 20);
//show where you can draw info
ctx.fillStyle = "#FF0000";
ctx.fillRect(0, 0, 20, 20);
//trails
//ctx.fillStyle = "rgba(0, 0, 0, 0.15)"; //background color
//ctx.fillRect(container.x, container.y, container.width, container.height);
//ctx.globalCompositeOperation = 'lighter';
drawMagField()
for (var i = 0; i < stars.length; i++) {
//draw a circle
ctx.beginPath();
ctx.arc(stars[i].x, stars[i].y, stars[i].r, 0, 2 * Math.PI, true);
ctx.fillStyle = stars[i].color;
ctx.fill();
//if mouse close to star show info
if ((stars[i].y - mousePos.y)*(stars[i].y - mousePos.y)+ (stars[i].x - mousePos.x)*(stars[i].x - mousePos.x) < stars[i].r*stars[i].r+2000){
printVariables(i)
}
//if pause show info else move and spply forces to star
if (physics.pause) {
printVariables(i)
} else {
moveStar(i)
magneticForce(i)
//attractedToMouse(i);
//wallBounce(i)
}
}
//add a star or remove
if (addStar == 1) {
pushStar();
addStar = 0;
} else if (addStar == -1) {
stars = [];
}
requestAnimationFrame(draw);
}
requestAnimationFrame(draw);
body {
font: 15px arial, sans-serif;
background-color: white;
}
canvas {
position: absolute;
left: 0;
top: 0;
z-index: -1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment