Created
September 11, 2017 03:03
-
-
Save lilgreenland/363fda1a95ce58d7756dcbbe5068c554 to your computer and use it in GitHub Desktop.
field lines
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
<svg> | |
<g id="grid" stroke="lightgrey" transform="scale(0.3)"> | |
<line x1="0" y1="1250" x2="9000" y2="1250" style="stroke-dasharray:1,48,1,0;stroke-width:9000;"/> | |
<line x1="2000" y1="0" x2="2000" y2="9000" style="stroke-dasharray:1,48,1,0;stroke-width:9000;"/> | |
</g> | |
</svg> | |
<canvas id="myCanvas"> </canvas> |
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
// todo | |
window.onresize = function(event) { | |
ctx.canvas.width = window.innerWidth; | |
ctx.canvas.height = window.innerHeight; | |
ctx.shadowBlur = 30; | |
ctx.shadowOffsetY = 30; | |
ctx.shadowOffsetX = 10; | |
if (physics.lines) { | |
ctx.shadowColor = physics.color; | |
} else { | |
ctx.shadowColor = "transparent"; | |
} | |
ctx.lineWidth = physics.drawSize; | |
}; | |
var physics = { | |
cycle: 0, //keeps track of cycle | |
pause: false, // pauses the simulation | |
speed: 6, //speed of waves and max speed of source | |
totalNodes: Math.round(window.innerWidth / 4), //spawns stars at start | |
control: 'mouse:speed cap',//"sine wave", //input mode (keys 1,2,3,4 switch) | |
period: 10 * Math.PI / 30, | |
amplitude: 30, | |
info: false, //toggles info display for sinewave: press "i" | |
lines: true, //toggles lines or squares: press "l" | |
multiwave: true, | |
drawSize: 3, //changes length of squares for each rectangle node | |
color: "#000000", | |
alpha: 1, | |
time: false, | |
xOffset: 0.5 * window.innerWidth, | |
yOffset: 0.5 * window.innerHeight, | |
}; | |
/* var pausefunction = function() { | |
this.pauseToggle = function() { | |
if (physics.pause) { | |
physics.pause = false; | |
} else { | |
physics.pause = true; | |
} | |
}; | |
}; */ | |
// draw the graphical user interface form the dat.GUI library | |
var gui = new dat.GUI(); | |
gui.close(); | |
gui.add(physics, 'pause'); | |
gui.add(physics, 'speed', 0, 50); | |
var controlController = gui.add(physics, 'control', ['mouse:raw', 'mouse:speed cap', 'sine wave', 'circle', 'super position 1', 'super position 2', 'super position 3', 'longitudinal wave']); | |
controlController.onChange(function(value) { | |
if (value === 'mouse:raw' || value === 'mouse:speed cap') { | |
sineFolder.close(); | |
} else { | |
sineFolder.open(); | |
} | |
}); | |
var sineFolder = gui.addFolder('sine controls'); | |
sineFolder.add(physics, 'info'); | |
sineFolder.add(physics, 'amplitude', 0, window.innerHeight / 2); | |
sineFolder.add(physics, 'period', 0, 5); | |
sineFolder.open(); | |
var looksFolder = gui.addFolder('looks'); | |
looksFolder.add(physics, 'time'); | |
var linesController = looksFolder.add(physics, 'lines'); | |
linesController.onChange(function(value) { | |
if (physics.lines) ctx.shadowColor = physics.color; | |
else ctx.shadowColor = "transparent"; | |
}); | |
//looksFolder.add(physics, 'multiwave'); | |
var drawSizeController = looksFolder.add(physics, 'drawSize', 1, 50); | |
drawSizeController.onChange(function(value) { | |
ctx.lineWidth = physics.drawSize; | |
}); | |
var alphaController = looksFolder.add(physics, 'alpha', 0, 1); | |
alphaController.onChange(function(value) { | |
ctx.globalAlpha = value; | |
}); | |
var colorController = looksFolder.addColor(physics, 'color'); | |
colorController.onChange(function(value) { | |
ctx.fillStyle = value; | |
ctx.strokeStyle = value; | |
if (physics.lines) ctx.shadowColor = value; | |
else ctx.shadowColor = "transparent"; | |
}); | |
var drawPos = { | |
x: physics.xOffset, | |
y: physics.yOffset, | |
}; | |
var fontSize = 20; | |
var canvas = document.getElementById("myCanvas"); | |
var ctx = canvas.getContext("2d"); | |
ctx.canvas.width = window.innerWidth; | |
ctx.canvas.height = window.innerHeight; | |
//ctx.globalCompositeOperation = 'source-over'; | |
ctx.globalAlpha = 1; | |
ctx.textAlign = "center"; | |
ctx.fillStyle = "#000000"; | |
ctx.strokeStyle = "#000000"; | |
ctx.lineWidth = physics.drawSize; | |
ctx.lineJoin = 'round'; //miter, round | |
ctx.lineCap = "round"; | |
ctx.shadowBlur = 30; | |
ctx.shadowOffsetY = 30; | |
ctx.shadowOffsetX = 10; | |
if (physics.lines) ctx.shadowColor = "black"; | |
else ctx.shadowColor = "transparent"; | |
var mousePos = { | |
x: window.innerWidth * 0.5, | |
y: window.innerHeight * 0.5 | |
}; | |
//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 | |
canvas.addEventListener('mousemove', function(evt) { | |
mousePos = getMousePos(canvas, evt); | |
}, false); | |
canvas.addEventListener("mousedown", function() { | |
physics.xOffset = mousePos.x | |
physics.yOffset = mousePos.y | |
}); | |
function controlMode() { | |
switch (physics.control) { | |
case "mouse:speed cap": | |
smoothMouseWave(); | |
break; | |
case "mouse:raw": | |
mouseWave(); | |
break; | |
case "sine wave": | |
sineWave(0, physics.amplitude, physics.period); //sine wave (X amp, Y amp, period) | |
break; | |
case "circle": | |
sineWave(physics.amplitude, physics.amplitude, physics.period); //circle | |
break; | |
case "super position 1": | |
sineWaves(0, physics.amplitude, physics.period, 0, physics.amplitude, physics.period * 0.85); // 2 sine waves slightly out of sync | |
break; | |
case "super position 2": | |
sineWaves(0, physics.amplitude, physics.period, 0, physics.amplitude / 10, physics.period / 10); // 2 sine waves: one big and one small | |
break; | |
case "super position 3": | |
sineWaves(physics.amplitude, physics.amplitude, physics.period, 0, physics.amplitude, physics.period * 0.85); // | |
break; | |
case "longitudinal wave": | |
sineWave(physics.amplitude, 0, physics.period); // wave that moves like sound | |
break; | |
default: | |
mouseWave(); | |
} | |
} | |
function smoothMouseWave() { | |
//gravitate towards mouse | |
var dir = Math.atan2(drawPos.y - mousePos.y, drawPos.x - mousePos.x) | |
var dist = Math.sqrt((drawPos.x - mousePos.x) * (drawPos.x - mousePos.x) + (drawPos.y - mousePos.y) * (drawPos.y - mousePos.y)); | |
if (dist > 5) { | |
var speed = 0; | |
if ((dist) < 50) { | |
speed = dist / 50 * physics.speed; | |
} else { | |
speed = physics.speed * 0.99; | |
} | |
drawPos.x -= speed * Math.cos(dir); | |
drawPos.y -= speed * Math.sin(dir); | |
} | |
} | |
function mouseWave() { | |
drawPos.x = mousePos.x; | |
drawPos.y = mousePos.y; | |
} | |
function sineWave(ampX, ampY, T) { | |
waveProperties(T, ampY); | |
T = T * 30 / Math.PI | |
drawPos.x = ampX * Math.cos(physics.cycle / T) + physics.xOffset; | |
drawPos.y = ampY * Math.sin(physics.cycle / T) + physics.yOffset; | |
} | |
function sineWaves(ampX, ampY, T, ampX2, ampY2, T2) { | |
waveProperties(T, ampY); | |
T = T * 30 / Math.PI | |
T2 = T2 * 30 / Math.PI | |
drawPos.x = ampX * Math.cos(physics.cycle / T) + physics.xOffset; | |
drawPos.x += ampX2 * Math.cos(physics.cycle / T2); | |
drawPos.y = ampY * Math.sin(physics.cycle / T) + physics.yOffset; | |
drawPos.y += ampY2 * Math.sin(physics.cycle / T2); | |
} | |
function waveProperties(T, ampY) { | |
if (physics.info) { | |
ctx.font = fontSize + "px Arial"; | |
ctx.textAlign = "start"; | |
ctx.fillText("y = " + ampY.toFixed(5).substring(0, 5) + " sin(" + (1 / T).toFixed(5).substring(0, 5) + " x)", 5, fontSize + 10); | |
ctx.fillText("f = " + (1 / T).toFixed(5).substring(0, 5) + "Hz", 5, fontSize + 40); | |
ctx.fillText("T = " + (T).toFixed(5).substring(0, 5) + "s", 5, fontSize + 70); | |
ctx.fillText("λ = " + (physics.speed * 60 * T).toFixed(5).substring(0, 5) + "px", 5, fontSize + 100); | |
ctx.fillText("v = " + (physics.speed * 60).toFixed(5).substring(0, 5) + "px/s", 5, fontSize + 130); | |
ctx.fillText("A = " + ampY.toFixed(5).substring(0, 5) + " px", 5, fontSize + 160); | |
// center line | |
ctx.beginPath(); | |
ctx.moveTo(0, physics.yOffset); | |
ctx.lineTo(window.innerWidth, physics.yOffset); | |
ctx.stroke(); | |
} | |
} | |
function time() { | |
if (physics.time) { | |
var d = new Date(); | |
var hour = d.getHours(); | |
var min = d.getMinutes(); | |
var sec = d.getSeconds(); | |
var ms = d.getMilliseconds().toFixed(2).substring(0, 2); | |
ctx.textAlign = "end"; | |
ctx.font = fontSize + "px Monospace"; | |
ctx.fillText(hour + 'h:' + min + 'm:' + sec + "." + ms + 's', window.innerWidth, window.innerHeight - 13); | |
} | |
} | |
/* window.onresize = function(event) { | |
ctx.canvas.width = window.innerWidth; | |
ctx.canvas.height = window.innerHeight; | |
container.height = window.innerHeight; | |
container.width = window.innerWidth; | |
}; */ | |
var node1 = [], | |
node2 = [], | |
node3 = [], | |
node4 = [], | |
node5 = [], | |
node6 = [], | |
node7 = [], | |
node8 = [], | |
node9 = [], | |
node10 = [], | |
node11 = [], | |
node12 = [], | |
node13 = [], | |
node14 = [], | |
node15 = [], | |
node16 = []; | |
//adds a new star objects to array stars | |
function pushNode(i, dirX, dirY, node) { | |
node.push({ | |
x: drawPos.x, | |
y: drawPos.y, | |
Vx: dirX, | |
Vy: dirY, | |
returnCycle: i, | |
}); | |
} | |
//spawns stars at the start in 8 different directions | |
for (var i = 0; i < physics.totalNodes; i++) { | |
pushNode(i, 1, 0, node1); | |
pushNode(i, -1, 0, node2); | |
pushNode(i, 0, 1, node3); | |
pushNode(i, 0, -1, node4); | |
pushNode(i, 0.7, 0.7, node5); | |
pushNode(i, -0.7, -0.7, node6); | |
pushNode(i, 0.7, -0.7, node7); | |
pushNode(i, -0.7, 0.7, node8); | |
pushNode(i, 0.92, 0.38, node9); | |
pushNode(i, -0.92, 0.38, node10); | |
pushNode(i, 0.92, -0.38, node11); | |
pushNode(i, -0.92, -0.38, node12); | |
pushNode(i, 0.38, 0.92, node13); | |
pushNode(i, -0.38, 0.92, node14); | |
pushNode(i, 0.38, -0.92, node15); | |
pushNode(i, -0.38, -0.92, node16); | |
} | |
function fieldLineLoop(node) { //lines | |
ctx.beginPath(); | |
i = node.length; | |
ctx.moveTo(node[i - 1].x, node[i - 1].y); | |
while (i--) { | |
ctx.lineTo(node[i].x, node[i].y); | |
//move node | |
node[i].x += node[i].Vx * physics.speed; | |
node[i].y += node[i].Vy * physics.speed; | |
//check for return | |
if (node[i].returnCycle < physics.cycle) { | |
node.splice(i, 1); | |
pushNode(physics.cycle + physics.totalNodes - 1, node[i].Vx, node[i].Vy, node); | |
} | |
} | |
ctx.stroke(); | |
} | |
function fieldDotLoop(node) { //turn shadows off for this | |
i = node.length; | |
while (i--) { | |
/*ctx.beginPath(); //cirlces are slower then rectangles | |
ctx.arc(node[i].x, node[i].y, physics.drawSize, 0, 2 * Math.PI); | |
ctx.fill(); */ | |
//ctx.fillStyle='#' + Math.floor(Math.random() * 16777216).toString(16); | |
ctx.fillRect(node[i].x, node[i].y, physics.drawSize, physics.drawSize); | |
//move node | |
node[i].x += node[i].Vx * physics.speed; | |
node[i].y += node[i].Vy * physics.speed; | |
//check for return | |
if (node[i].returnCycle < physics.cycle) { | |
node.splice(i, 1); | |
pushNode(physics.cycle + physics.totalNodes - 1, node[i].Vx, node[i].Vy, node); | |
} | |
} | |
} | |
function draw() { | |
if (physics.pause === false) { | |
physics.cycle++; | |
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight); | |
time(); | |
controlMode(); | |
//draw each line | |
if (physics.lines) { | |
fieldLineLoop(node1); | |
if (physics.multiwave) { | |
fieldLineLoop(node2); | |
fieldLineLoop(node3); | |
fieldLineLoop(node4); | |
fieldLineLoop(node5); | |
fieldLineLoop(node6); | |
fieldLineLoop(node7); | |
fieldLineLoop(node8); | |
fieldLineLoop(node9); | |
fieldLineLoop(node10); | |
fieldLineLoop(node11); | |
fieldLineLoop(node12); | |
fieldLineLoop(node13); | |
fieldLineLoop(node14); | |
fieldLineLoop(node15); | |
fieldLineLoop(node16); | |
} | |
} else { | |
fieldDotLoop(node1); | |
if (physics.multiwave) { | |
fieldDotLoop(node2); | |
fieldDotLoop(node3); | |
fieldDotLoop(node4); | |
fieldDotLoop(node5); | |
fieldDotLoop(node6); | |
fieldDotLoop(node7); | |
fieldDotLoop(node8); | |
fieldDotLoop(node9); | |
fieldDotLoop(node10); | |
fieldDotLoop(node11); | |
fieldDotLoop(node12); | |
fieldDotLoop(node13); | |
fieldDotLoop(node14); | |
fieldDotLoop(node15); | |
fieldDotLoop(node16); | |
} | |
} | |
} | |
requestAnimationFrame(draw); | |
} | |
requestAnimationFrame(draw); |
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
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js"></script> |
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
body { | |
font: 15px arial, sans-serif; | |
background-color: white; | |
overflow:hidden; | |
cursor: crosshair; | |
} | |
h2 { | |
font: 25px arial, sans-serif; | |
} | |
canvas { | |
position: absolute; | |
left: 0; | |
top: 0; | |
z-index: -1; | |
} | |
svg{ | |
position: absolute; | |
left: 0; | |
top: 0; | |
z-index: -2; | |
width: 100%; | |
height: 100%; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment