Extraction/conversion of a plotting visualization -- the nonlinear anecdote -- from @worrydream's Kill Math noodlings.
See also Evan Miller's response, Don't Kill Math.
Extraction/conversion of a plotting visualization -- the nonlinear anecdote -- from @worrydream's Kill Math noodlings.
See also Evan Miller's response, Don't Kill Math.
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<script src="lib.js"></script> | |
<body> | |
<canvas id="Nonlinear" width="240" height="240"></canvas> | |
<script> | |
var canvas = document.getElementById('Nonlinear'); | |
viz = new Nonlinear(canvas); | |
setInterval(viz.updateAnimation, 20); | |
</script> | |
class Nonlinear | |
constructor: (canvas) -> | |
@canvas = @element = canvas | |
@width = parseInt(canvas.width) | |
@height = parseInt(canvas.height) | |
@ctx = @canvas.getContext("2d") | |
@plotScale = 50 | |
@plotOffsetX = @width/2 | |
@plotOffsetY = @height/2 | |
@timeStep = 10e-3 | |
@hasReset = false | |
@backgroundImage = new Image() | |
@backgroundImage.src = "background.png" | |
updateAnimation: => | |
now = Date.now() | |
dt = 0.001 * (now - (@lastTimestamp || now)) | |
@lastTimestamp = now | |
return null if dt is 0 | |
@reset() if not @hasReset | |
@currentTime += dt | |
@currentTimeModStep += dt | |
while @currentTimeModStep > @timeStep | |
@currentTimeModStep -= @timeStep | |
@tick(@timeStep) | |
@drawInContext(@ctx) | |
@reset() if @currentTime > 18 | |
reset: () => | |
@hasReset = true | |
@currentTime = 0 | |
@currentTimeModStep = 0 | |
@x = -1 | |
@y = 0 | |
@ctx.drawImage(@backgroundImage, 0, 0) | |
@ctx.closePath() | |
@ctx.lineWidth = 1 | |
@ctx.strokeStyle = "#2392d9" | |
@ctx.beginPath() | |
@ctx.moveTo(@x * @plotScale + @plotOffsetX, -@y * @plotScale + @plotOffsetY) | |
tick: (dt) => | |
dx = dt * @y | |
dy = dt * (-0.5 * @y - 5 * Math.sin(@x)) | |
@x += dx | |
@y += dy | |
@ctx.lineTo(@x * @plotScale + @plotOffsetX, -@y * @plotScale + @plotOffsetY) | |
drawInContext: (ctx) => | |
ctx.stroke() | |
ctx.closePath() | |
ctx.beginPath() | |
ctx.moveTo(@x * @plotScale + @plotOffsetX, -@y * @plotScale + @plotOffsetY) | |
window.Nonlinear = Nonlinear |
// Generated by CoffeeScript 1.6.3 | |
(function() { | |
var Nonlinear, | |
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; | |
Nonlinear = (function() { | |
function Nonlinear(canvas) { | |
this.drawInContext = __bind(this.drawInContext, this); | |
this.tick = __bind(this.tick, this); | |
this.reset = __bind(this.reset, this); | |
this.updateAnimation = __bind(this.updateAnimation, this); | |
this.canvas = this.element = canvas; | |
this.width = parseInt(canvas.width); | |
this.height = parseInt(canvas.height); | |
this.ctx = this.canvas.getContext("2d"); | |
this.plotScale = 50; | |
this.plotOffsetX = this.width / 2; | |
this.plotOffsetY = this.height / 2; | |
this.timeStep = 10e-3; | |
this.hasReset = false; | |
this.backgroundImage = new Image(); | |
this.backgroundImage.src = "background.png"; | |
} | |
Nonlinear.prototype.updateAnimation = function() { | |
var dt, now; | |
now = Date.now(); | |
dt = 0.001 * (now - (this.lastTimestamp || now)); | |
this.lastTimestamp = now; | |
if (dt === 0) { | |
return null; | |
} | |
if (!this.hasReset) { | |
this.reset(); | |
} | |
this.currentTime += dt; | |
this.currentTimeModStep += dt; | |
while (this.currentTimeModStep > this.timeStep) { | |
this.currentTimeModStep -= this.timeStep; | |
this.tick(this.timeStep); | |
} | |
this.drawInContext(this.ctx); | |
if (this.currentTime > 18) { | |
return this.reset(); | |
} | |
}; | |
Nonlinear.prototype.reset = function() { | |
this.hasReset = true; | |
this.currentTime = 0; | |
this.currentTimeModStep = 0; | |
this.x = -1; | |
this.y = 0; | |
this.ctx.drawImage(this.backgroundImage, 0, 0); | |
this.ctx.closePath(); | |
this.ctx.lineWidth = 1; | |
this.ctx.strokeStyle = "#2392d9"; | |
this.ctx.beginPath(); | |
return this.ctx.moveTo(this.x * this.plotScale + this.plotOffsetX, -this.y * this.plotScale + this.plotOffsetY); | |
}; | |
Nonlinear.prototype.tick = function(dt) { | |
var dx, dy; | |
dx = dt * this.y; | |
dy = dt * (-0.5 * this.y - 5 * Math.sin(this.x)); | |
this.x += dx; | |
this.y += dy; | |
return this.ctx.lineTo(this.x * this.plotScale + this.plotOffsetX, -this.y * this.plotScale + this.plotOffsetY); | |
}; | |
Nonlinear.prototype.drawInContext = function(ctx) { | |
ctx.stroke(); | |
ctx.closePath(); | |
ctx.beginPath(); | |
return ctx.moveTo(this.x * this.plotScale + this.plotOffsetX, -this.y * this.plotScale + this.plotOffsetY); | |
}; | |
return Nonlinear; | |
})(); | |
window.Nonlinear = Nonlinear; | |
}).call(this); |