A Pen by lilgreenland on CodePen.
Last active
March 20, 2016 16:57
-
-
Save lilgreenland/04dc84055aeef4f84beb to your computer and use it in GitHub Desktop.
wave 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 | |
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: "sine wave", //input mode (keys 1,2,3,4 switch) | |
period: 10, | |
amplitude: 30, | |
info: false, //toggles info display for sinewave: press "i" | |
lines: false, //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.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', 'longitudinal wave']); | |
controlController.onChange(function(value) { | |
if (value === 'sine wave' || value === 'circle') { | |
sineFolder.open(); | |
} else { | |
sineFolder.close(); | |
} | |
}); | |
var sineFolder = gui.addFolder('sine controls'); | |
sineFolder.add(physics, 'info'); | |
sineFolder.add(physics, 'amplitude', 0, window.innerHeight / 2); | |
sineFolder.add(physics, 'period', 0, 15); | |
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 = "black"; | |
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; | |
}); | |
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 "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) < 200) { | |
speed = dist / 200 * 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) { | |
drawPos.x = ampX * Math.cos(physics.cycle / T) + physics.xOffset; | |
drawPos.y = ampY * Math.sin(physics.cycle / T) + physics.yOffset; | |
waveProperties(T, ampY); | |
} | |
function sineWaves(ampX, ampY, T, ampX2, ampY2, T2) { | |
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("A = " + ampY.toFixed(5).substring(0, 5) + " px", 5, canvas.height - 10); | |
ctx.fillText("f = " + (30 / T / Math.PI).toFixed(5).substring(0, 5) + "Hz", 5, canvas.height - 40); | |
ctx.fillText("T = " + (T / 30 * Math.PI).toFixed(5).substring(0, 5) + "s", 5, canvas.height - 70); | |
ctx.fillText("λ = " + (physics.speed * T * 2 * Math.PI).toFixed(5).substring(0, 5) + "px", 5, canvas.height - 100); | |
ctx.fillText("v = " + (physics.speed * 60).toFixed(5).substring(0, 5) + "px/s", 5, canvas.height - 130); | |
} | |
} | |
/* 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.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 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); | |
} | |
} | |
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="http://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%; | |
} |
A Pen by lilgreenland on CodePen.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment