var IS_SKV8 = typeof document == "undefined"; var HAS_PATH = typeof Path2D != "undefined"; var HAS_DISPLAY_LIST = typeof DisplayList != "undefined"; var NumTeeth = 24; var NumGears = 60; var DeltaTheta = Math.PI/90; var FaceColors = ["#000099", "#006600", "#990000", "#EEEE00"]; var SideColors = ["#0000FF", "#009900", "#FF0000", "#CCCC00"]; function makeGear(pathLike, r) { var dT = Math.PI*2/NumTeeth; var dTq = dT/4; var outer = r; var inner = 0.7 * r; pathLike.moveTo(Math.sin(-2*dTq)*outer, Math.cos(-2*dTq)*outer); for (var i=0; i<NumTeeth; i+=2) { pathLike.lineTo(Math.sin(dT*i-dTq)*outer, Math.cos(dT*i-dTq)*outer); pathLike.lineTo(Math.sin(dT*i+dTq)*inner, Math.cos(dT*i+dTq)*inner); pathLike.lineTo(Math.sin(dT*(i+1)-dTq)*inner, Math.cos(dT*(i+1)-dTq)*inner); pathLike.lineTo(Math.sin(dT*(i+1)+dTq)*outer, Math.cos(dT*(i+1)+dTq)*outer); } } function gearPath(r) { if (HAS_PATH) { p = new Path2D(); makeGear(p, r) p.closePath(); return p; } else { return null; } } function gearDisplayListStroke(r, color) { if (HAS_DISPLAY_LIST) { p = new Path2D(); makeGear(p, r) p.closePath(); var dl = new DisplayList(); dl.strokeStyle = color; dl.stroke(p); dl.finalize() return dl; } else { return null; } } function gearDisplayListFill(r, color) { if (HAS_DISPLAY_LIST) { p = new Path2D(); makeGear(p, r) p.closePath(); var dl = new DisplayList(); dl.fillStyle = color; dl.fill(p); dl.finalize() return dl; } else { return null; } } function strokeGear(ctx, gear) { if (HAS_PATH) { ctx.stroke(gear.path); } else { ctx.beginPath(); makeGear(ctx, gear.r); ctx.closePath(); ctx.stroke(); } } function fillGear(ctx) { if (HAS_PATH) { ctx.fill(gear.path); } else { ctx.beginPath(); makeGear(ctx, gear.r); ctx.closePath(); ctx.fill(); } } function draw3DGear(ctx, angle, gear) { ctx.strokeStyle = gear.sideColor; ctx.fillStyle = gear.faceColor; ctx.rotate(angle); strokeGear(ctx, gear); for (var i=0; i < 20; i++) { ctx.rotate(-angle); ctx.translate(0.707, 0.707); ctx.rotate(angle); if (HAS_DISPLAY_LIST) { ctx.draw(gear.gearStroke); } else { strokeGear(ctx, gear); } } if (HAS_DISPLAY_LIST) { ctx.draw(gear.gearFill); } else { fillGear(ctx, gear); } ctx.rotate(-angle); } function draw3DGearAt(ctx, angle, gear) { ctx.save(); ctx.translate(gear.x, gear.y); draw3DGear(ctx, angle, gear); ctx.restore(); } var onDraw = function() { var ticks=0; var rotation = 0; var gears = []; for (var i=0; i<NumGears; i++) { color = Math.floor(Math.random()*FaceColors.length); r = Math.random()*100+5; gears.push({ x: Math.random()*500, y: Math.random()*500, path: gearPath(r), gearFill: gearDisplayListFill(r, FaceColors[color]), gearStroke: gearDisplayListStroke(r, SideColors[color]), r: r, faceColor: FaceColors[color], sideColor: SideColors[color] }); } function draw(ctx) { ctx.resetTransform(); ctx.fillStyle = "#FFFFFF"; ctx.fillRect(0, 0, 499, 499); rotation += DeltaTheta; if (rotation >= Math.PI*2) { rotation = 0; } for (var i=0; i < gears.length; i++) { gear = gears[i]; draw3DGearAt(ctx, rotation, gear); } ticks++; if (IS_SKV8) { inval(); } }; function fps() { console.log(ticks); ticks = 0; setTimeout(fps, 1000); }; setTimeout(fps, 1000); return draw; }(); if (!IS_SKV8) { window.onload = function(){ var canvas = document.getElementById("gears"); var ctx = canvas.getContext("2d"); function drawCallback() { onDraw(ctx); setTimeout(drawCallback, 1); } setTimeout(drawCallback, 1); } } console.log("HAS_PATH: " + HAS_PATH);