| var canvas; |
| var ctx; |
| var canvasGradients = {}; |
| |
| function canvas_rbga(color) { |
| var a = canvas_opacity(color); |
| var r = (color >> 16) & 0xFF; |
| var g = (color >> 8) & 0xFF; |
| var b = (color >> 0) & 0xFF; |
| return "rgba(" + r + "," + g + "," + b + "," + a + ")"; |
| } |
| |
| function canvas_opacity(color) { |
| var a = (color >> 24) & 0xFF; |
| return a / 255.; |
| } |
| |
| function displayCanvas(displayList) { |
| if (displayList.clear) { |
| ctx.clearRect(0, 0, canvas.width, canvas.height); |
| } |
| for (var index = 0; index < displayList.length; ++index) { |
| drawToCanvas(displayList[index]); |
| } |
| } |
| |
| function drawToCanvas(action) { |
| ctx.save(); |
| var paint = paintToCanvas(action.paint); |
| var draw = action.draw; |
| if ('string' == typeof(draw)) { |
| draw = (new Function("return " + draw))(); |
| } |
| if (isArray(draw)) { |
| assert(draw.length > 0); |
| var picture = 'draw' in draw[0]; |
| if (picture) { |
| for (var index = 0; index < draw.length; ++index) { |
| drawToCanvas(draw[index]); |
| } |
| return; |
| } |
| ctx.beginPath(); |
| for (var index = 0; index < draw.length; ++index) { |
| for (var prop in draw[index]) { |
| var v = draw[index][prop]; |
| switch (prop) { |
| case 'arcTo': |
| ctx.arcTo(v[0], v[1], v[2], v[3], v[4]); |
| break; |
| case 'close': |
| ctx.closePath(); |
| break; |
| case 'cubic': |
| ctx.moveTo(v[0], v[1]); |
| ctx.bezierCurveTo(v[2], v[3], v[4], v[5], v[6], v[7]); |
| break; |
| case 'line': |
| ctx.moveTo(v[0], v[1]); |
| ctx.lineTo(v[2], v[3]); |
| break; |
| case 'quad': |
| ctx.moveTo(v[0], v[1]); |
| ctx.quadraticCurveTo(v[2], v[3], v[4], v[5]); |
| break; |
| default: |
| assert(0); |
| } |
| } |
| } |
| if ('fill' == paint.style) { |
| ctx.fill(); |
| } else { |
| assert('stroke' == paint.style); |
| ctx.stroke(); |
| } |
| } else { |
| assert('string' in draw); |
| if ('fill' == paint.style) { |
| ctx.fillText(draw.string, draw.x, draw.y); |
| } else { |
| assert('stroke' == paint.style); |
| ctx.strokeText(draw.string, draw.x, draw.y); |
| } |
| } |
| ctx.restore(); |
| } |
| |
| function keyframeCanvasInit(displayList, first) { |
| if ('canvas' in first && 'clear' == first.canvas) { |
| displayList.clear = true; |
| } |
| } |
| |
| function paintToCanvas(paint) { |
| var color; |
| var inPicture = 'string' == typeof(paint); |
| if (inPicture) { |
| paint = (new Function("return " + paint))(); |
| assert('object' == typeof(paint) && !isArray(paint)); |
| } |
| if ('gradient' in paint) { |
| var gradient = paint.gradient.split('.'); |
| var gradName = gradient[1]; |
| if (!canvasGradients[gradName]) { |
| var g = window[gradient[0]][gradient[1]]; |
| var grad = ctx.createRadialGradient(g.cx, g.cy, 0, g.cx, g.cy, g.r); |
| var stopLen = g.stops.length; |
| for (var index = 0; index < stopLen; ++index) { |
| var stop = g.stops[index]; |
| var color = canvas_rbga(stop.color); |
| grad.addColorStop(index, color); |
| } |
| canvasGradients[gradName] = grad; |
| } |
| color = canvasGradients[gradName]; |
| if (!inPicture) { |
| ctx.globalAlpha = canvas_opacity(paint.color); |
| } |
| } else { |
| color = canvas_rbga(paint.color); |
| } |
| if ('fill' == paint.style) { |
| ctx.fillStyle = color; |
| } else if ('stroke' == paint.style) { |
| ctx.strokeStyle = color; |
| } else { |
| ctx.globalAlpha = canvas_opacity(paint.color); |
| } |
| if ('strokeWidth' in paint) { |
| ctx.lineWidth = paint.strokeWidth; |
| } |
| if ('typeface' in paint) { |
| var typeface = typefaces[paint.typeface]; |
| var font = typeface.style; |
| if ('textSize' in paint) { |
| font += " " + paint.textSize; |
| } |
| if ('family' in typeface) { |
| font += " " + typeface.family; |
| } |
| ctx.font = font; |
| if ('textAlign' in paint) { |
| ctx.textAlign = paint.textAlign; |
| } |
| if ('textBaseline' in paint) { |
| ctx.textBaseline = paint.textBaseline; |
| } |
| } |
| return paint; |
| } |
| |
| function setupCanvas() { |
| canvas = document.getElementById("canvas"); |
| ctx = canvas ? canvas.getContext("2d") : null; |
| assert(ctx); |
| var resScale = window.devicePixelRatio ? window.devicePixelRatio : 1; |
| var unscaledWidth = canvas.width; |
| var unscaledHeight = canvas.height; |
| canvas.width = unscaledWidth * resScale; |
| canvas.height = unscaledHeight * resScale; |
| canvas.style.width = unscaledWidth + 'px'; |
| canvas.style.height = unscaledHeight + 'px'; |
| if (resScale != 1) { |
| ctx.scale(resScale, resScale); |
| } |
| } |