var c = document.getElementById('c');
var context = c.getContext("2d");
var centerx = context.canvas.width / 2;
var centery = context.canvas.height / 2;
// shim layer with setTimeout fallback
window.requestAnimFrame = (function() {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
throw new Error("WTF? why no annimation?");
};
})();
// usage:
// instead of setInterval(render, 16) ....
running = false;
$('#toggle').click(function() {
i = 500;
running = !running;
$('#toggle').val(running);
animloop();
});
i = 500;
function animloop() {
if (!running) return;
requestAnimFrame(animloop);
advance();
if (i-- < 0) running = false;
};
// place the rAF *before* the render() to assure as close to
// 60fps with the setTimeout fallback.
function advance() {
Z = incrementVal("Z", 0.01);
b = incrementVal("b", 0.01);
e = incrementVal("e", 0.01);
renderSpiral({
a: 1,
//1,
b: b,
e: e,
//1.5,
Z: Z,
tail: 10
});
}
function incrementVal(valName, step) {
percentVal = parseFloat($('#percent' + valName).val());
diff = parseFloat($('#max' + valName).val()) - parseFloat($('#min' + valName).val());
val = parseFloat($('#min' + valName).val()) + diff * percentVal / 100;
$('#percent' + valName).val(percentVal + step);
$('#val' + valName).val(val);
return val;
}
function renderSpiral(params) {
a = params.a;
b = params.b;
e = params.e;
Z = params.Z;
tail = params.tail;
context.clearRect(0, 0, 400, 400);
targetX = a * Math.pow(e, b * Z * .1) * Math.cos(Z * .1);
targetY = a * Math.pow(e, b * Z * .1) * Math.sin(Z * .1);
theta = Math.atan(targetX / targetY);
y = targetX * Math.sin(theta) + targetY * Math.cos(theta);
if (y < 0) theta = theta + Math.PI;
endZ = Z + tail;
endX = a * Math.pow(e, b * endZ * .1) * Math.cos(endZ * .1);
endY = a * Math.pow(e, b * endZ * .1) * Math.sin(endZ * .1);
y = endX * Math.sin(theta) + endY * Math.cos(theta);
x = endX * Math.cos(theta) - endY * Math.sin(theta);
context.save();
max = Math.max(Math.abs(endX), Math.max(Math.abs(endY), 1));
scale = 50 / max;
x = x * scale;
y = y * scale;
context.translate(centerx - x, centery - y);
context.rotate(theta);
context.lineWidth = 1 / scale;
context.scale(scale, scale);
$('#scale').text(scale);
context.beginPath();
context.moveTo(0, 0);
context.lineTo(0, 100);
context.strokeStyle = "green";
context.stroke();
// a = scale;
context.beginPath();
context.rect(-max, -max, max * 2, max * 2);
context.strokeStyle = 'blue';
context.stroke();
context.beginPath();
for (i = 0; i < Z + 1 + tail; i++) {
angle = 0.1 * i;
x = a * Math.pow(e, b * angle) * Math.cos(angle);
y = a * Math.pow(e, b * angle) * Math.sin(angle);
if (i == 0) context.moveTo(x, y);
context.lineTo(x, y);
}
context.strokeStyle = "#F00";
context.stroke();
context.restore();
context.beginPath();
context.moveTo(0, 0);
context.rect(-100 + centerx, -100 + centery, 200, 200);
context.strokeStyle = 'black';
context.stroke();
context.beginPath();
context.rect(-10 + centerx, -10 + centery, 20, 20);
context.fill();
}
<canvas id="c" width="220" height="250"></canvas><input type="button" value="Start" id="toggle"/>
<br/>
Z:
<input type="value" id="minZ" class="val" value="50"/>
<input type="range" min="0" max="100" step="0.001" value="50" id="percentZ"/>
<input type="value" id="maxZ" class="val" value="300"/>
:
<input type="value" id="valZ" class="val" value=""/>
<br/>
b:
<input type="value" id="minb" class="val" value="2"/>
<input type="range" min="0" max="100" step="0.001" value="50" id="percentb"/>
<input type="value" id="maxb" class="val" value=".5"/>
:
<input type="value" id="valb" class="val" value=""/>
<br/>
e:
<input type="value" id="mine" class="val" value="3"/>
<input type="range" min="0" max="100" step="0.001" value="50" id="percente"/>
<input type="value" id="maxe" class="val" value="1.01"/>
:
<input type="value" id="vale" class="val" value=""/>
<br/>
Scale: <span id="scale"></span>
#c {
border: 1px solid #000;
}
.val {
width: 30px;
}