(function () { var _onload = function () { var canvastag = document.getElementById("canvasdonut"); var tmr1 = undefined, tmr2 = undefined; var A = 1, B = 1; // This is a reimplementation according to my math derivation on the page var R1 = 1; var R2 = 2; var K1 = 200; var K2 = 3; var canvasframe = function () { var ctx = canvastag.getContext("2d"); ctx.fillStyle = "#000"; ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); if (tmr1 === undefined) { // only update A and B if the first animation isn't doing it already A += 0.07; B += 0.03; } // precompute cosines and sines of A, B, theta, phi, same as before var cA = Math.cos(A), sA = Math.sin(A), cB = Math.cos(B), sB = Math.sin(B); for (var j = 0; j < 6.28; j += 0.3) { // j <=> theta var ct = Math.cos(j), st = Math.sin(j); // cosine theta, sine theta for (i = 0; i < 6.28; i += 0.1) { // i <=> phi var sp = Math.sin(i), cp = Math.cos(i); // cosine phi, sine phi var ox = R2 + R1 * ct, // object x, y = (R2,0,0) + (R1 cos theta, R1 sin theta, 0) oy = R1 * st; var x = ox * (cB * cp + sA * sB * sp) - oy * cA * sB; // final 3D x coordinate var y = ox * (sB * cp - sA * cB * sp) + oy * cA * cB; // final 3D y var ooz = 1 / (K2 + cA * ox * sp + sA * oy); // one over z var xp = ctx.canvas.width / 2 + K1 * ooz * x; // x' = screen space coordinate, translated and scaled to fit our 320x240 canvas element var yp = ctx.canvas.height / 2 - K1 * ooz * y; // y' (it's negative here because in our output, positive y goes down but in our 3D space, positive y goes up) // luminance, scaled back to 0 to 1 var L = 0.7 * (cp * ct * sB - cA * ct * sp - sA * st + cB * (cA * st - ct * sA * sp)); if (L > 0) { ctx.fillStyle = "rgba(255,255,255," + L + ")"; ctx.fillRect(xp, yp, 1.5, 1.5); } } } }; window.animation = function () { if (tmr2 === undefined) { tmr2 = setInterval(canvasframe, 50); } else { clearInterval(tmr2); tmr2 = undefined; } }; canvasframe(); }; if (document.all) window.attachEvent("onload", _onload); else window.addEventListener("load", _onload, false); })();