Index: experimental/docs/svgbaseddoc.htm |
diff --git a/experimental/docs/svgbaseddoc.htm b/experimental/docs/svgbaseddoc.htm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c96edcc4f6db873c918956312b97b45d7d6f59a9 |
--- /dev/null |
+++ b/experimental/docs/svgbaseddoc.htm |
@@ -0,0 +1,1712 @@ |
+<!DOCTYPE html> |
+<html lang="en"> |
+<head> |
+ |
+ |
+<style> |
+html { |
+ font-family: Helvetica, Arial, sans-serif; |
+ font-size: 100%; |
+} |
+ |
+.controls { |
+ margin: 1em 0; |
+} |
+ |
+button { |
+ display: inline-block; |
+ border-radius: 3px; |
+ border: none; |
+ font-size: 0.9rem; |
+ padding: 0.4rem 0.8em; |
+ background: #69c773; |
+ border-bottom: 1px solid #498b50; |
+ color: white; |
+ -webkit-font-smoothing: antialiased; |
+ font-weight: bold; |
+ margin: 0 0.25rem; |
+ text-align: center; |
+} |
+ |
+button:hover, button:focus { |
+ opacity: 0.75; |
+ cursor: pointer; |
+} |
+ |
+button:active { |
+ opacity: 1; |
+ box-shadow: 0 -3px 10px rgba(0, 0, 0, 0.1) inset; |
+} |
+ |
+</style> |
+ |
+<! set height back to 500 /> |
+<svg id="svg" width="800" height="500" |
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> |
+ |
+<defs> |
+ <radialGradient id="grad1" cx="200" cy="200" r="300" gradientUnits="userSpaceOnUse"> |
+ <stop offset="0%" style="stop-color:rgb(0,0,255); stop-opacity:0.3" /> |
+ <stop offset="100%" style="stop-color:rgb(0,0,255); stop-opacity:0" /> |
+ </radialGradient> |
+ <radialGradient id="grad2" cx="200" cy="200" r="300" gradientUnits="userSpaceOnUse"> |
+ <stop offset="0%" style="stop-color:rgb(0,255,0); stop-opacity:0.3" /> |
+ <stop offset="100%" style="stop-color:rgb(0,255,0); stop-opacity:0" /> |
+ </radialGradient> |
+ <radialGradient id="grad3" cx="200" cy="200" r="300" gradientUnits="userSpaceOnUse"> |
+ <stop offset="0%" style="stop-color:rgb(255,0,0); stop-opacity:0.3" /> |
+ <stop offset="100%" style="stop-color:rgb(255,0,0); stop-opacity:0" /> |
+ </radialGradient> |
+ <radialGradient id="grad4" cx="200" cy="200" r="300" gradientUnits="userSpaceOnUse"> |
+ <stop offset="0%" style="stop-color:rgb(192,63,192); stop-opacity:0.3" /> |
+ <stop offset="100%" style="stop-color:rgb(192,63,192); stop-opacity:0" /> |
+ </radialGradient> |
+ <radialGradient id="grad5" cx="200" cy="200" r="300" gradientUnits="userSpaceOnUse"> |
+ <stop offset="0%" style="stop-color:rgb(127,127,0); stop-opacity:0.3" /> |
+ <stop offset="100%" style="stop-color:rgb(127,127,0); stop-opacity:0" /> |
+ </radialGradient> |
+ <radialGradient id="grad6" cx="200" cy="200" r="300" gradientUnits="userSpaceOnUse"> |
+ <stop offset="0%" style="stop-color:rgb(127,0,127); stop-opacity:0.3" /> |
+ <stop offset="100%" style="stop-color:rgb(127,0,127); stop-opacity:0" /> |
+ </radialGradient> |
+ <radialGradient id="grad7" cx="200" cy="200" r="300" gradientUnits="userSpaceOnUse"> |
+ <stop offset="0%" style="stop-color:rgb(0,127,127); stop-opacity:0.3" /> |
+ <stop offset="100%" style="stop-color:rgb(0,127,127); stop-opacity:0" /> |
+ </radialGradient> |
+ <radialGradient id="grad8" cx="200" cy="200" r="300" gradientUnits="userSpaceOnUse"> |
+ <stop offset="0%" style="stop-color:rgb(63,192,63); stop-opacity:0.3" /> |
+ <stop offset="100%" style="stop-color:rgb(63,192,63); stop-opacity:0" /> |
+ </radialGradient> |
+</defs> |
+ |
+<path id="circleFill" d="M300,200 A 100,100 0,0,0 300,200" fill="#777" fill-opacity="0" /> |
+<path id="circle" d="M300,200 A 100,100 0,0,0 300,200" fill="none" stroke="black" /> |
+ |
+<! elements for keyframe 1 /> |
+<text id="spanWedgeDesc" fill-opacity="0" > |
+All spans are contained by a wedge. |
+</text> |
+<path id="span1" d="M200,200 Q300,300 200,300" fill="none" stroke="black" stroke-opacity="0"/> |
+<path id="span2" d="M200,200 C100,300 100,400 200,300" fill="none" stroke="black" stroke-opacity="0"/> |
+<path id="span3" d="M200,200 C300,100 100,400 300,200" fill="none" stroke="black" stroke-opacity="0"/> |
+<path id="wedge1" d="M200,200 L500,500 A 424.26,424.26 0,0,1 200,624.26 z" fill="url(#grad1)" fill-opacity="0"/> |
+<path id="wedge2" d="M200,200 L200,624.26 A 424.26,424.26 0,0,1 -100,500 z" fill="url(#grad2)" fill-opacity="0"/> |
+<path id="wedge3" d="M200,200 L500,-100 A 424.26,424.26 0,0,1 240,622.5 z" fill="url(#grad3)" fill-opacity="0"/> |
+ |
+<! keyframe 2 /> |
+<text id="trivialWedgeDesc1" fill-opacity="0" > |
+Wedges that don't overlap can be |
+</text> |
+<text id="trivialWedgeDesc2" y="240" fill-opacity="0" > |
+easily sorted. |
+</text> |
+<path id="span4" d="M200,200 Q300,300 400,300" fill="none" stroke="black" stroke-opacity="0"/> |
+<path id="span5" d="M200,200 Q280,320 200,400" fill="none" stroke="black" stroke-opacity="0"/> |
+<path id="span6" d="M200,200 Q60,340 100,400" fill="none" stroke="black" stroke-opacity="0"/> |
+<path id="wedge4" d="M200,200 L500,500 A 424.26,424.26 0,0,1 579.47,389.74 z" fill="url(#grad1)" fill-opacity="0"/> |
+<path id="wedge5" d="M200,200 L389.74,579.47 A 424.26,424.26 0,0,1 200,500 z" fill="url(#grad2)" fill-opacity="0"/> |
+<path id="wedge6" d="M200,200 L10.26,579.47 A 424.26,424.26 0,0,1 -100,500 z" fill="url(#grad3)" fill-opacity="0"/> |
+ |
+ |
+<! keyframe 3 /> |
+<text id="sectorDesc1" fill-opacity="0" > |
+A sector is a wedge of a circle |
+</text> |
+<text id="sectorDesc2" y="240" fill-opacity="0" > |
+containing a range of points. |
+</text> |
+<g id="xaxis" stroke-opacity="0" fill-opacity="0"> |
+ <path d="M100,200 L300,200" fill="none" stroke="rgb(191,191,191)"/> |
+ <text x="100" y="220" fill="rgb(191,191,191)">-X</text> |
+ <text x="300" y="220" text-anchor="end" fill="rgb(191,191,191)">+X</text> |
+</g> |
+<g id="yaxis" stroke-opacity="0" fill-opacity="0"> |
+ <path d="M200,100 L200,300" fill="none" stroke="rgb(191,191,191)"/> |
+ <text x="205" y="100" alignment-baseline="hanging" fill="rgb(191,191,191)">-Y</text> |
+ <text x="205" y="300" fill="rgb(191,191,191)">+Y</text> |
+</g> |
+<text id="sectorDescXYA" x="500" y="310" fill="rgb(0,0,255)" fill-opacity="0"> |
+X > 0> Y > 0 Y < X</text> |
+<text id="sectorDescXYB" x="500" y="360" fill="rgb(0,127,0)" fill-opacity="0"> |
+X < 0 Y > 0 -Y < X</text> |
+<text id="sectorDescXYC" x="500" y="410" fill="rgb(255,0,0)" fill-opacity="0"> |
+X < 0 Y < 0 Y < X</text> |
+<path id="wedgeXY8" d="M200,200 L500,500 A 424.26,424.26 0,0,1 624.26,200 z" fill="url(#grad1)" fill-opacity="0"/> |
+<path id="wedgeXY6" d="M200,200 L-100,500 A 424.26,424.26 0,0,1 200,624.26 z" fill="url(#grad2)" fill-opacity="0"/> |
+<path id="wedgeXY3" d="M200,200 L-100,-100 A 424.26,424.26 0,0,1 200,-175.74 z" fill="url(#grad3)" fill-opacity="0"/> |
+ |
+<! keyframe 4 /> |
+<text id="lineSingleDesc" fill-opacity="0" > |
+Line spans are contained by a single sector. |
+</text> |
+<text id="sectorDescXY1" x="500" y="460" fill="rgb(192,63,192)" fill-opacity="0"> |
+X > 0 Y < 0 -Y < X</text> |
+<text id="sectorDescXY2" x="500" y="460" fill="rgb(127,127,0)" fill-opacity="0"> |
+X > 0 Y < 0 -Y > X</text> |
+<text id="sectorDescXY3" x="500" y="460" fill="rgb(255,0,0)" fill-opacity="0"> |
+X < 0 Y < 0 Y < X</text> |
+<text id="sectorDescXY4" x="500" y="460" fill="rgb(127,0,127)" fill-opacity="0"> |
+X < 0 Y < 0 Y > X</text> |
+<text id="sectorDescXY5" x="500" y="460" fill="rgb(0,127,127)" fill-opacity="0"> |
+X < 0 Y > 0 -Y < X</text> |
+<text id="sectorDescXY6" x="500" y="460" fill="rgb(0,127,0)" fill-opacity="0"> |
+X < 0 Y > 0 -Y < X</text> |
+<text id="sectorDescXY7" x="500" y="460" fill="rgb(63,192,63)" fill-opacity="0"> |
+X > 0 Y > 0 Y > X</text> |
+<text id="sectorDescXY8" x="500" y="460" fill="rgb(0,0,255)" fill-opacity="0"> |
+X > 0 Y > 0 Y < X</text> |
+<path id="wedgeXY1" d="M200,200 L500,-100 A 424.26,424.26 0,0,1 624.26,200 z" fill="url(#grad4)" fill-opacity="0"/> |
+<path id="wedgeXY2" d="M200,200 L200,-175.74 A 424.26,424.26 0,0,1 500,-100 z" fill="url(#grad5)" fill-opacity="0"/> |
+<path id="wedgeXY4" d="M200,200 L-175.74,200 A 424.26,424.26 0,0,1 -100,-100 z" fill="url(#grad6)" fill-opacity="0"/> |
+<path id="wedgeXY5" d="M200,200 L-100,500 A 424.26,424.26 0,0,1 -175.74,200 z" fill="url(#grad7)" fill-opacity="0"/> |
+<path id="wedgeXY7" d="M200,200 L200,624.26 A 424.26,424.26 0,0,1 500,500 z" fill="url(#grad8)" fill-opacity="0"/> |
+<path id="lineSegment" d="M200,200 L200,624.26" fill="none" stroke="black" stroke-opacity="0"/> |
+ |
+<! keyframe 5 /> |
+<text id="curveMultipleDesc1" fill-opacity="0" > |
+A curve span may cover more |
+</text> |
+<text id="curveMultipleDesc2" y="240" fill-opacity="0" > |
+than one sector. |
+</text> |
+<path id="curveSegment" d="M200,200 C250,200 300,150 300,100" fill="none" stroke="black" stroke-opacity="0"/> |
+<path id="curveSegment1" d="M200,200 C250,200 300,150 300,100" fill="none"/> |
+<path id="curveSegment2" d="M200,200 C250,200 300,150 200,100" fill="none"/> |
+<path id="curveSegment3" d="M200,200 C350,200 250,-150 170,300" fill="none"/> |
+ |
+<! keyframe 6 /> |
+<text id="line1DDest1" fill-opacity="0" > |
+Some lines occupy one-dimensional |
+</text> |
+<text id="line1DDest2" y="240" fill-opacity="0" > |
+sectors. |
+</text> |
+<text id="sectorDescXY9" x="500" y="460" fill="rgb(192,92,31)" fill-opacity="0"> |
+X > 0 Y == 0</text> |
+<text id="sectorDescXY10" x="500" y="460" fill="rgb(31,92,192)" fill-opacity="0"> |
+Y > 0 0 == X</text> |
+<text id="sectorDescXY11" x="500" y="460" fill="rgb(127,63,127)" fill-opacity="0"> |
+X < 0 Y == X</text> |
+<path id="horzSegment" d="M200,200 L341.4,200" fill="none" stroke="rgb(192,92,31)" stroke-width="2" stroke-opacity="0"/> |
+<path id="vertSegment" d="M200,200 L200,341.4" fill="none" stroke="rgb(31,92,192)" stroke-width="2" stroke-opacity="0"/> |
+<path id="diagSegment" d="M200,200 L100,100" fill="none" stroke="rgb(127,63,127)" stroke-width="2" stroke-opacity="0"/> |
+ |
+<! keyframe 7 /> |
+<text id="curve1dDesc1" fill-opacity="0" > |
+Some curves initially occupy |
+</text> |
+<text id="curve1dDesc2" y="240" fill-opacity="0" > |
+one-dimensional sectors, then diverge. |
+</text> |
+<path id="cubicSegment" fill="none" stroke="black" /> |
+<path id="cubicSegment1" d="M200,200 C200,200 200,200 200,200" fill="none" /> |
+<path id="cubicSegment2" d="M200,200 C250,200 300,200 300,100" fill="none"/> |
+ |
+<text id="sectorNumberDesc" fill-opacity="0" > |
+Each sector is assigned a number. |
+</text> |
+<text id="spanSectorDesc" fill-opacity="0" > |
+Each span has a bit set for one or more sectors. |
+</text> |
+<text id="bitOverDesc" fill-opacity="0" > |
+Span sets allow rough sorting without angle computation. |
+</text> |
+ |
+</svg> |
+ |
+<! canvas support /> |
+<script> |
+ |
+var keyFrameQueue = []; |
+var animationsPending = []; |
+var animationsActive = []; |
+var displayList = []; |
+var visibleFinished = []; |
+ |
+var animationState = {}; |
+animationState.reset = function () { |
+ this.start = null; |
+ this.time = 0; |
+ this.requestID = null; |
+ this.paused = false; |
+ this.displayEngine = 'Canvas'; |
+} |
+ |
+circle.center = { x: 200, y: 200 } |
+circle.radius = 100; |
+ |
+function assert(condition) { |
+ if (!condition) debugger; |
+} |
+ |
+function CanvasGrads(ctx) { |
+ var grad1 = ctx.createRadialGradient(200, 200, 0, 200, 200, 300); |
+ grad1.addColorStop(0, "rgba(0,0,255, 0.3)"); |
+ grad1.addColorStop(1, "rgba(0,0,255, 0)"); |
+ var grad2 = ctx.createRadialGradient(200, 200, 0, 200, 200, 300); |
+ grad2.addColorStop(0, "rgba(0,255,0, 0.3)"); |
+ grad2.addColorStop(1, "rgba(0,255,0, 0)"); |
+ var grad3 = ctx.createRadialGradient(200, 200, 0, 200, 200, 300); |
+ grad3.addColorStop(0, "rgba(255,0,0, 0.3)"); |
+ grad3.addColorStop(1, "rgba(255,0,0, 0)"); |
+ var grad4 = ctx.createRadialGradient(200, 200, 0, 200, 200, 300); |
+ grad4.addColorStop(0, "rgba(192,63,192, 0.3)"); |
+ grad4.addColorStop(1, "rgba(192,63,192, 0)"); |
+ var grad5 = ctx.createRadialGradient(200, 200, 0, 200, 200, 300); |
+ grad5.addColorStop(0, "rgba(127,127,0, 0.3)"); |
+ grad5.addColorStop(1, "rgba(127,127,0, 0)"); |
+ var grad6 = ctx.createRadialGradient(200, 200, 0, 200, 200, 300); |
+ grad6.addColorStop(0, "rgba(127,0,127, 0.3)"); |
+ grad6.addColorStop(1, "rgba(127,0,127, 0)"); |
+ var grad7 = ctx.createRadialGradient(200, 200, 0, 200, 200, 300); |
+ grad7.addColorStop(0, "rgba(0,127,127, 0.3)"); |
+ grad7.addColorStop(1, "rgba(0,127,127, 0)"); |
+ var grad8 = ctx.createRadialGradient(200, 200, 0, 200, 200, 300); |
+ grad8.addColorStop(0, "rgba(63,192,63, 0.3)"); |
+ grad8.addColorStop(1, "rgba(63,192,63, 0)"); |
+ var data = { |
+ grad1: grad1, |
+ grad2: grad2, |
+ grad3: grad3, |
+ grad4: grad4, |
+ grad5: grad5, |
+ grad6: grad6, |
+ grad7: grad7, |
+ grad8: grad8, |
+ }; |
+ return data; |
+} |
+ |
+function skip_sep(data) { |
+ if (!data.length) { |
+ return data; |
+ } |
+ while (data[0] == ' ' || data[0] == ',') { |
+ data = data.substring(1); |
+ } |
+ return data; |
+} |
+ |
+function find_points(str, value, count, isRelative, relative) { |
+ var numRegEx = /-?\d+\.?\d*(?:e-?\d+)?/g; |
+ var match; |
+ for (var index = 0; index < count; ++index) { |
+ str = skip_sep(str); |
+ match = numRegEx.exec(str); |
+ assert(match); |
+ var x = Number(match[0]); |
+ str = skip_sep(str); |
+ match = numRegEx.exec(str); |
+ assert(match); |
+ var y = Number(match[0]); |
+ value[index] = { x: x, y : y }; |
+ } |
+ if (isRelative) { |
+ for (var index = 0; index < count; index++) { |
+ value[index].x += relative.x; |
+ value[index].y += relative.y; |
+ } |
+ } |
+ return str.substring(match.index + match[0].length); |
+} |
+ |
+function find_scalar(str, obj, isRelative, relative) { |
+ var numRegEx = /-?\d+\.?\d*(?:e-?\d+)?/g; |
+ str = skip_sep(str); |
+ var match = numRegEx.exec(str); |
+ obj.value = Number(match[0]); |
+ if (isRelative) { |
+ obj.value += relative; |
+ } |
+ return str.substring(match.index + match[0].length); |
+} |
+ |
+function parse_path(data) { |
+ var path = "ctx.beginPath();\n"; |
+ var f = {x:0, y:0}; |
+ var c = {x:0, y:0}; |
+ var lastc = {x:0, y:0}; |
+ var points = []; |
+ var op = '\0'; |
+ var previousOp = '\0'; |
+ var relative = false; |
+ for (;;) { |
+ data = skip_sep(data); |
+ if (!data.length) { |
+ break; |
+ } |
+ var ch = data[0]; |
+ if (('0' <= ch && ch <= '9') || ch == '-' || ch == '+') { |
+ assert(op != '\0'); |
+ } else if (ch == ' ' || ch == ',') { |
+ data = skip_sep(data); |
+ } else { |
+ op = ch; |
+ relative = false; |
+ if ('a' <= op && op <= 'z') { |
+ op = op.toUpperCase(); |
+ relative = true; |
+ } |
+ data = data.substring(1); |
+ data = skip_sep(data); |
+ } |
+ switch (op) { |
+ case 'A': |
+ var radii = []; |
+ data = find_points(data, radii, 1, false, null); |
+ var xaxisObj = {}; |
+ data = find_scalar(data, xaxisObj, false, null); |
+ var largeArcObj = {}; |
+ data = find_scalar(data, largeArcObj, false, null); |
+ var sweepObj = {}; |
+ data = find_scalar(data, sweepObj, false, null); |
+ data = find_points(data, points, 1, relative, c); |
+ var mid = { x: (c.x + points[0].x) / 2, y: (c.y + points[0].y) / 2 }; |
+ var midVec = { x: mid.x - c.x, y: mid.y - c.y }; |
+ var midLenSqr = midVec.x * midVec.x + midVec.y * midVec.y; |
+ var radius = radii[0].x; |
+ var scale = Math.sqrt(midLenSqr) / Math.sqrt(radius * radius - midLenSqr); |
+ var tangentPt = { x: mid.x + midVec.y * scale, |
+ y: mid.y - midVec.x * scale }; |
+ path += "ctx.arcTo(" + tangentPt.x + "," + tangentPt.y + "," |
+ + points[0].x + "," + points[0].y + "," + radius + ");\n"; |
+ c = points[0]; |
+ break; |
+ case 'M': |
+ data = find_points(data, points, 1, relative, c); |
+ path += "ctx.moveTo(" + points[0].x + "," + points[0].y + ");\n"; |
+ op = 'L'; |
+ c = points[0]; |
+ break; |
+ case 'L': |
+ data = find_points(data, points, 1, relative, c); |
+ path += "ctx.lineTo(" + points[0].x + "," + points[0].y + ");\n"; |
+ c = points[0]; |
+ break; |
+ case 'H': { |
+ var xObj = {}; |
+ data = find_scalar(data, xObj, relative, c.x); |
+ path += "ctx.lineTo(" + xObj.value + "," + c.y + ");\n"; |
+ c.x = xObj.value; |
+ } break; |
+ case 'V': { |
+ var yObj = {}; |
+ data = find_scalar(data, y, relative, c.y); |
+ path += "ctx.lineTo(" + c.x + "," + yObj.value+ ");\n"; |
+ c.y = yObj.value; |
+ } break; |
+ case 'C': |
+ data = find_points(data, points, 3, relative, c); |
+ path += "ctx.bezierCurveTo(" + points[0].x + "," + points[0].y + "," |
+ + points[1].x + "," + points[1].y + "," |
+ + points[2].x + "," + points[2].y + ");\n"; |
+ lastc = points[1]; |
+ c = points[2]; |
+ break; |
+ case 'S': |
+ var pts2_3 = []; |
+ data = find_points(data, pts2_3, 2, relative, c); |
+ points[0] = c; |
+ points[1] = pts2_3[0]; |
+ points[2] = pts2_3[1]; |
+ if (previousOp == 'C' || previousOp == 'S') { |
+ points[0].x -= lastc.x - c.x; |
+ points[0].y -= lastc.y - c.y; |
+ } |
+ path += "ctx.bezierCurveTo(" + points[0].x + "," + points[0].y + "," |
+ + points[1].x + "," + points[1].y + "," |
+ + points[2].x + "," + points[2].y + ");\n"; |
+ lastc = points[1]; |
+ c = points[2]; |
+ break; |
+ case 'Q': // Quadratic Bezier Curve |
+ data = find_points(data, points, 2, relative, c); |
+ path += "ctx.quadraticCurveTo(" + points[0].x + "," + points[0].y + "," |
+ + points[1].x + "," + points[1].y + ");\n"; |
+ lastc = points[0]; |
+ c = points[1]; |
+ break; |
+ case 'T': |
+ var pts2 = []; |
+ data = find_points(data, pts2, 1, relative, c); |
+ points[0] = pts2[0]; |
+ points[1] = pts2[0]; |
+ if (previousOp == 'Q' || previousOp == 'T') { |
+ points[0].x = c.x * 2 - lastc.x; |
+ points[0].y = c.y * 2 - lastc.y; |
+ } |
+ path += "ctx.quadraticCurveTo(" + points[0].x + "," + points[0].y + "," |
+ + points[1].x + "," + points[1].y + ");\n"; |
+ path.quadTo(points[0], points[1]); |
+ lastc = points[0]; |
+ c = points[1]; |
+ break; |
+ case 'Z': |
+ path += "ctx.closePath();\n"; |
+ c = f; |
+ op = '\0'; |
+ break; |
+ case '~': |
+ var args = []; |
+ data = find_points(data, args, 2, false, null); |
+ path += "moveTo(" + args[0].x + "," + args[0].y + ");\n"; |
+ path += "lineTo(" + args[1].x + "," + args[1].y + ");\n"; |
+ break; |
+ default: |
+ return false; |
+ } |
+ if (previousOp == 0) { |
+ f = c; |
+ } |
+ previousOp = op; |
+ } |
+ return path; |
+} |
+ |
+function CanvasPaths(ctx) { |
+ var svgStrs = { |
+ // keyframe 1 |
+ span1: "M200,200 Q300,300 200,300", |
+ span2: "M200,200 C100,300 100,400 200,300", |
+ span3: "M200,200 C300,100 100,400 300,200", |
+ wedge1: "M200,200 L500,500 A 424.26,424.26 0,0,1 200,624.26 z", |
+ wedge2: "M200,200 L200,624.26 A 424.26,424.26 0,0,1 -100,500 z", |
+ wedge3: "M200,200 L500,-100 A 424.26,424.26 0,0,1 240,622.5 z", |
+ // keyframe 2 |
+ span4: "M200,200 Q300,300 400,300", |
+ span5: "M200,200 Q280,320 200,400", |
+ span6: "M200,200 Q60,340 100,400", |
+ wedge4: "M200,200 L500,500 A 424.26,424.26 0,0,1 579.47,389.74 z", |
+ wedge5: "M200,200 L389.74,579.47 A 424.26,424.26 0,0,1 200,500 z", |
+ wedge6: "M200,200 L10.26,579.47 A 424.26,424.26 0,0,1 -100,500 z", |
+ // keyframe 3 |
+ xaxis: "M100,200 L300,200", |
+ yaxis: "M200,100 L200,300", |
+ wedgeXY8: "M200,200 L500,500 A 424.26,424.26 0,0,1 624.26,200 z", |
+ wedgeXY6: "M200,200 L-100,500 A 424.26,424.26 0,0,1 200,624.26 z", |
+ wedgeXY3: "M200,200 L-100,-100 A 424.26,424.26 0,0,1 200,-175.74 z", |
+ // keyframe 4 |
+ wedgeXY1: "M200,200 L500,-100 A 424.26,424.26 0,0,1 624.26,200 z", |
+ wedgeXY2: "M200,200 L200,-175.74 A 424.26,424.26 0,0,1 500,-100 z", |
+ wedgeXY4: "M200,200 L-175.74,200 A 424.26,424.26 0,0,1 -100,-100 z", |
+ wedgeXY5: "M200,200 L-100,500 A 424.26,424.26 0,0,1 -175.74,200 z", |
+ wedgeXY7: "M200,200 L200,624.26 A 424.26,424.26 0,0,1 500,500 z", |
+ lineSegment: "M200,200 L200,624.26", |
+ // keyframe 5 |
+ curveSegment: "M200,200 C250,200 300,150 300,100", |
+ curveSegment1: "M200,200 C250,200 300,150 300,100", |
+ curveSegment2: "M200,200 C250,200 300,150 200,100", |
+ curveSegment3: "M200,200 C350,200 250,-150 170,300", |
+ // keyframe 6 |
+ horzSegment: "M200,200 L341.4,200", |
+ vertSegment: "M200,200 L200,341.4", |
+ diagSegment: "M200,200 L100,100", |
+ // keyframe 7 |
+ cubicSegment: "M200,200 C200,200 200,200 200,200", |
+ cubicSegment1: "M200,200 C200,200 200,200 200,200", |
+ cubicSegment2: "M200,200 C250,200 300,200 300,100", |
+ }; |
+ var paths = []; |
+ var keys = Object.keys(svgStrs); |
+ for (var index in keys) { |
+ var key = keys[index]; |
+ var str = svgStrs[key]; |
+ var path = parse_path(str); |
+ var record = []; |
+ paths[key] = { |
+ str: str, |
+ funcBody: path, |
+ }; |
+ } |
+ return paths; |
+} |
+ |
+function canvas_fill_font(record) { |
+ assert(record); |
+ var str = 'ctx.font = "normal 1.3rem Helvetica,Arial";\n'; |
+ if (record.fillStyle) { |
+ str += 'ctx.fillStyle = ' + record.fillStyle + ';\n'; |
+ } |
+ return str; |
+} |
+ |
+function canvas_fill_text(record) { |
+ assert(record); |
+ assert(typeof record.fillText == 'string'); |
+ return 'ctx.fillText("' + record.fillText + '"'; |
+} |
+ |
+function canvas_xy(record) { |
+ var x = typeof record.x == "number" ? record.x : 400; |
+ var y = typeof record.y == "number" ? record.y : 200; |
+ return ', ' + x + ', ' + y + ');\n'; |
+} |
+ |
+function canvas_text_xy(record) { |
+ return canvas_fill_text(record) + canvas_xy(record); |
+} |
+ |
+function add_canvas_stroke(paths, data, id, strokeStyle) { |
+ var record = {}; |
+ record.data = paths[id].funcBody; |
+ record.style = 'ctx.strokeStyle = ' + (strokeStyle ? strokeStyle : '"black"') + ';\n'; |
+ record.draw = 'ctx.stroke();\n'; |
+ record.func = new Function('ctx', record.data + record.style + record.draw); |
+ return data[id] = record; |
+} |
+ |
+function add_canvas_style(record, style) { |
+ record.style += style; |
+ record.func = new Function('ctx', record.data + record.style + record.draw); |
+} |
+ |
+function add_canvas_fill(paths, data, id, fillStyle) { |
+ var record = {}; |
+ record.data = paths[id].funcBody; |
+ record.style = 'ctx.fillStyle = ' + (fillStyle ? fillStyle : '"black"') + ';\n'; |
+ record.draw = 'ctx.fill();\n'; |
+ record.func = new Function('ctx', record.data + record.style + record.draw); |
+ return data[id] = record; |
+} |
+ |
+function add_canvas_text(data, id, params) { |
+ var record = {}; |
+ record.style = canvas_fill_font(params); |
+ record.draw = canvas_fill_text(params); |
+ record.position = canvas_xy(params); |
+ record.x = params.x; |
+ record.y = params.y; |
+ record.func = new Function('ctx', record.style + record.draw + record.position); |
+ return data[id] = record; |
+} |
+ |
+function keyframe1(grads, paths) { |
+ var data = []; |
+ add_canvas_text(data, "spanWedgeDesc", { fillText:"All spans are contained by a wedge" } ); |
+ add_canvas_stroke(paths, data, "span1"); |
+ add_canvas_stroke(paths, data, "span2"); |
+ add_canvas_stroke(paths, data, "span3"); |
+ add_canvas_fill(paths, data, "wedge1", "grads.grad1"); |
+ add_canvas_fill(paths, data, "wedge2", "grads.grad2"); |
+ add_canvas_fill(paths, data, "wedge3", "grads.grad3"); |
+ return data; |
+} |
+ |
+function keyframe2(grads, paths) { |
+ var data = []; |
+ add_canvas_text(data, "trivialWedgeDesc1", { fillText:"Wedges that don't overlap can be" } ); |
+ add_canvas_text(data, "trivialWedgeDesc2", { fillText:"easily sorted.", y:240 } ); |
+ add_canvas_stroke(paths, data, "span4").debug = true; |
+ add_canvas_stroke(paths, data, "span5"); |
+ add_canvas_stroke(paths, data, "span6"); |
+ add_canvas_fill(paths, data, "wedge4", "grads.grad1"); |
+ add_canvas_fill(paths, data, "wedge5", "grads.grad2"); |
+ add_canvas_fill(paths, data, "wedge6", "grads.grad3"); |
+ return data; |
+} |
+ |
+function setup_axes(paths, data) { |
+ var color = '"rgb(191,191,191)"'; |
+ var xaxis = add_canvas_stroke(paths, data, "xaxis", color); |
+ xaxis.funcBody = canvas_fill_font( { fillStyle:color } ); |
+ xaxis.funcBody += canvas_text_xy( { fillText:"-X", x:100, y:220 } ); |
+ xaxis.funcBody += "ctx.textAlign = 'right';\n"; |
+ xaxis.funcBody += canvas_text_xy( { fillText:"+X", x:300, y:220 } ); |
+ xaxis.func = new Function('ctx', xaxis.data + xaxis.style + xaxis.draw + xaxis.funcBody); |
+ var yaxis = add_canvas_stroke(paths, data, "yaxis", color); |
+ yaxis.funcBody = canvas_fill_font( { fillStyle:color } ); |
+ yaxis.funcBody += "ctx.textBaseline = 'hanging';\n"; |
+ yaxis.funcBody += canvas_text_xy( { fillText:"-Y", x:205, y:100 } ); |
+ yaxis.funcBody += "ctx.textBaseline = 'alphabetic';\n"; |
+ yaxis.funcBody += canvas_text_xy( { fillText:"+Y", x:205, y:300 } ); |
+ yaxis.func = new Function('ctx', yaxis.data + yaxis.style + yaxis.draw + yaxis.funcBody); |
+} |
+ |
+function keyframe3(grads, paths) { |
+ var data = []; |
+ add_canvas_text(data, "sectorDesc1", { fillText:"A sector is a wedge of a circle" } ); |
+ add_canvas_text(data, "sectorDesc2", { fillText:"containing a range of points.", y:240 } ); |
+ setup_axes(paths, data); |
+ add_canvas_text(data, "sectorDescXYA", |
+ { fillText:"X > 0 Y > 0 Y < X", x:500, y:310, fillStyle:'"rgb(0,0,255)"'} ); |
+ add_canvas_text(data, "sectorDescXYB", |
+ { fillText:"X < 0 Y > 0 -Y < X", x:500, y:360, fillStyle:'"rgb(0,127,0)"'} ); |
+ add_canvas_text(data, "sectorDescXYC", |
+ { fillText:"X < 0 Y < 0 Y < X", x:500, y:410, fillStyle:'"rgb(255,0,0)"'} ); |
+ add_canvas_fill(paths, data, "wedgeXY8", "grads.grad1"); |
+ add_canvas_fill(paths, data, "wedgeXY6", "grads.grad2"); |
+ add_canvas_fill(paths, data, "wedgeXY3", "grads.grad3"); |
+ return data; |
+} |
+ |
+function keyframe4(grads, paths) { |
+ var data = []; |
+ setup_axes(paths, data); |
+ add_canvas_text(data, "lineSingleDesc", |
+ { fillText:"Line spans are contained by a single sector." } ); |
+ add_canvas_text(data, "sectorDescXY1", |
+ { fillText:"X > 0 Y < 0 -Y < X", x:500, y:460, fillStyle:'"rgb(192,63,192)"'} ); |
+ add_canvas_text(data, "sectorDescXY2", |
+ { fillText:"X > 0 Y < 0 -Y > X", x:500, y:460, fillStyle:'"rgb(127,127,0)"'} ); |
+ add_canvas_text(data, "sectorDescXY3", |
+ { fillText:"X < 0 Y < 0 Y < X", x:500, y:460, fillStyle:'"rgb(255,0,0)"'} ); |
+ add_canvas_text(data, "sectorDescXY4", |
+ { fillText:"X < 0 Y < 0 Y > X", x:500, y:460, fillStyle:'"rgb(127,0,127)"'} ); |
+ add_canvas_text(data, "sectorDescXY5", |
+ { fillText:"X < 0 Y > 0 -Y < X", x:500, y:460, fillStyle:'"rgb(0,127,127)"'} ); |
+ add_canvas_text(data, "sectorDescXY6", |
+ { fillText:"X < 0 Y > 0 -Y < X", x:500, y:460, fillStyle:'"rgb(0,127,0)"'} ); |
+ add_canvas_text(data, "sectorDescXY7", |
+ { fillText:"X > 0 Y > 0 Y > X", x:500, y:460, fillStyle:'"rgb(63,192,63)"'} ); |
+ add_canvas_text(data, "sectorDescXY8", |
+ { fillText:"X > 0 Y > 0 Y < X", x:500, y:460, fillStyle:'"rgb(0,0,255)"'} ); |
+ add_canvas_fill(paths, data, "wedgeXY1", "grads.grad4"); |
+ add_canvas_fill(paths, data, "wedgeXY2", "grads.grad5"); |
+ add_canvas_fill(paths, data, "wedgeXY3", "grads.grad3"); |
+ add_canvas_fill(paths, data, "wedgeXY4", "grads.grad6"); |
+ add_canvas_fill(paths, data, "wedgeXY5", "grads.grad7"); |
+ add_canvas_fill(paths, data, "wedgeXY6", "grads.grad2"); |
+ add_canvas_fill(paths, data, "wedgeXY7", "grads.grad8"); |
+ add_canvas_fill(paths, data, "wedgeXY8", "grads.grad1"); |
+ add_canvas_stroke(paths, data, "lineSegment"); |
+ return data; |
+} |
+ |
+function keyframe5(grads, paths) { |
+ var data = []; |
+ setup_axes(paths, data); |
+ add_canvas_text(data, "curveMultipleDesc1", |
+ { fillText:"A curve span may cover more" } ); |
+ add_canvas_text(data, "curveMultipleDesc2", |
+ { fillText:"than one sector.", y:240 } ); |
+ add_canvas_stroke(paths, data, "curveSegment"); |
+ add_canvas_text(data, "sectorDescXY1", |
+ { fillText:"X > 0 Y < 0 -Y < X", x:500, y:460, fillStyle:'"rgb(192,63,192)"'} ); |
+ add_canvas_text(data, "sectorDescXY2", |
+ { fillText:"X > 0 Y < 0 -Y > X", x:500, y:460, fillStyle:'"rgb(127,127,0)"'} ); |
+ add_canvas_text(data, "sectorDescXY3", |
+ { fillText:"X < 0 Y < 0 Y < X", x:500, y:460, fillStyle:'"rgb(255,0,0)"'} ); |
+ add_canvas_text(data, "sectorDescXY4", |
+ { fillText:"X < 0 Y < 0 Y > X", x:500, y:460, fillStyle:'"rgb(127,0,127)"'} ); |
+ add_canvas_text(data, "sectorDescXY5", |
+ { fillText:"X < 0 Y > 0 -Y < X", x:500, y:460, fillStyle:'"rgb(0,127,127)"'} ); |
+ add_canvas_text(data, "sectorDescXY6", |
+ { fillText:"X < 0 Y > 0 -Y < X", x:500, y:460, fillStyle:'"rgb(0,127,0)"'} ); |
+ add_canvas_fill(paths, data, "wedgeXY1", "grads.grad4"); |
+ add_canvas_fill(paths, data, "wedgeXY2", "grads.grad5"); |
+ add_canvas_fill(paths, data, "wedgeXY3", "grads.grad3"); |
+ add_canvas_fill(paths, data, "wedgeXY4", "grads.grad6"); |
+ add_canvas_fill(paths, data, "wedgeXY5", "grads.grad7"); |
+ add_canvas_fill(paths, data, "wedgeXY6", "grads.grad2"); |
+ return data; |
+} |
+ |
+function keyframe6(grads, paths) { |
+ var data = []; |
+ setup_axes(paths, data); |
+ |
+ add_canvas_text(data, "line1DDest1", |
+ { fillText:"Some lines occupy one-dimensional" } ); |
+ add_canvas_text(data, "line1DDest2", |
+ { fillText:"sectors.", y:240 } ); |
+ add_canvas_text(data, "sectorDescXY9", |
+ { fillText:"X > 0 Y == 0", x:500, y:460, fillStyle:'"rgb(192,92,31)"' } ); |
+ add_canvas_text(data, "sectorDescXY10", |
+ { fillText:"Y > 0 0 == X", x:500, y:460, fillStyle:'"rgb(31,92,192)"' } ); |
+ add_canvas_text(data, "sectorDescXY11", |
+ { fillText:"X < 0 Y == X", x:500, y:460, fillStyle:'"rgb(127,63,127)"' } ); |
+ var horz = add_canvas_stroke(paths, data, "horzSegment", '"rgb(192,92,31)"'); |
+ add_canvas_style(horz, "ctx.lineWidth = " + 2 * animationState.resScale + ";\n"); |
+ var vert = add_canvas_stroke(paths, data, "vertSegment", '"rgb(31,92,192)"'); |
+ add_canvas_style(vert, "ctx.lineWidth = " + 2 * animationState.resScale + ";\n"); |
+ var diag = add_canvas_stroke(paths, data, "diagSegment", '"rgb(127,63,127)"'); |
+ add_canvas_style(diag, "ctx.lineWidth = " + 2 * animationState.resScale + ";\n"); |
+ return data; |
+} |
+ |
+function keyframe7(grads, paths) { |
+ var data = []; |
+ setup_axes(paths, data); |
+ add_canvas_text(data, "curve1dDesc1", |
+ { fillText:"Some curves initially occupy" } ); |
+ add_canvas_text(data, "curve1dDesc2", |
+ { fillText:"one-dimensional sectors, then diverge.", y:240 } ); |
+ add_canvas_stroke(paths, data, "cubicSegment"); |
+ add_canvas_text(data, "sectorDescXY1", |
+ { fillText:"X > 0 Y < 0 -Y < X", x:500, y:460, fillStyle:'"rgb(192,63,192)"'} ); |
+ add_canvas_text(data, "sectorDescXY9", |
+ { fillText:"X > 0 Y == 0", x:500, y:460, fillStyle:'"rgb(192,92,31)"' } ); |
+ var horz = add_canvas_stroke(paths, data, "horzSegment", '"rgb(192,92,31)"'); |
+ add_canvas_style(horz, "ctx.lineWidth = " + 2 * animationState.resScale + ";\n"); |
+ add_canvas_fill(paths, data, "wedgeXY1", "grads.grad4"); |
+ return data; |
+} |
+ |
+var canvasData = null; |
+ |
+function CanvasInit(keyframe) { |
+ canvasData = window[keyframe](grads, paths); |
+} |
+ |
+</script> |
+ |
+<script> |
+ |
+function interp(A, B, t) { |
+ return A + (B - A) * t; |
+} |
+ |
+function interp_cubic_coords(x1, x2, x3, x4, t) |
+{ |
+ var ab = interp(x1, x2, t); |
+ var bc = interp(x2, x3, t); |
+ var cd = interp(x3, x4, t); |
+ var abc = interp(ab, bc, t); |
+ var bcd = interp(bc, cd, t); |
+ var abcd = interp(abc, bcd, t); |
+ return abcd; |
+} |
+ |
+function cubic_partial(value, p) { |
+ var x1 = p[0], y1 = p[1], x2 = p[2], y2 = p[3]; |
+ var x3 = p[4], y3 = p[5], x4 = p[6], y4 = p[7]; |
+ var t1 = 0, t2 = value; |
+ var ax = interp_cubic_coords(x1, x2, x3, x4, t1); |
+ var ay = interp_cubic_coords(y1, y2, y3, y4, t1); |
+ var ex = interp_cubic_coords(x1, x2, x3, x4, (t1*2+t2)/3); |
+ var ey = interp_cubic_coords(y1, y2, y3, y4, (t1*2+t2)/3); |
+ var fx = interp_cubic_coords(x1, x2, x3, x4, (t1+t2*2)/3); |
+ var fy = interp_cubic_coords(y1, y2, y3, y4, (t1+t2*2)/3); |
+ var dx = interp_cubic_coords(x1, x2, x3, x4, t2); |
+ var dy = interp_cubic_coords(y1, y2, y3, y4, t2); |
+ var mx = ex * 27 - ax * 8 - dx; |
+ var my = ey * 27 - ay * 8 - dy; |
+ var nx = fx * 27 - ax - dx * 8; |
+ var ny = fy * 27 - ay - dy * 8; |
+ var bx = (mx * 2 - nx) / 18; |
+ var by = (my * 2 - ny) / 18; |
+ var cx = (nx * 2 - mx) / 18; |
+ var cy = (ny * 2 - my) / 18; |
+ var array = [ |
+ ax, ay, bx, by, cx, cy, dx, dy |
+ ]; |
+ return array; |
+} |
+ |
+function evaluate_at(value, p) { |
+ var array = []; |
+ for (var index = 0; index < p.length; ++index) { |
+ var func = new Function('value', 'return ' + p[index] + ';'); |
+ array[index] = func(value); |
+ } |
+ return array; |
+} |
+ |
+function interpolate_at(value, p) { |
+ var array = []; |
+ var start = p[0]; |
+ var end = p[1]; |
+ assert(typeof end == typeof start); |
+ switch (typeof start) { |
+ case 'object': |
+ for (var index = 0; index < start.length; ++index) { |
+ array[index] = interp(start[index], end[index], value); |
+ } |
+ break; |
+ case 'number': |
+ array[index] = interp(start, end, value); |
+ break; |
+ default: |
+ debugger; |
+ } |
+ return array; |
+} |
+ |
+function AnimationAddCommon(timing, range, attr, inParams) { |
+ var animation = { |
+ timing: timing, |
+ range: range, |
+ attr: attr, |
+ inParams: inParams, |
+ duration: timing[1] - timing[0], |
+ remaining: timing[1] - timing[0], |
+ firstStep: true, |
+ } |
+ animationsPending.push(animation); |
+ return animation; |
+} |
+ |
+function AnimationAddSVG(timing, element, range, attr, inParams) { |
+ var animation = AnimationAddCommon(timing, range, attr, inParams); |
+ animation.element = element; |
+ return animation; |
+} |
+ |
+function AnimationAddCanvas(timing, element, range, attr, inParams) { |
+ var animation = AnimationAddCommon(timing, range, attr, inParams); |
+ animation.element = canvasData[element]; |
+ assert(animation.element); |
+ animation.firstElement = null; |
+ return animation; |
+} |
+ |
+function AnimationAdd(timing, e, range, attr, funct, inParams) { |
+ if (!range) { |
+ range = [0, 1]; |
+ } |
+ if (!attr) { |
+ attr = 'opacity'; |
+ } |
+ if (!funct) { |
+ funct = interpolate_at; |
+ } |
+ var element; |
+ switch (animationState.displayEngine) { |
+ case 'SVG': |
+ element = typeof e == 'string' ? document.getElementById(e) : e; |
+ break; |
+ case 'Canvas': |
+ element = typeof e == 'string' ? e : e.id; |
+ break; |
+ default: |
+ debugger; |
+ } |
+ assert(element); |
+ switch (attr) { |
+ case 'path': |
+ if (!inParams) { |
+ inParams = PathDataArray(element); |
+ } |
+ break; |
+ case 'opacity': |
+ if (!inParams) { |
+ inParams = [0, 1]; |
+ } |
+ break; |
+ default: |
+ debugger; |
+ } |
+ var funcBody = 'var outParams = ' + funct.name + '(value, inParams);\n'; |
+ switch (animationState.displayEngine) { |
+ case 'SVG': |
+ switch (attr) { |
+ case 'path': |
+ var verbArray = PathVerbArray(element); |
+ funcBody += 'return '; |
+ for (var index = 0; index < inParams.length; ++index) { |
+ funcBody += '"' + verbArray[index] + '"'; |
+ funcBody += 'outParams[' + index + '];\n'; |
+ } |
+ if (verbArray.length > inParams.length) { |
+ funcBody += '"' + verbArray[verbArray.length - 1] + '"'; |
+ } |
+ funcBody += ';\n'; |
+ var animation = AnimationAddSVG(timing, element, range, "d", inParams); |
+ animation.func = new Function('value', 'inParams', funcBody); |
+ break; |
+ case 'opacity': |
+ if (animation.element.getAttribute("stroke-opacity")) { |
+ animation = AnimationAddSVG(timing, element, range, "stroke-opacity", inParams); |
+ } |
+ if (animation.element.getAttribute("fill-opacity")) { |
+ animation = AnimationAddSVG(timing, element, range, "fill-opacity", inParams); |
+ } |
+ break; |
+ default: |
+ debugger; |
+ } |
+ case 'Canvas': |
+ switch (attr) { |
+ case 'path': |
+ var verbArray = PathVerbArray(element); |
+ for (var index = 0; index < inParams.length; ++index) { |
+ funcBody += verbArray[index]; |
+ funcBody += 'outParams[' + index + ']'; |
+ } |
+ if (verbArray.length > inParams.length) { |
+ funcBody += verbArray[verbArray.length - 1]; |
+ } |
+ animation = AnimationAddCanvas(timing, element, range, attr, inParams); |
+ funcBody += animation.element.style + animation.element.draw; |
+ animation.func = new Function('ctx', 'value', 'inParams', funcBody); |
+ break; |
+ case 'opacity': |
+ animation = AnimationAddCanvas(timing, element, range, attr, inParams); |
+ break; |
+ default: |
+ debugger; |
+ } |
+ break; |
+ default: |
+ debugger; |
+ } |
+ return animation; |
+} |
+ |
+function path_data_common(element, getValues) { |
+ var numRegEx = /-?\d+\.?\d*(?:e-?\d+)?/g; |
+ var data = []; |
+ var match; |
+ var path; |
+ switch (animationState.displayEngine) { |
+ case 'SVG': path = element.getAttribute("d"); break; |
+ case 'Canvas': path = paths[element].funcBody; break; |
+ default: debugger; |
+ } |
+ if (getValues) { |
+ while ((match = numRegEx.exec(path))) { |
+ data.push(Number(match[0])); |
+ } |
+ } else { |
+ var sIndex = 0; |
+ while ((match = numRegEx.exec(path))) { |
+ if (sIndex < match.index) { |
+ data.push(path.substring(sIndex, match.index)); |
+ } |
+ sIndex = match.index + match[0].length; |
+ } |
+ if (sIndex < path.length) { |
+ data.push(path.substring(sIndex, path.length)); |
+ } |
+ } |
+ return data; |
+} |
+ |
+function PathDataArray(element) { |
+ return path_data_common(element, true); |
+} |
+ |
+function PathVerbArray(element) { |
+ return path_data_common(element, false); |
+} |
+ |
+function PathSet(element, funct, value, params) { |
+ var pathVerbs = PathVerbArray(element); |
+ if (funct) { |
+ params = funct(value, params); |
+ } |
+ var setValue = ''; |
+ for (var index = 0; index < params.length; ++index) { |
+ setValue += pathVerbs[index]; |
+ setValue += params[index]; |
+ } |
+ if (pathVerbs.length > params.length) { |
+ setValue += pathVerbs[pathVerbs.length - 1]; |
+ } |
+ switch (animationState.displayEngine) { |
+ case 'SVG': |
+ element.setAttribute('d', setValue); |
+ break; |
+ case 'Canvas': |
+ element.func = new Function('ctx', setValue + element.style + element.draw); |
+ break; |
+ default: |
+ debugger; |
+ } |
+} |
+ |
+function RemoveFromArray(array, element) { |
+ for (var index in array) { |
+ var record = array[index]; |
+ if (record.element == element) { |
+ array.splice(index, 1); |
+ break; |
+ } |
+ } |
+} |
+ |
+function EndAnimationCanvas(animation, visibleFinished) { |
+ var changeAlpha = "opacity" == animation.attr; |
+ if (!changeAlpha || animation.range[1] > 0) { |
+ if (changeAlpha) { |
+ ctx.save(); |
+ ctx.globalAlpha = animation.range[1]; |
+ } |
+ if (animation.func) { |
+ animation.func(ctx, animation.range[animation.range.length - 1], animation.inParams); |
+ } else { |
+ animation.element.func(ctx); |
+ } |
+ if (changeAlpha) { |
+ ctx.restore(); |
+ } |
+// if (visibleFinished) { |
+// visibleFinished.push(animation); |
+// } |
+ } else { |
+ // if (visibleFinished) { |
+ // RemoveFromArray(visibleFinished, animation.element); |
+ // } |
+ } |
+} |
+ |
+/* start here |
+canvas: |
+ |
+display list : |
+ for each element (canvas) |
+ save |
+ set global alpha (override) |
+ create geometry (override) |
+ create style (override) |
+ draw |
+ restore |
+ |
+maybe each action should have an override slot |
+animations write to the slot |
+each element in display list then iterates overrides once the animations complete the frame |
+ |
+so, first -- |
+ active animations update the display list |
+ |
+next -- |
+ active animations install themselves in override slots |
+ |
+finally |
+ display list is iterated, calling override slots |
+ |
+---------------- |
+ |
+svg: |
+ display list is implicit |
+ |
+ active animations write element attributes |
+ */ |
+ |
+function EndAnimationSVG(animation, visibleFinished) { |
+ switch (animation.attr) { |
+ case "opacity": |
+ animation.element.setAttribute(animation.attribute, animation.range[1]); |
+ if (animation.range[1] > 0) { |
+ visibleFinished.push(animation); |
+ } else { |
+ RemoveFromArray(visibleFinished, animation.element); |
+ } |
+ break; |
+ case "path": |
+ var attrStr = animation.func(animation.range[1], animation.inParams); |
+ animation.element.setAttribute(animation.attribute, attrStr); |
+ break; |
+ default: |
+ debugger; |
+ } |
+} |
+ |
+function StepAnimationCanvas(animation, value) { |
+ var endValue = animation.range[animation.range.length - 1]; |
+ var interp = animation.range[0] + (endValue - animation.range[0]) * (1 - value); |
+ if (animation.firstStep) { |
+ RemoveFromArray(visibleFinished, animation.element); |
+ animation.firstStep = false; |
+ } |
+ var changeAlpha = "opacity" == animation.attr; |
+ if (changeAlpha) { |
+ ctx.save(); |
+ ctx.globalAlpha = interp; |
+ } |
+ if (animation.func) { |
+ animation.func(ctx, interp, animation.inParams); |
+ } else { |
+ animation.element.func(ctx); |
+ } |
+ if (changeAlpha) { |
+ ctx.restore(); |
+ } |
+} |
+ |
+function StepAnimationSVG(animation, value) { |
+ var interp = animation.range[0] + (animation.range[1] - animation.range[0]) * (1 - value); |
+ switch (animation.attr) { |
+ case "opacity": |
+ animation.element.setAttribute(animation.attribute, interp); |
+ break; |
+ case "path": |
+ var attrStr = animation.func(interp, animation.inParams); |
+ animation.element.setAttribute(animation.attribute, attrStr); |
+ break; |
+ default: |
+ debugger; |
+ } |
+} |
+ |
+var animate_frame = 0; |
+ |
+function AnimateList(now) { |
+ ++animate_frame; |
+ if (animationState.paused) { |
+ return; |
+ } |
+ if (animationState.start == null) { |
+ animationState.start = now - animationState.time; |
+ } |
+ animationState.time = now - animationState.start; |
+ var stillPending = []; |
+ for (var index in animationsPending) { |
+ var animation = animationsPending[index]; |
+ var interval = animationState.time - animation.timing[0]; |
+ if (interval <= 0) { |
+ stillPending.push(animation); |
+ continue; |
+ } |
+ animationsActive.push(animation); |
+ var inList = false; |
+ for (var dlIndex in displayList) { |
+ var displayable = displayList[dlIndex]; |
+ if (displayable == animation.element) { |
+ inList = true; |
+ break; |
+ } |
+ } |
+ if (!inList) { |
+ displayList.push(animation.element); |
+ } |
+ } |
+ animationsPending = stillPending; |
+ var stillAnimating = []; |
+ if ('Canvas' == animationState.displayEngine) { |
+ ctx.clearRect(0, 0, canvas.width, canvas.height); |
+// for (var index in visibleFinished) { |
+// var animation = visibleFinished[index]; |
+// animation.endAnimation = false; |
+// } |
+ } |
+ for (var index in animationsActive) { |
+ var animation = animationsActive[index]; |
+ var interval = animationState.time - animation.timing[0]; |
+ animation.remaining = animation.duration > interval ? animation.duration - interval : 0; |
+ animation.endAnimation = animation.remaining <= 0; |
+ if (animation.endAnimation) { |
+ switch (animationState.displayEngine) { |
+ case 'SVG': EndAnimationSVG(animation, visibleFinished); break; |
+ case 'Canvas': EndAnimationCanvas(animation, visibleFinished); break; |
+ default: debugger; |
+ } |
+ continue; |
+ } |
+ var value = animation.remaining / animation.duration; |
+ switch (animationState.displayEngine) { |
+ case 'SVG': StepAnimationSVG(animation, value); break; |
+ case 'Canvas': |
+ if (!animation.firstElement || !animation.firstElement.endAnimation) { |
+ StepAnimationCanvas(animation, value); |
+ } |
+ break; |
+ default: debugger; |
+ } |
+ stillAnimating.push(animation); |
+ } |
+ if ('Canvas' == animationState.displayEngine) { |
+ for (var index in visibleFinished) { |
+ var animation = visibleFinished[index]; |
+ if (!animation.endAnimation) { |
+ EndAnimationCanvas(animation, null); |
+ } |
+ } |
+ } |
+ animationsActive = stillAnimating; |
+ if (animationsPending.length || animationsActive.length) { |
+ animationState.requestID = requestAnimationFrame(AnimateList); |
+ } |
+} |
+ |
+function CancelAnimate(now) { |
+ if (animationState.start == null) { |
+ animationState.start = now; |
+ } |
+ var time = now - animationState.start; |
+ var stillAnimating = []; |
+ for (var index in animationsActive) { |
+ var animation = animationsActive[index]; |
+ var remaining = animation.remaining - time; |
+ var value = remaining / animation.duration; |
+ switch (animationState.displayEngine) { |
+ case 'SVG': animation.element.setAttribute(animation.attribute, value); break; |
+ case 'Canvas': break; |
+ } |
+ if (remaining <= 0) { |
+ continue; |
+ } |
+ stillAnimating.push(animation); |
+ } |
+ animationsActive = stillAnimating; |
+ if (animationsActive.length) { |
+ animationState.requestID = requestAnimationFrame(CancelAnimate); |
+ return; |
+ } |
+ animationsPending = []; |
+ animationState.reset(); |
+ if (keyFrameQueue.length > 0) { |
+ var animationFunc = keyFrameQueue.pop(); |
+ animationFunc(); |
+ } |
+} |
+ |
+function CancelAnimation() { |
+ cancelAnimationFrame(animationState.requestID); |
+ for (var index in animationsActive) { |
+ var animation = animationsActive[index]; |
+ switch (animation.attr) { |
+ case "opacity": |
+ var tmp = animation.range[0]; animation.range[0] = animation.range[1]; animation[1] = tmp; |
+ animation.remaining = animation.duration - animation.remaining; |
+ animation.remaining /= animation.duration / 1000; |
+ animation.duration = 1000; |
+ break; |
+ case "fadeOut": |
+ RemoveFromArray(visibleFinished, animation.element); |
+ break; |
+ case "path": |
+ break; |
+ default: |
+ debugger; |
+ |
+ } |
+ } |
+ for (var index in visibleFinished) { |
+ var animation = visibleFinished[index]; |
+ animation.action = "fadeOut"; |
+ animation.remaining = animation.duration = 1000; |
+ animationsActive.push(animation); |
+ } |
+ visibleFinished = []; |
+ animationState.reset(); |
+ animationState.requestID = requestAnimationFrame(CancelAnimate); |
+} |
+ |
+function PauseAnimation() { |
+ animationState.paused = true; |
+} |
+ |
+function QueueAnimation(animationFunc) { |
+ if (null == animationState.requestID) { |
+ animationFunc(); |
+ return; |
+ } |
+ keyFrameQueue.push(animationFunc); |
+} |
+ |
+function UnpauseAnimation() { |
+ animationState.paused = false; |
+ animationState.start = performance.now() - animationState.time; |
+ animationState.requestID = requestAnimationFrame(AnimateList); |
+} |
+ |
+function SetupTextSVG(t, x, y) { |
+ var text; |
+ if (typeof t == "string") { |
+ text = document.getElementById(t); |
+ } else { |
+ text = t; |
+ } |
+ text.setAttribute("font-family", "Helvetica,Arial"); |
+ text.setAttribute("font-size", "1.3rem"); |
+ if (typeof x == 'number') { |
+ text.setAttribute("x", x); |
+ } else if (null == text.getAttribute("x")) { |
+ text.setAttribute("x", 400); |
+ } |
+ if (typeof y == 'number') { |
+ text.setAttribute("y", y); |
+ } else if (null == text.getAttribute("y")) { |
+ text.setAttribute("y", 200); |
+ } |
+} |
+ |
+function SetupTextCanvas(t, x, y) { |
+ var text = typeof t == 'string' ? t : t.id; |
+ var record = canvasData[text]; |
+ if (typeof x == 'number') { |
+ record.x = x; |
+ } |
+ if (typeof y == 'number') { |
+ record.y = y; |
+ } |
+ record.position = canvas_xy(record); |
+ record.func = new Function('ctx', record.style + record.draw + record.position); |
+} |
+ |
+function SetupText(t, x, y) { |
+ switch (animationState.displayEngine) { |
+ case 'SVG': |
+ SetupTextSVG(t, x, y); |
+ break; |
+ case 'Canvas': |
+ SetupTextCanvas(t, x, y); |
+ break; |
+ default: |
+ debugger; |
+ } |
+} |
+ |
+function FirstText(text) { |
+ SetupText(text); |
+ AnimationAdd([0, 1000], text); |
+} |
+ |
+ |
+function EngineInit(keyframe) { |
+ displayList = []; |
+ switch (animationState.displayEngine) { |
+ case 'SVG': break; |
+ case 'Canvas': CanvasInit(keyframe); break; |
+ default: debugger; |
+ } |
+} |
+ |
+function EngineStart() { |
+ switch (animationState.displayEngine) { |
+ case 'SVG': break; |
+ case 'Canvas': |
+ // associate fadeIn and fadeOut |
+ for (var outerIndex in animationsPending) { |
+ var outer = animationsPending[outerIndex]; |
+ for (var innerIndex in animationsPending) { |
+ if (outerIndex == innerIndex) { |
+ continue; |
+ } |
+ var inner = animationsPending[innerIndex]; |
+ if (inner.element == outer.element) { |
+ inner.firstElement = outer; |
+ continue; |
+ } |
+ } |
+ } |
+ break; |
+ default: debugger; |
+ } |
+ animationState.reset(); |
+ animationState.requestID = requestAnimationFrame(AnimateList); |
+} |
+ |
+function AnimateSpanWedge() { |
+ EngineInit('keyframe1'); |
+ FirstText(spanWedgeDesc); |
+ AnimationAdd([1000, 2000], span1); |
+ AnimationAdd([1500, 3000], wedge1); |
+ AnimationAdd([3500, 4000], span1, [1, 0]); |
+ AnimationAdd([3500, 4000], wedge1, [1, 0]); |
+ AnimationAdd([4000, 5000], span2); |
+ AnimationAdd([4500, 6000], wedge2); |
+ AnimationAdd([6500, 7000], span2, [1, 0]); |
+ AnimationAdd([6500, 7000], wedge2, [1, 0]); |
+ AnimationAdd([7000, 8000], span3); |
+ AnimationAdd([7500, 9000], wedge3); |
+ EngineStart(); |
+} |
+ |
+function AnimateTrivialWedge() { |
+ EngineInit('keyframe2'); |
+ FirstText(trivialWedgeDesc1); |
+ FirstText(trivialWedgeDesc2); |
+ AnimationAdd([2000, 3500], span4); |
+ AnimationAdd([2000, 3500], wedge4); |
+ AnimationAdd([2000, 3500], span5); |
+ AnimationAdd([2000, 3500], wedge5); |
+ AnimationAdd([2000, 3500], span6); |
+ AnimationAdd([2000, 3500], wedge6); |
+ EngineStart(); |
+} |
+ |
+function AnimateSectorDesc() { |
+ EngineInit('keyframe3'); |
+ FirstText(sectorDesc1); |
+ FirstText(sectorDesc2); |
+ AnimationAdd([ 0, 1000], xaxis); |
+ AnimationAdd([ 500, 1500], yaxis); |
+ AnimationAdd([2000, 3500], sectorDescXYA); |
+ AnimationAdd([2000, 3500], wedgeXY8); |
+ AnimationAdd([3000, 4500], sectorDescXYB); |
+ AnimationAdd([3000, 4500], wedgeXY6); |
+ AnimationAdd([4000, 5500], sectorDescXYC); |
+ AnimationAdd([4000, 5500], wedgeXY3); |
+ EngineStart(); |
+} |
+ |
+function AnimateLineSingle() { |
+ EngineInit('keyframe4'); |
+ FirstText(lineSingleDesc); |
+ for (var i = 1; i <= 8; ++i) { |
+ SetupText("sectorDescXY" + i, 500, 260); |
+ } |
+ AnimationAdd([ 0, 1000], xaxis); |
+ AnimationAdd([ 0, 1000], yaxis); |
+ AnimationAdd([1000, 2000], lineSegment); |
+ AnimationAdd([1000, 3000], lineSegment, [-22.5 * Math.PI / 180], "path", evaluate_at, |
+ [ circle.center.x, circle.center.y, |
+ circle.center.x + " + " + circle.radius + " * Math.cos(value)", |
+ circle.center.y + " + " + circle.radius + " * Math.sin(value)", |
+ ]); |
+ AnimationAdd([2000, 3000], sectorDescXY1); |
+ AnimationAdd([2000, 3000], wedgeXY1); |
+ AnimationAdd([3000, 7000], lineSegment, [-22.5 * Math.PI / 180, (-22.5 - 360) * Math.PI / 180], |
+ "path", evaluate_at, |
+ [ circle.center.x, circle.center.y, |
+ circle.center.x + " + " + circle.radius + " * Math.cos(value)", |
+ circle.center.y + " + " + circle.radius + " * Math.sin(value)", |
+ ]); |
+ for (var i = 1; i < 8; ++i) { |
+ AnimationAdd([2500 + 500 * i, 3000 + 500 * i], "sectorDescXY" + (i + 1)); |
+ AnimationAdd([2500 + 500 * i, 3000 + 500 * i], "wedgeXY" + (i + 1)); |
+ AnimationAdd([2500 + 500 * i, 3000 + 500 * i], "sectorDescXY" + i, [1, 0]); |
+ AnimationAdd([2500 + 500 * i, 3000 + 500 * i], "wedgeXY" + i, [1, 0]); |
+ } |
+ AnimationAdd([2500 + 500 * 8, 3000 + 500 * 8], sectorDescXY1); |
+ AnimationAdd([2500 + 500 * 8, 3000 + 500 * 8], wedgeXY1); |
+ AnimationAdd([2500 + 500 * 8, 3000 + 500 * 8], sectorDescXY8, [1, 0]); |
+ AnimationAdd([2500 + 500 * 8, 3000 + 500 * 8], wedgeXY8, [1, 0]); |
+ EngineStart(); |
+} |
+ |
+function AnimateCurveMultiple() { |
+ EngineInit('keyframe5'); |
+ var cubicStart = PathDataArray(curveSegment1); |
+ var cubicMid = PathDataArray(curveSegment2); |
+ var cubicEnd = PathDataArray(curveSegment3); |
+ FirstText(curveMultipleDesc1); |
+ FirstText(curveMultipleDesc2); |
+ for (var i = 1; i <= 6; ++i) { |
+ SetupText("sectorDescXY" + i, 500, 260 + i * 25); |
+ } |
+ AnimationAdd([ 0, 1000], xaxis); |
+ AnimationAdd([ 0, 1000], yaxis); |
+ AnimationAdd([1000, 2000], curveSegment); |
+ AnimationAdd([2000, 3000], sectorDescXY1); |
+ AnimationAdd([2000, 3000], wedgeXY1); |
+ AnimationAdd([3000, 4000], curveSegment, [0, 1], "path", interpolate_at, [cubicStart, cubicMid]); |
+ AnimationAdd([4000, 5000], sectorDescXY2); |
+ AnimationAdd([4000, 5000], wedgeXY2); |
+ AnimationAdd([5000, 6000], curveSegment, [0, 1], "path", interpolate_at, [cubicMid, cubicEnd]); |
+ AnimationAdd([6000, 7000], sectorDescXY3); |
+ AnimationAdd([6000, 7000], wedgeXY3); |
+ AnimationAdd([6000, 7000], sectorDescXY4); |
+ AnimationAdd([6000, 7000], wedgeXY4); |
+ AnimationAdd([6000, 7000], sectorDescXY5); |
+ AnimationAdd([6000, 7000], wedgeXY5); |
+ AnimationAdd([6000, 7000], sectorDescXY6); |
+ AnimationAdd([6000, 7000], wedgeXY6); |
+ EngineStart(); |
+} |
+ |
+function AnimateOneDLines() { |
+ EngineInit('keyframe6'); |
+ FirstText(line1DDest1); |
+ FirstText(line1DDest2); |
+ for (var i = 9; i <= 11; ++i) { |
+ SetupText("sectorDescXY" + i, 500, 260 + (i - 8) * 25); |
+ } |
+ AnimationAdd([ 0, 1000], xaxis); |
+ AnimationAdd([ 0, 1000], yaxis); |
+ AnimationAdd([2000, 3000], sectorDescXY9); |
+ AnimationAdd([2000, 3000], horzSegment); |
+ AnimationAdd([3000, 4000], sectorDescXY10); |
+ AnimationAdd([3000, 4000], vertSegment); |
+ AnimationAdd([4000, 5000], sectorDescXY11); |
+ AnimationAdd([4000, 5000], diagSegment); |
+ EngineStart(); |
+} |
+ |
+function AnimateDiverging() { |
+ EngineInit('keyframe7'); |
+ var cubicData = PathDataArray(cubicSegment2); |
+ FirstText(curve1dDesc1); |
+ FirstText(curve1dDesc2); |
+ SetupText("sectorDescXY9", 500, 285); |
+ SetupText("sectorDescXY1", 500, 320); |
+ AnimationAdd([ 0, 1000], xaxis); |
+ AnimationAdd([ 0, 1000], yaxis); |
+ AnimationAdd([1900, 1900], cubicSegment); |
+ AnimationAdd([2000, 3000], cubicSegment, [0, 1], "path", cubic_partial, cubicData); |
+ AnimationAdd([2000, 3000], sectorDescXY9); |
+ AnimationAdd([2000, 3000], horzSegment); |
+ AnimationAdd([3000, 4000], sectorDescXY1); |
+ AnimationAdd([3000, 4000], wedgeXY1); |
+ EngineStart(); |
+} |
+ |
+circle.animate = AnimateCircle; |
+circle.start = null; |
+ |
+function AngleToPt(center, radius, degrees) { |
+ var radians = degrees * Math.PI / 180.0; |
+ return { |
+ x: center.x + (radius * Math.cos(radians)), |
+ y: center.y - (radius * Math.sin(radians)) |
+ }; |
+} |
+ |
+function PtsToSweep(pt1, pt2, center) { // unused |
+ return { |
+ start: 180 / Math.PI * Math.atan2(pt1.y - center.y, pt1.x - center.x), |
+ end: 180 / Math.PI * Math.atan2(pt2.y - center.y, pt2.x - center.x) |
+ }; |
+} |
+ |
+ |
+function ArcStr(center, radius, startAngle, endAngle) { |
+ var endPt = AngleToPt(center, radius, endAngle); |
+ var arcSweep = endAngle - startAngle <= 180 ? "0" : "1"; |
+ return ["A", radius, radius, 0, arcSweep, 0, endPt.x, endPt.y].join(" "); |
+} |
+ |
+function ArcStart(center, radius, startAngle, endAngle) { |
+ var startPt = AngleToPt(center, radius, startAngle); |
+ return [ startPt.x, startPt.y, ArcStr(center, radius, startAngle, endAngle) ].join(" "); |
+} |
+ |
+function MakeArc(arcStart) { |
+ return "M" + arcStart; |
+} |
+ |
+function MakeWedge(center, arcStart) { |
+ return ["M", center.x, center.y, "L", arcStart, "z"].join(" "); |
+} |
+ |
+function Animate(path, now, dur) { |
+ if (path.start == null) { |
+ path.start = now; |
+// console.log("start=" + now); |
+ } |
+ if (now - path.start < dur) { |
+ requestAnimationFrame(path.animate); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+function AnimateCircle(now) { |
+ if (circle.start == null) { |
+ circleFill.setAttribute("fill-opacity", "0.3"); |
+ } |
+ var dur = 2 * 1000; |
+ var animating = Animate(circle, now, dur); |
+// console.log("now=" + now + "circle.start=" + circle.start ) |
+ var pathStr = ArcStart(circle.center, circle.radius, 0, (now - circle.start) / (dur / 359.9)); |
+ |
+ circle.setAttribute("d", MakeArc(pathStr)); |
+ circleFill.setAttribute("d", MakeWedge(circle.center, pathStr)); |
+ if (!animating) { |
+ var delay = dur - (now - circle.start); |
+ setTimeout(CircleFinal, delay); |
+ } |
+} |
+ |
+function CircleFinal() { |
+ var firstHalf = ArcStart(circle.center, circle.radius, 0, 180); |
+ var secondHalf = ArcStr(circle.center, circle.radius, 180, 360); |
+ circle.setAttribute("d", "M" + firstHalf + secondHalf + "z"); |
+ circleFill.setAttribute("d", "M" + firstHalf + secondHalf + "z"); |
+} |
+ |
+var svgNS = "http://www.w3.org/2000/svg"; |
+ |
+function CreateTextLabels() |
+{ |
+ for (var i = 0; i < 32; ++i) { |
+ var text = document.createElementNS(svgNS, "text"); |
+ var pt = AngleToPt(circle.center, circle.radius + 80, i * 360 / 32); |
+ text.setAttribute("id", "t" + i); |
+ text.setAttribute("x", pt.x); |
+ text.setAttribute("y", pt.y); |
+ text.setAttribute("text-anchor", "middle"); |
+ text.setAttribute("alignment-baseline", "mathematical"); |
+ var textNode = document.createTextNode(i); |
+ text.appendChild(textNode); |
+ document.getElementById("svg").appendChild(text); |
+ } |
+} |
+ |
+// CreateTextLabels(); |
+ |
+var keyframeArray = [ |
+ AnimateSpanWedge, |
+ AnimateTrivialWedge, |
+ AnimateSectorDesc, |
+ AnimateLineSingle, |
+ AnimateCurveMultiple, |
+ AnimateOneDLines, |
+ AnimateDiverging, |
+]; |
+ |
+var keyframeIndex = 3; // keyframeArray.length - 1; // normally 0 ; set to debug a particular frame |
+ |
+function QueueKeyframe() { |
+ QueueAnimation(keyframeArray[keyframeIndex]); |
+ if (keyframeIndex < keyframeArray.length - 1) { |
+ ++keyframeIndex; |
+ } |
+} |
+ |
+var grads; |
+var paths; |
+var canvas; |
+var ctx; |
+ |
+function canvasSetup() { |
+ canvas = document.getElementById("canvas"); |
+ ctx = canvas ? canvas.getContext("2d") : null; |
+ assert(ctx); |
+ var resScale = animationState.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); |
+ } |
+ |
+ grads = CanvasGrads(ctx); |
+ paths = CanvasPaths(ctx); |
+} |
+ |
+function Onload() { |
+ canvasSetup(); |
+ var startBtn = document.getElementById('startBtn'); |
+ var stopBtn = document.getElementById('stopBtn'); |
+ var resetBtn = document.getElementById('resetBtn'); |
+ |
+ startBtn.addEventListener('click', function(e) { |
+ e.preventDefault(); |
+ e.srcElement.innerText = "Next"; |
+ CancelAnimation(); |
+ QueueKeyframe(); |
+ }); |
+ |
+ stopBtn.addEventListener('click', function(e) { |
+ e.preventDefault(); |
+ |
+ if (!animationState.paused) { |
+ PauseAnimation(); |
+ e.srcElement.innerText = "Resume"; |
+ } else { |
+ UnpauseAnimation(); |
+ e.srcElement.innerText = "Pause"; |
+ } |
+ }); |
+ |
+ resetBtn.addEventListener('click', function(e) { |
+ e.preventDefault(); |
+ CancelAnimation(); |
+ keyframeIndex = 0; |
+ startBtn.innerText = "Start"; |
+ QueueKeyframe(); |
+ }); |
+} |
+ |
+</script> |
+ |
+</head> |
+ |
+<body onLoad="Onload()"> |
+ |
+<div class="controls"> |
+ <button type="button" id="startBtn">Start</button> |
+ <button type="button" id="stopBtn">Pause</button> |
+ <button type="button" id="resetBtn">Restart</button> |
+</div> |
+ |
+<canvas id="canvas" width="800" height="500" /> |
+ |
+</body> |
+</html> |