|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<style> |
|
body { |
|
background-color: black; |
|
color: rgb(200, 200, 200); |
|
margin: 0px; |
|
} |
|
canvas { |
|
margin-top: 10px; |
|
} |
|
table { |
|
margin-left: 10px; |
|
} |
|
</style> |
|
<script src="//d3js.org/d3.v4.min.js"></script> |
|
</head> |
|
<body> |
|
<canvas></canvas> |
|
<table> |
|
<tr> |
|
<td>freq. #1: <text id="f1"></text></td> |
|
<td>freq. #2: <text id="f2"></text></td> |
|
<td>freq. #3: <text id="f3"></text></td> |
|
<td>Compound wavelength</td> |
|
</tr> |
|
<tr> |
|
<td><input type="range" min="1" max="100" value="12" oninput="draw()"></td> |
|
<td><input type="range" min="1" max="100" value="50" oninput="draw()"></td> |
|
<td><input type="range" min="1" max="100" value="2" oninput="draw()"></td> |
|
<th id="LCM"></th> |
|
</tr> |
|
</table> |
|
</body> |
|
<script> |
|
const width = innerWidth, |
|
height = innerHeight - 60; |
|
|
|
const canvas = d3.select("canvas") |
|
.attr("width", width) |
|
.attr("height", height); |
|
|
|
const canvasCtx = canvas.node().getContext("2d"); |
|
|
|
const x = d3.scaleLinear().range([0, width]); |
|
|
|
const wave = d3.line() |
|
.curve(d3.curveMonotoneX) |
|
.x(function(d, i) {return x(i)}) |
|
.y(function(d) {return d * height}) |
|
.context(canvasCtx); |
|
|
|
draw(); |
|
|
|
function draw() { |
|
canvasCtx.clearRect(0, 0, width, height); |
|
canvasCtx.fillStyle = 'rgb(0, 0, 0)'; |
|
canvasCtx.fillRect(0, 0, width, height); |
|
|
|
const fVals = d3.selectAll("input").nodes().map(function(d) {return +d.value}); |
|
const commonLength = LCM(LCM(fVals[0], fVals[1]), fVals[2]) * 2 + 1; |
|
|
|
x.domain([0, commonLength]); |
|
|
|
const wavesArray = fVals.map(function(d) { return []}) |
|
const compoundWave = []; |
|
|
|
for (let i=0; i<commonLength; i++) { |
|
let combinedVal = 0; |
|
for (let n=0; n<wavesArray.length; n++) { |
|
const d = fVals[n] |
|
const thisVal = d3.easeSinInOut((i % (d*2) - d) / d); |
|
combinedVal += thisVal |
|
wavesArray[n].push(thisVal) |
|
} |
|
compoundWave.push(combinedVal/3) |
|
} |
|
|
|
wavesArray.map(function(d) {drawWave(d, 'rgb(200, 200, 200)', d.length > 1000 ? .1 : .4)}) |
|
|
|
drawWave(compoundWave, 'rgb(255, 0, 0)') |
|
|
|
d3.select("#f1").html(fVals[0]) |
|
d3.select("#f2").html(fVals[1]) |
|
d3.select("#f3").html(fVals[2]) |
|
d3.select("#LCM").html(commonLength) |
|
} |
|
|
|
function drawWave(array, color, lineWidth = 1) { |
|
canvasCtx.beginPath(); |
|
canvasCtx.lineWidth = lineWidth; |
|
canvasCtx.strokeStyle = color; |
|
canvasCtx.moveTo(0, 0); |
|
wave(array) |
|
canvasCtx.stroke(); |
|
} |
|
|
|
function LCM(a, b) { |
|
return (a/gcd(a, b)*b) |
|
} |
|
|
|
function gcd(a,b) { |
|
while (true) { |
|
if (b == 0) return a; |
|
a %= b; |
|
if (a == 0) return b; |
|
b %= a; |
|
} |
|
} |
|
</script> |
|
</html> |