Skip to content

Instantly share code, notes, and snippets.

@lilgreenland
Last active March 20, 2016 16:57
Show Gist options
  • Save lilgreenland/04dc84055aeef4f84beb to your computer and use it in GitHub Desktop.
Save lilgreenland/04dc84055aeef4f84beb to your computer and use it in GitHub Desktop.
wave lines
<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>
// 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);
<script src="http://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js"></script>
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