Skip to content

Instantly share code, notes, and snippets.

@veltman
Last active February 2, 2017 17:28
Show Gist options
  • Save veltman/72108247a8f8304ce0ccd7a50f49a9ca to your computer and use it in GitHub Desktop.
Save veltman/72108247a8f8304ce0ccd7a50f49a9ca to your computer and use it in GitHub Desktop.
Harmonographics
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<canvas width="960" height="500"></canvas>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
var canvas = document.querySelector("canvas"),
context = canvas.getContext("2d"),
width = canvas.width,
height = canvas.height,
step = 0.015;
context.translate(width / 2, height / 2);
context.lineWidth = 0.5;
context.strokeStyle = "#f13f94";
var scales = {
phase: d3.scaleLinear().range([0, Math.PI]),
damping: d3.scaleLinear().range([0.01, 0.05]),
frequency: d3.scaleLinear().range([2, 6])
};
var keys = d3.keys(scales);
var x = new Pendulum(),
y = new Pendulum(),
xy = new Pendulum();
x.amplitude = y.amplitude = 150;
xy.amplitude = 100;
tween();
function tween() {
d3.transition()
.duration(6000)
.tween("tween", function(){
var p = choose([x, y, xy]),
scale = keys.shift(),
invert = p[scale] === scales[scale](1);
keys.push(scale);
return function(t){
p[scale] = scales[scale](invert ? 1 - t : t);
draw();
};
})
.on("end", tween);
}
function draw(){
var t = 0;
context.clearRect(-width / 2, -height / 2, width, height);
context.beginPath();
x.stopped = y.stopped = xy.stopped = false;
while (!x.stopped || !y.stopped || !xy.stopped) {
context[t ? "lineTo" : "moveTo"](x.pos(t) + xy.x(t), y.pos(t) + xy.pos(t));
t += step;
}
context.stroke();
}
function Pendulum() {
for (var key in scales) {
this[key] = scales[key](Math.random() < 0.5 ? 0 : 1);
}
}
Pendulum.prototype.pos = function(t){
return this.amplitude * Math.sin(t * this.frequency + Math.PI * this.phase) * this.damp(t);
};
Pendulum.prototype.damp = function(t){
var factor = Math.exp(-this.damping * t);
if (factor < 0.1) {
this.stopped = true;
}
return factor;
};
Pendulum.prototype.x = function(t){
return this.amplitude * Math.cos(t * this.frequency) * this.damp(t);
};
function choose(arr){
return arr[Math.floor(Math.random() * arr.length)];
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment