OLD | NEW |
(Empty) | |
| 1 <!DOCTYPE html> |
| 2 <html lang="en"> |
| 3 <head> |
| 4 |
| 5 |
| 6 <style> |
| 7 html { |
| 8 font-family: Helvetica, Arial, sans-serif; |
| 9 font-size: 100%; |
| 10 } |
| 11 |
| 12 .controls { |
| 13 margin: 1em 0; |
| 14 } |
| 15 |
| 16 button { |
| 17 display: inline-block; |
| 18 border-radius: 3px; |
| 19 border: none; |
| 20 font-size: 0.9rem; |
| 21 padding: 0.4rem 0.8em; |
| 22 background: #69c773; |
| 23 border-bottom: 1px solid #498b50; |
| 24 color: white; |
| 25 -webkit-font-smoothing: antialiased; |
| 26 font-weight: bold; |
| 27 margin: 0 0.25rem; |
| 28 text-align: center; |
| 29 } |
| 30 |
| 31 button:hover, button:focus { |
| 32 opacity: 0.75; |
| 33 cursor: pointer; |
| 34 } |
| 35 |
| 36 button:active { |
| 37 opacity: 1; |
| 38 box-shadow: 0 -3px 10px rgba(0, 0, 0, 0.1) inset; |
| 39 } |
| 40 |
| 41 </style> |
| 42 |
| 43 <! set height back to 500 /> |
| 44 <svg id="svg" width="800" height="500" |
| 45 xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink
"> |
| 46 |
| 47 <defs> |
| 48 <radialGradient id="grad1" cx="200" cy="200" r="300" gradientUnits="userSpac
eOnUse"> |
| 49 <stop offset="0%" style="stop-color:rgb(0,0,255); stop-opacity:0.3" /> |
| 50 <stop offset="100%" style="stop-color:rgb(0,0,255); stop-opacity:0" /> |
| 51 </radialGradient> |
| 52 <radialGradient id="grad2" cx="200" cy="200" r="300" gradientUnits="userSpac
eOnUse"> |
| 53 <stop offset="0%" style="stop-color:rgb(0,255,0); stop-opacity:0.3" /> |
| 54 <stop offset="100%" style="stop-color:rgb(0,255,0); stop-opacity:0" /> |
| 55 </radialGradient> |
| 56 <radialGradient id="grad3" cx="200" cy="200" r="300" gradientUnits="userSpac
eOnUse"> |
| 57 <stop offset="0%" style="stop-color:rgb(255,0,0); stop-opacity:0.3" /> |
| 58 <stop offset="100%" style="stop-color:rgb(255,0,0); stop-opacity:0" /> |
| 59 </radialGradient> |
| 60 <radialGradient id="grad4" cx="200" cy="200" r="300" gradientUnits="userSpac
eOnUse"> |
| 61 <stop offset="0%" style="stop-color:rgb(192,63,192); stop-opacity:0.3" /
> |
| 62 <stop offset="100%" style="stop-color:rgb(192,63,192); stop-opacity:0" /> |
| 63 </radialGradient> |
| 64 <radialGradient id="grad5" cx="200" cy="200" r="300" gradientUnits="userSpac
eOnUse"> |
| 65 <stop offset="0%" style="stop-color:rgb(127,127,0); stop-opacity:0.3" /> |
| 66 <stop offset="100%" style="stop-color:rgb(127,127,0); stop-opacity:0" /> |
| 67 </radialGradient> |
| 68 <radialGradient id="grad6" cx="200" cy="200" r="300" gradientUnits="userSpac
eOnUse"> |
| 69 <stop offset="0%" style="stop-color:rgb(127,0,127); stop-opacity:0.3" /> |
| 70 <stop offset="100%" style="stop-color:rgb(127,0,127); stop-opacity:0" /> |
| 71 </radialGradient> |
| 72 <radialGradient id="grad7" cx="200" cy="200" r="300" gradientUnits="userSpac
eOnUse"> |
| 73 <stop offset="0%" style="stop-color:rgb(0,127,127); stop-opacity:0.3" /> |
| 74 <stop offset="100%" style="stop-color:rgb(0,127,127); stop-opacity:0" /> |
| 75 </radialGradient> |
| 76 <radialGradient id="grad8" cx="200" cy="200" r="300" gradientUnits="userSpac
eOnUse"> |
| 77 <stop offset="0%" style="stop-color:rgb(63,192,63); stop-opacity:0.3" /> |
| 78 <stop offset="100%" style="stop-color:rgb(63,192,63); stop-opacity:0" /> |
| 79 </radialGradient> |
| 80 </defs> |
| 81 |
| 82 <path id="circleFill" d="M300,200 A 100,100 0,0,0 300,200" fill="#777" fill-opac
ity="0" /> |
| 83 <path id="circle" d="M300,200 A 100,100 0,0,0 300,200" fill="none" stroke="black
" /> |
| 84 |
| 85 <! elements for keyframe 1 /> |
| 86 <text id="spanWedgeDesc" fill-opacity="0" > |
| 87 All spans are contained by a wedge. |
| 88 </text> |
| 89 <path id="span1" d="M200,200 Q300,300 200,300" fill="none" stroke="black" stroke
-opacity="0"/> |
| 90 <path id="span2" d="M200,200 C100,300 100,400 200,300" fill="none" stroke="black
" stroke-opacity="0"/> |
| 91 <path id="span3" d="M200,200 C300,100 100,400 300,200" fill="none" stroke="black
" stroke-opacity="0"/> |
| 92 <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"/> |
| 93 <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"/> |
| 94 <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"/> |
| 95 |
| 96 <! keyframe 2 /> |
| 97 <text id="trivialWedgeDesc1" fill-opacity="0" > |
| 98 Wedges that don't overlap can be |
| 99 </text> |
| 100 <text id="trivialWedgeDesc2" y="240" fill-opacity="0" > |
| 101 easily sorted. |
| 102 </text> |
| 103 <path id="span4" d="M200,200 Q300,300 400,300" fill="none" stroke="black" stroke
-opacity="0"/> |
| 104 <path id="span5" d="M200,200 Q280,320 200,400" fill="none" stroke="black" stroke
-opacity="0"/> |
| 105 <path id="span6" d="M200,200 Q60,340 100,400" fill="none" stroke="black" stroke-
opacity="0"/> |
| 106 <path id="wedge4" d="M200,200 L500,500 A 424.26,424.26 0,0,1 579.47,389.74 z" fi
ll="url(#grad1)" fill-opacity="0"/> |
| 107 <path id="wedge5" d="M200,200 L389.74,579.47 A 424.26,424.26 0,0,1 200,500 z" fi
ll="url(#grad2)" fill-opacity="0"/> |
| 108 <path id="wedge6" d="M200,200 L10.26,579.47 A 424.26,424.26 0,0,1 -100,500 z" fi
ll="url(#grad3)" fill-opacity="0"/> |
| 109 |
| 110 |
| 111 <! keyframe 3 /> |
| 112 <text id="sectorDesc1" fill-opacity="0" > |
| 113 A sector is a wedge of a circle |
| 114 </text> |
| 115 <text id="sectorDesc2" y="240" fill-opacity="0" > |
| 116 containing a range of points. |
| 117 </text> |
| 118 <g id="xaxis" stroke-opacity="0" fill-opacity="0"> |
| 119 <path d="M100,200 L300,200" fill="none" stroke="rgb(191,191,191)"/> |
| 120 <text x="100" y="220" fill="rgb(191,191,191)">-X</text> |
| 121 <text x="300" y="220" text-anchor="end" fill="rgb(191,191,191)">+X</text> |
| 122 </g> |
| 123 <g id="yaxis" stroke-opacity="0" fill-opacity="0"> |
| 124 <path d="M200,100 L200,300" fill="none" stroke="rgb(191,191,191)"/> |
| 125 <text x="205" y="100" alignment-baseline="hanging" fill="rgb(191,191,191)">-
Y</text> |
| 126 <text x="205" y="300" fill="rgb(191,191,191)">+Y</text> |
| 127 </g> |
| 128 <text id="sectorDescXYA" x="500" y="310" fill="rgb(0,0,255)" fill-opacity="0"> |
| 129 X > 0> Y > 0 Y < X</text> |
| 130 <text id="sectorDescXYB" x="500" y="360" fill="rgb(0,127,0)" fill-opacity="0"> |
| 131 X < 0 Y > 0 -Y < X</text> |
| 132 <text id="sectorDescXYC" x="500" y="410" fill="rgb(255,0,0)" fill-opacity="0"> |
| 133 X < 0 Y < 0 Y < X</text> |
| 134 <path id="wedgeXY8" d="M200,200 L500,500 A 424.26,424.26 0,0,1 624.26,200 z" fil
l="url(#grad1)" fill-opacity="0"/> |
| 135 <path id="wedgeXY6" d="M200,200 L-100,500 A 424.26,424.26 0,0,1 200,624.26 z" fi
ll="url(#grad2)" fill-opacity="0"/> |
| 136 <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"/> |
| 137 |
| 138 <! keyframe 4 /> |
| 139 <text id="lineSingleDesc" fill-opacity="0" > |
| 140 Line spans are contained by a single sector. |
| 141 </text> |
| 142 <text id="sectorDescXY1" x="500" y="460" fill="rgb(192,63,192)" fill-opacity="0"
> |
| 143 X > 0 Y < 0 -Y < X</text> |
| 144 <text id="sectorDescXY2" x="500" y="460" fill="rgb(127,127,0)" fill-opacity="0"> |
| 145 X > 0 Y < 0 -Y > X</text> |
| 146 <text id="sectorDescXY3" x="500" y="460" fill="rgb(255,0,0)" fill-opacity="0"> |
| 147 X < 0 Y < 0 Y < X</text> |
| 148 <text id="sectorDescXY4" x="500" y="460" fill="rgb(127,0,127)" fill-opacity="0"> |
| 149 X < 0 Y < 0 Y > X</text> |
| 150 <text id="sectorDescXY5" x="500" y="460" fill="rgb(0,127,127)" fill-opacity="0"> |
| 151 X < 0 Y > 0 -Y < X</text> |
| 152 <text id="sectorDescXY6" x="500" y="460" fill="rgb(0,127,0)" fill-opacity="0"> |
| 153 X < 0 Y > 0 -Y < X</text> |
| 154 <text id="sectorDescXY7" x="500" y="460" fill="rgb(63,192,63)" fill-opacity="0"> |
| 155 X > 0 Y > 0 Y > X</text> |
| 156 <text id="sectorDescXY8" x="500" y="460" fill="rgb(0,0,255)" fill-opacity="0"> |
| 157 X > 0 Y > 0 Y < X</text> |
| 158 <path id="wedgeXY1" d="M200,200 L500,-100 A 424.26,424.26 0,0,1 624.26,200 z" fi
ll="url(#grad4)" fill-opacity="0"/> |
| 159 <path id="wedgeXY2" d="M200,200 L200,-175.74 A 424.26,424.26 0,0,1 500,-100 z" f
ill="url(#grad5)" fill-opacity="0"/> |
| 160 <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"/> |
| 161 <path id="wedgeXY5" d="M200,200 L-100,500 A 424.26,424.26 0,0,1 -175.74,200 z" f
ill="url(#grad7)" fill-opacity="0"/> |
| 162 <path id="wedgeXY7" d="M200,200 L200,624.26 A 424.26,424.26 0,0,1 500,500 z" fil
l="url(#grad8)" fill-opacity="0"/> |
| 163 <path id="lineSegment" d="M200,200 L200,624.26" fill="none" stroke="black" strok
e-opacity="0"/> |
| 164 |
| 165 <! keyframe 5 /> |
| 166 <text id="curveMultipleDesc1" fill-opacity="0" > |
| 167 A curve span may cover more |
| 168 </text> |
| 169 <text id="curveMultipleDesc2" y="240" fill-opacity="0" > |
| 170 than one sector. |
| 171 </text> |
| 172 <path id="curveSegment" d="M200,200 C250,200 300,150 300,100" fill="none" stroke
="black" stroke-opacity="0"/> |
| 173 <path id="curveSegment1" d="M200,200 C250,200 300,150 300,100" fill="none"/> |
| 174 <path id="curveSegment2" d="M200,200 C250,200 300,150 200,100" fill="none"/> |
| 175 <path id="curveSegment3" d="M200,200 C350,200 250,-150 170,300" fill="none"/> |
| 176 |
| 177 <! keyframe 6 /> |
| 178 <text id="line1DDest1" fill-opacity="0" > |
| 179 Some lines occupy one-dimensional |
| 180 </text> |
| 181 <text id="line1DDest2" y="240" fill-opacity="0" > |
| 182 sectors. |
| 183 </text> |
| 184 <text id="sectorDescXY9" x="500" y="460" fill="rgb(192,92,31)" fill-opacity="0"> |
| 185 X > 0 Y == 0</text> |
| 186 <text id="sectorDescXY10" x="500" y="460" fill="rgb(31,92,192)" fill-opacity="0"
> |
| 187 Y > 0 0 == X</text> |
| 188 <text id="sectorDescXY11" x="500" y="460" fill="rgb(127,63,127)" fill-opacity="0
"> |
| 189 X < 0 Y == X</text> |
| 190 <path id="horzSegment" d="M200,200 L341.4,200" fill="none" stroke="rgb(192,92,31
)" stroke-width="2" stroke-opacity="0"/> |
| 191 <path id="vertSegment" d="M200,200 L200,341.4" fill="none" stroke="rgb(31,92,192
)" stroke-width="2" stroke-opacity="0"/> |
| 192 <path id="diagSegment" d="M200,200 L100,100" fill="none" stroke="rgb(127,63,12
7)" stroke-width="2" stroke-opacity="0"/> |
| 193 |
| 194 <! keyframe 7 /> |
| 195 <text id="curve1dDesc1" fill-opacity="0" > |
| 196 Some curves initially occupy |
| 197 </text> |
| 198 <text id="curve1dDesc2" y="240" fill-opacity="0" > |
| 199 one-dimensional sectors, then diverge. |
| 200 </text> |
| 201 <path id="cubicSegment" fill="none" stroke="black" /> |
| 202 <path id="cubicSegment1" d="M200,200 C200,200 200,200 200,200" fill="none" /> |
| 203 <path id="cubicSegment2" d="M200,200 C250,200 300,200 300,100" fill="none"/> |
| 204 |
| 205 <text id="sectorNumberDesc" fill-opacity="0" > |
| 206 Each sector is assigned a number. |
| 207 </text> |
| 208 <text id="spanSectorDesc" fill-opacity="0" > |
| 209 Each span has a bit set for one or more sectors. |
| 210 </text> |
| 211 <text id="bitOverDesc" fill-opacity="0" > |
| 212 Span sets allow rough sorting without angle computation. |
| 213 </text> |
| 214 |
| 215 </svg> |
| 216 |
| 217 <! canvas support /> |
| 218 <script> |
| 219 |
| 220 var keyFrameQueue = []; |
| 221 var animationsPending = []; |
| 222 var animationsActive = []; |
| 223 var displayList = []; |
| 224 var visibleFinished = []; |
| 225 |
| 226 var animationState = {}; |
| 227 animationState.reset = function () { |
| 228 this.start = null; |
| 229 this.time = 0; |
| 230 this.requestID = null; |
| 231 this.paused = false; |
| 232 this.displayEngine = 'Canvas'; |
| 233 } |
| 234 |
| 235 circle.center = { x: 200, y: 200 } |
| 236 circle.radius = 100; |
| 237 |
| 238 function assert(condition) { |
| 239 if (!condition) debugger; |
| 240 } |
| 241 |
| 242 function CanvasGrads(ctx) { |
| 243 var grad1 = ctx.createRadialGradient(200, 200, 0, 200, 200, 300); |
| 244 grad1.addColorStop(0, "rgba(0,0,255, 0.3)"); |
| 245 grad1.addColorStop(1, "rgba(0,0,255, 0)"); |
| 246 var grad2 = ctx.createRadialGradient(200, 200, 0, 200, 200, 300); |
| 247 grad2.addColorStop(0, "rgba(0,255,0, 0.3)"); |
| 248 grad2.addColorStop(1, "rgba(0,255,0, 0)"); |
| 249 var grad3 = ctx.createRadialGradient(200, 200, 0, 200, 200, 300); |
| 250 grad3.addColorStop(0, "rgba(255,0,0, 0.3)"); |
| 251 grad3.addColorStop(1, "rgba(255,0,0, 0)"); |
| 252 var grad4 = ctx.createRadialGradient(200, 200, 0, 200, 200, 300); |
| 253 grad4.addColorStop(0, "rgba(192,63,192, 0.3)"); |
| 254 grad4.addColorStop(1, "rgba(192,63,192, 0)"); |
| 255 var grad5 = ctx.createRadialGradient(200, 200, 0, 200, 200, 300); |
| 256 grad5.addColorStop(0, "rgba(127,127,0, 0.3)"); |
| 257 grad5.addColorStop(1, "rgba(127,127,0, 0)"); |
| 258 var grad6 = ctx.createRadialGradient(200, 200, 0, 200, 200, 300); |
| 259 grad6.addColorStop(0, "rgba(127,0,127, 0.3)"); |
| 260 grad6.addColorStop(1, "rgba(127,0,127, 0)"); |
| 261 var grad7 = ctx.createRadialGradient(200, 200, 0, 200, 200, 300); |
| 262 grad7.addColorStop(0, "rgba(0,127,127, 0.3)"); |
| 263 grad7.addColorStop(1, "rgba(0,127,127, 0)"); |
| 264 var grad8 = ctx.createRadialGradient(200, 200, 0, 200, 200, 300); |
| 265 grad8.addColorStop(0, "rgba(63,192,63, 0.3)"); |
| 266 grad8.addColorStop(1, "rgba(63,192,63, 0)"); |
| 267 var data = { |
| 268 grad1: grad1, |
| 269 grad2: grad2, |
| 270 grad3: grad3, |
| 271 grad4: grad4, |
| 272 grad5: grad5, |
| 273 grad6: grad6, |
| 274 grad7: grad7, |
| 275 grad8: grad8, |
| 276 }; |
| 277 return data; |
| 278 } |
| 279 |
| 280 function skip_sep(data) { |
| 281 if (!data.length) { |
| 282 return data; |
| 283 } |
| 284 while (data[0] == ' ' || data[0] == ',') { |
| 285 data = data.substring(1); |
| 286 } |
| 287 return data; |
| 288 } |
| 289 |
| 290 function find_points(str, value, count, isRelative, relative) { |
| 291 var numRegEx = /-?\d+\.?\d*(?:e-?\d+)?/g; |
| 292 var match; |
| 293 for (var index = 0; index < count; ++index) { |
| 294 str = skip_sep(str); |
| 295 match = numRegEx.exec(str); |
| 296 assert(match); |
| 297 var x = Number(match[0]); |
| 298 str = skip_sep(str); |
| 299 match = numRegEx.exec(str); |
| 300 assert(match); |
| 301 var y = Number(match[0]); |
| 302 value[index] = { x: x, y : y }; |
| 303 } |
| 304 if (isRelative) { |
| 305 for (var index = 0; index < count; index++) { |
| 306 value[index].x += relative.x; |
| 307 value[index].y += relative.y; |
| 308 } |
| 309 } |
| 310 return str.substring(match.index + match[0].length); |
| 311 } |
| 312 |
| 313 function find_scalar(str, obj, isRelative, relative) { |
| 314 var numRegEx = /-?\d+\.?\d*(?:e-?\d+)?/g; |
| 315 str = skip_sep(str); |
| 316 var match = numRegEx.exec(str); |
| 317 obj.value = Number(match[0]); |
| 318 if (isRelative) { |
| 319 obj.value += relative; |
| 320 } |
| 321 return str.substring(match.index + match[0].length); |
| 322 } |
| 323 |
| 324 function parse_path(data) { |
| 325 var path = "ctx.beginPath();\n"; |
| 326 var f = {x:0, y:0}; |
| 327 var c = {x:0, y:0}; |
| 328 var lastc = {x:0, y:0}; |
| 329 var points = []; |
| 330 var op = '\0'; |
| 331 var previousOp = '\0'; |
| 332 var relative = false; |
| 333 for (;;) { |
| 334 data = skip_sep(data); |
| 335 if (!data.length) { |
| 336 break; |
| 337 } |
| 338 var ch = data[0]; |
| 339 if (('0' <= ch && ch <= '9') || ch == '-' || ch == '+') { |
| 340 assert(op != '\0'); |
| 341 } else if (ch == ' ' || ch == ',') { |
| 342 data = skip_sep(data); |
| 343 } else { |
| 344 op = ch; |
| 345 relative = false; |
| 346 if ('a' <= op && op <= 'z') { |
| 347 op = op.toUpperCase(); |
| 348 relative = true; |
| 349 } |
| 350 data = data.substring(1); |
| 351 data = skip_sep(data); |
| 352 } |
| 353 switch (op) { |
| 354 case 'A': |
| 355 var radii = []; |
| 356 data = find_points(data, radii, 1, false, null); |
| 357 var xaxisObj = {}; |
| 358 data = find_scalar(data, xaxisObj, false, null); |
| 359 var largeArcObj = {}; |
| 360 data = find_scalar(data, largeArcObj, false, null); |
| 361 var sweepObj = {}; |
| 362 data = find_scalar(data, sweepObj, false, null); |
| 363 data = find_points(data, points, 1, relative, c); |
| 364 var mid = { x: (c.x + points[0].x) / 2, y: (c.y + points[0].y) /
2 }; |
| 365 var midVec = { x: mid.x - c.x, y: mid.y - c.y }; |
| 366 var midLenSqr = midVec.x * midVec.x + midVec.y * midVec.y; |
| 367 var radius = radii[0].x; |
| 368 var scale = Math.sqrt(midLenSqr) / Math.sqrt(radius * radius - m
idLenSqr); |
| 369 var tangentPt = { x: mid.x + midVec.y * scale, |
| 370 y: mid.y - midVec.x * scale }; |
| 371 path += "ctx.arcTo(" + tangentPt.x + "," + tangentPt.y + "," |
| 372 + points[0].x + "," + points[0].y + "," + radius + ");\n"; |
| 373 c = points[0]; |
| 374 break; |
| 375 case 'M': |
| 376 data = find_points(data, points, 1, relative, c); |
| 377 path += "ctx.moveTo(" + points[0].x + "," + points[0].y + ");\n"
; |
| 378 op = 'L'; |
| 379 c = points[0]; |
| 380 break; |
| 381 case 'L': |
| 382 data = find_points(data, points, 1, relative, c); |
| 383 path += "ctx.lineTo(" + points[0].x + "," + points[0].y + ");\n"
; |
| 384 c = points[0]; |
| 385 break; |
| 386 case 'H': { |
| 387 var xObj = {}; |
| 388 data = find_scalar(data, xObj, relative, c.x); |
| 389 path += "ctx.lineTo(" + xObj.value + "," + c.y + ");\n"; |
| 390 c.x = xObj.value; |
| 391 } break; |
| 392 case 'V': { |
| 393 var yObj = {}; |
| 394 data = find_scalar(data, y, relative, c.y); |
| 395 path += "ctx.lineTo(" + c.x + "," + yObj.value+ ");\n"; |
| 396 c.y = yObj.value; |
| 397 } break; |
| 398 case 'C': |
| 399 data = find_points(data, points, 3, relative, c); |
| 400 path += "ctx.bezierCurveTo(" + points[0].x + "," + points[0].y +
"," |
| 401 + points[1].x + "," + points[1].y + "," |
| 402 + points[2].x + "," + points[2].y + ");\n"; |
| 403 lastc = points[1]; |
| 404 c = points[2]; |
| 405 break; |
| 406 case 'S': |
| 407 var pts2_3 = []; |
| 408 data = find_points(data, pts2_3, 2, relative, c); |
| 409 points[0] = c; |
| 410 points[1] = pts2_3[0]; |
| 411 points[2] = pts2_3[1]; |
| 412 if (previousOp == 'C' || previousOp == 'S') { |
| 413 points[0].x -= lastc.x - c.x; |
| 414 points[0].y -= lastc.y - c.y; |
| 415 } |
| 416 path += "ctx.bezierCurveTo(" + points[0].x + "," + points[0].y +
"," |
| 417 + points[1].x + "," + points[1].y + "," |
| 418 + points[2].x + "," + points[2].y + ");\n"; |
| 419 lastc = points[1]; |
| 420 c = points[2]; |
| 421 break; |
| 422 case 'Q': // Quadratic Bezier Curve |
| 423 data = find_points(data, points, 2, relative, c); |
| 424 path += "ctx.quadraticCurveTo(" + points[0].x + "," + points[0].
y + "," |
| 425 + points[1].x + "," + points[1].y + ");\n"; |
| 426 lastc = points[0]; |
| 427 c = points[1]; |
| 428 break; |
| 429 case 'T': |
| 430 var pts2 = []; |
| 431 data = find_points(data, pts2, 1, relative, c); |
| 432 points[0] = pts2[0]; |
| 433 points[1] = pts2[0]; |
| 434 if (previousOp == 'Q' || previousOp == 'T') { |
| 435 points[0].x = c.x * 2 - lastc.x; |
| 436 points[0].y = c.y * 2 - lastc.y; |
| 437 } |
| 438 path += "ctx.quadraticCurveTo(" + points[0].x + "," + points[0].
y + "," |
| 439 + points[1].x + "," + points[1].y + ");\n"; |
| 440 path.quadTo(points[0], points[1]); |
| 441 lastc = points[0]; |
| 442 c = points[1]; |
| 443 break; |
| 444 case 'Z': |
| 445 path += "ctx.closePath();\n"; |
| 446 c = f; |
| 447 op = '\0'; |
| 448 break; |
| 449 case '~': |
| 450 var args = []; |
| 451 data = find_points(data, args, 2, false, null); |
| 452 path += "moveTo(" + args[0].x + "," + args[0].y + ");\n"; |
| 453 path += "lineTo(" + args[1].x + "," + args[1].y + ");\n"; |
| 454 break; |
| 455 default: |
| 456 return false; |
| 457 } |
| 458 if (previousOp == 0) { |
| 459 f = c; |
| 460 } |
| 461 previousOp = op; |
| 462 } |
| 463 return path; |
| 464 } |
| 465 |
| 466 function CanvasPaths(ctx) { |
| 467 var svgStrs = { |
| 468 // keyframe 1 |
| 469 span1: "M200,200 Q300,300 200,300", |
| 470 span2: "M200,200 C100,300 100,400 200,300", |
| 471 span3: "M200,200 C300,100 100,400 300,200", |
| 472 wedge1: "M200,200 L500,500 A 424.26,424.26 0,0,1 200,624.26 z", |
| 473 wedge2: "M200,200 L200,624.26 A 424.26,424.26 0,0,1 -100,500 z", |
| 474 wedge3: "M200,200 L500,-100 A 424.26,424.26 0,0,1 240,622.5 z", |
| 475 // keyframe 2 |
| 476 span4: "M200,200 Q300,300 400,300", |
| 477 span5: "M200,200 Q280,320 200,400", |
| 478 span6: "M200,200 Q60,340 100,400", |
| 479 wedge4: "M200,200 L500,500 A 424.26,424.26 0,0,1 579.47,389.74 z", |
| 480 wedge5: "M200,200 L389.74,579.47 A 424.26,424.26 0,0,1 200,500 z", |
| 481 wedge6: "M200,200 L10.26,579.47 A 424.26,424.26 0,0,1 -100,500 z", |
| 482 // keyframe 3 |
| 483 xaxis: "M100,200 L300,200", |
| 484 yaxis: "M200,100 L200,300", |
| 485 wedgeXY8: "M200,200 L500,500 A 424.26,424.26 0,0,1 624.26,200 z", |
| 486 wedgeXY6: "M200,200 L-100,500 A 424.26,424.26 0,0,1 200,624.26 z", |
| 487 wedgeXY3: "M200,200 L-100,-100 A 424.26,424.26 0,0,1 200,-175.74 z", |
| 488 // keyframe 4 |
| 489 wedgeXY1: "M200,200 L500,-100 A 424.26,424.26 0,0,1 624.26,200 z", |
| 490 wedgeXY2: "M200,200 L200,-175.74 A 424.26,424.26 0,0,1 500,-100 z", |
| 491 wedgeXY4: "M200,200 L-175.74,200 A 424.26,424.26 0,0,1 -100,-100 z", |
| 492 wedgeXY5: "M200,200 L-100,500 A 424.26,424.26 0,0,1 -175.74,200 z", |
| 493 wedgeXY7: "M200,200 L200,624.26 A 424.26,424.26 0,0,1 500,500 z", |
| 494 lineSegment: "M200,200 L200,624.26", |
| 495 // keyframe 5 |
| 496 curveSegment: "M200,200 C250,200 300,150 300,100", |
| 497 curveSegment1: "M200,200 C250,200 300,150 300,100", |
| 498 curveSegment2: "M200,200 C250,200 300,150 200,100", |
| 499 curveSegment3: "M200,200 C350,200 250,-150 170,300", |
| 500 // keyframe 6 |
| 501 horzSegment: "M200,200 L341.4,200", |
| 502 vertSegment: "M200,200 L200,341.4", |
| 503 diagSegment: "M200,200 L100,100", |
| 504 // keyframe 7 |
| 505 cubicSegment: "M200,200 C200,200 200,200 200,200", |
| 506 cubicSegment1: "M200,200 C200,200 200,200 200,200", |
| 507 cubicSegment2: "M200,200 C250,200 300,200 300,100", |
| 508 }; |
| 509 var paths = []; |
| 510 var keys = Object.keys(svgStrs); |
| 511 for (var index in keys) { |
| 512 var key = keys[index]; |
| 513 var str = svgStrs[key]; |
| 514 var path = parse_path(str); |
| 515 var record = []; |
| 516 paths[key] = { |
| 517 str: str, |
| 518 funcBody: path, |
| 519 }; |
| 520 } |
| 521 return paths; |
| 522 } |
| 523 |
| 524 function canvas_fill_font(record) { |
| 525 assert(record); |
| 526 var str = 'ctx.font = "normal 1.3rem Helvetica,Arial";\n'; |
| 527 if (record.fillStyle) { |
| 528 str += 'ctx.fillStyle = ' + record.fillStyle + ';\n'; |
| 529 } |
| 530 return str; |
| 531 } |
| 532 |
| 533 function canvas_fill_text(record) { |
| 534 assert(record); |
| 535 assert(typeof record.fillText == 'string'); |
| 536 return 'ctx.fillText("' + record.fillText + '"'; |
| 537 } |
| 538 |
| 539 function canvas_xy(record) { |
| 540 var x = typeof record.x == "number" ? record.x : 400; |
| 541 var y = typeof record.y == "number" ? record.y : 200; |
| 542 return ', ' + x + ', ' + y + ');\n'; |
| 543 } |
| 544 |
| 545 function canvas_text_xy(record) { |
| 546 return canvas_fill_text(record) + canvas_xy(record); |
| 547 } |
| 548 |
| 549 function add_canvas_stroke(paths, data, id, strokeStyle) { |
| 550 var record = {}; |
| 551 record.data = paths[id].funcBody; |
| 552 record.style = 'ctx.strokeStyle = ' + (strokeStyle ? strokeStyle : '"black"'
) + ';\n'; |
| 553 record.draw = 'ctx.stroke();\n'; |
| 554 record.func = new Function('ctx', record.data + record.style + record.draw); |
| 555 return data[id] = record; |
| 556 } |
| 557 |
| 558 function add_canvas_style(record, style) { |
| 559 record.style += style; |
| 560 record.func = new Function('ctx', record.data + record.style + record.draw); |
| 561 } |
| 562 |
| 563 function add_canvas_fill(paths, data, id, fillStyle) { |
| 564 var record = {}; |
| 565 record.data = paths[id].funcBody; |
| 566 record.style = 'ctx.fillStyle = ' + (fillStyle ? fillStyle : '"black"') + ';
\n'; |
| 567 record.draw = 'ctx.fill();\n'; |
| 568 record.func = new Function('ctx', record.data + record.style + record.draw); |
| 569 return data[id] = record; |
| 570 } |
| 571 |
| 572 function add_canvas_text(data, id, params) { |
| 573 var record = {}; |
| 574 record.style = canvas_fill_font(params); |
| 575 record.draw = canvas_fill_text(params); |
| 576 record.position = canvas_xy(params); |
| 577 record.x = params.x; |
| 578 record.y = params.y; |
| 579 record.func = new Function('ctx', record.style + record.draw + record.positi
on); |
| 580 return data[id] = record; |
| 581 } |
| 582 |
| 583 function keyframe1(grads, paths) { |
| 584 var data = []; |
| 585 add_canvas_text(data, "spanWedgeDesc", { fillText:"All spans are contained b
y a wedge" } ); |
| 586 add_canvas_stroke(paths, data, "span1"); |
| 587 add_canvas_stroke(paths, data, "span2"); |
| 588 add_canvas_stroke(paths, data, "span3"); |
| 589 add_canvas_fill(paths, data, "wedge1", "grads.grad1"); |
| 590 add_canvas_fill(paths, data, "wedge2", "grads.grad2"); |
| 591 add_canvas_fill(paths, data, "wedge3", "grads.grad3"); |
| 592 return data; |
| 593 } |
| 594 |
| 595 function keyframe2(grads, paths) { |
| 596 var data = []; |
| 597 add_canvas_text(data, "trivialWedgeDesc1", { fillText:"Wedges that don't ove
rlap can be" } ); |
| 598 add_canvas_text(data, "trivialWedgeDesc2", { fillText:"easily sorted.", y:24
0 } ); |
| 599 add_canvas_stroke(paths, data, "span4").debug = true; |
| 600 add_canvas_stroke(paths, data, "span5"); |
| 601 add_canvas_stroke(paths, data, "span6"); |
| 602 add_canvas_fill(paths, data, "wedge4", "grads.grad1"); |
| 603 add_canvas_fill(paths, data, "wedge5", "grads.grad2"); |
| 604 add_canvas_fill(paths, data, "wedge6", "grads.grad3"); |
| 605 return data; |
| 606 } |
| 607 |
| 608 function setup_axes(paths, data) { |
| 609 var color = '"rgb(191,191,191)"'; |
| 610 var xaxis = add_canvas_stroke(paths, data, "xaxis", color); |
| 611 xaxis.funcBody = canvas_fill_font( { fillStyle:color } ); |
| 612 xaxis.funcBody += canvas_text_xy( { fillText:"-X", x:100, y:220 } ); |
| 613 xaxis.funcBody += "ctx.textAlign = 'right';\n"; |
| 614 xaxis.funcBody += canvas_text_xy( { fillText:"+X", x:300, y:220 } ); |
| 615 xaxis.func = new Function('ctx', xaxis.data + xaxis.style + xaxis.draw + xax
is.funcBody); |
| 616 var yaxis = add_canvas_stroke(paths, data, "yaxis", color); |
| 617 yaxis.funcBody = canvas_fill_font( { fillStyle:color } ); |
| 618 yaxis.funcBody += "ctx.textBaseline = 'hanging';\n"; |
| 619 yaxis.funcBody += canvas_text_xy( { fillText:"-Y", x:205, y:100 } ); |
| 620 yaxis.funcBody += "ctx.textBaseline = 'alphabetic';\n"; |
| 621 yaxis.funcBody += canvas_text_xy( { fillText:"+Y", x:205, y:300 } ); |
| 622 yaxis.func = new Function('ctx', yaxis.data + yaxis.style + yaxis.draw + yax
is.funcBody); |
| 623 } |
| 624 |
| 625 function keyframe3(grads, paths) { |
| 626 var data = []; |
| 627 add_canvas_text(data, "sectorDesc1", { fillText:"A sector is a wedge of a ci
rcle" } ); |
| 628 add_canvas_text(data, "sectorDesc2", { fillText:"containing a range of point
s.", y:240 } ); |
| 629 setup_axes(paths, data); |
| 630 add_canvas_text(data, "sectorDescXYA", |
| 631 { fillText:"X > 0 Y > 0 Y < X", x:500, y:310, fillStyle:'"rgb(0,0,2
55)"'} ); |
| 632 add_canvas_text(data, "sectorDescXYB", |
| 633 { fillText:"X < 0 Y > 0 -Y < X", x:500, y:360, fillStyle:'"rgb(0,127
,0)"'} ); |
| 634 add_canvas_text(data, "sectorDescXYC", |
| 635 { fillText:"X < 0 Y < 0 Y < X", x:500, y:410, fillStyle:'"rgb(255,0
,0)"'} ); |
| 636 add_canvas_fill(paths, data, "wedgeXY8", "grads.grad1"); |
| 637 add_canvas_fill(paths, data, "wedgeXY6", "grads.grad2"); |
| 638 add_canvas_fill(paths, data, "wedgeXY3", "grads.grad3"); |
| 639 return data; |
| 640 } |
| 641 |
| 642 function keyframe4(grads, paths) { |
| 643 var data = []; |
| 644 setup_axes(paths, data); |
| 645 add_canvas_text(data, "lineSingleDesc", |
| 646 { fillText:"Line spans are contained by a single sector." } ); |
| 647 add_canvas_text(data, "sectorDescXY1", |
| 648 { fillText:"X > 0 Y < 0 -Y < X", x:500, y:460, fillStyle:'"rgb(192,6
3,192)"'} ); |
| 649 add_canvas_text(data, "sectorDescXY2", |
| 650 { fillText:"X > 0 Y < 0 -Y > X", x:500, y:460, fillStyle:'"rgb(127,1
27,0)"'} ); |
| 651 add_canvas_text(data, "sectorDescXY3", |
| 652 { fillText:"X < 0 Y < 0 Y < X", x:500, y:460, fillStyle:'"rgb(255,0
,0)"'} ); |
| 653 add_canvas_text(data, "sectorDescXY4", |
| 654 { fillText:"X < 0 Y < 0 Y > X", x:500, y:460, fillStyle:'"rgb(127,0
,127)"'} ); |
| 655 add_canvas_text(data, "sectorDescXY5", |
| 656 { fillText:"X < 0 Y > 0 -Y < X", x:500, y:460, fillStyle:'"rgb(0,127
,127)"'} ); |
| 657 add_canvas_text(data, "sectorDescXY6", |
| 658 { fillText:"X < 0 Y > 0 -Y < X", x:500, y:460, fillStyle:'"rgb(0,127
,0)"'} ); |
| 659 add_canvas_text(data, "sectorDescXY7", |
| 660 { fillText:"X > 0 Y > 0 Y > X", x:500, y:460, fillStyle:'"rgb(63,19
2,63)"'} ); |
| 661 add_canvas_text(data, "sectorDescXY8", |
| 662 { fillText:"X > 0 Y > 0 Y < X", x:500, y:460, fillStyle:'"rgb(0,0,2
55)"'} ); |
| 663 add_canvas_fill(paths, data, "wedgeXY1", "grads.grad4"); |
| 664 add_canvas_fill(paths, data, "wedgeXY2", "grads.grad5"); |
| 665 add_canvas_fill(paths, data, "wedgeXY3", "grads.grad3"); |
| 666 add_canvas_fill(paths, data, "wedgeXY4", "grads.grad6"); |
| 667 add_canvas_fill(paths, data, "wedgeXY5", "grads.grad7"); |
| 668 add_canvas_fill(paths, data, "wedgeXY6", "grads.grad2"); |
| 669 add_canvas_fill(paths, data, "wedgeXY7", "grads.grad8"); |
| 670 add_canvas_fill(paths, data, "wedgeXY8", "grads.grad1"); |
| 671 add_canvas_stroke(paths, data, "lineSegment"); |
| 672 return data; |
| 673 } |
| 674 |
| 675 function keyframe5(grads, paths) { |
| 676 var data = []; |
| 677 setup_axes(paths, data); |
| 678 add_canvas_text(data, "curveMultipleDesc1", |
| 679 { fillText:"A curve span may cover more" } ); |
| 680 add_canvas_text(data, "curveMultipleDesc2", |
| 681 { fillText:"than one sector.", y:240 } ); |
| 682 add_canvas_stroke(paths, data, "curveSegment"); |
| 683 add_canvas_text(data, "sectorDescXY1", |
| 684 { fillText:"X > 0 Y < 0 -Y < X", x:500, y:460, fillStyle:'"rgb(192,6
3,192)"'} ); |
| 685 add_canvas_text(data, "sectorDescXY2", |
| 686 { fillText:"X > 0 Y < 0 -Y > X", x:500, y:460, fillStyle:'"rgb(127,1
27,0)"'} ); |
| 687 add_canvas_text(data, "sectorDescXY3", |
| 688 { fillText:"X < 0 Y < 0 Y < X", x:500, y:460, fillStyle:'"rgb(255,0
,0)"'} ); |
| 689 add_canvas_text(data, "sectorDescXY4", |
| 690 { fillText:"X < 0 Y < 0 Y > X", x:500, y:460, fillStyle:'"rgb(127,0
,127)"'} ); |
| 691 add_canvas_text(data, "sectorDescXY5", |
| 692 { fillText:"X < 0 Y > 0 -Y < X", x:500, y:460, fillStyle:'"rgb(0,127
,127)"'} ); |
| 693 add_canvas_text(data, "sectorDescXY6", |
| 694 { fillText:"X < 0 Y > 0 -Y < X", x:500, y:460, fillStyle:'"rgb(0,127
,0)"'} ); |
| 695 add_canvas_fill(paths, data, "wedgeXY1", "grads.grad4"); |
| 696 add_canvas_fill(paths, data, "wedgeXY2", "grads.grad5"); |
| 697 add_canvas_fill(paths, data, "wedgeXY3", "grads.grad3"); |
| 698 add_canvas_fill(paths, data, "wedgeXY4", "grads.grad6"); |
| 699 add_canvas_fill(paths, data, "wedgeXY5", "grads.grad7"); |
| 700 add_canvas_fill(paths, data, "wedgeXY6", "grads.grad2"); |
| 701 return data; |
| 702 } |
| 703 |
| 704 function keyframe6(grads, paths) { |
| 705 var data = []; |
| 706 setup_axes(paths, data); |
| 707 |
| 708 add_canvas_text(data, "line1DDest1", |
| 709 { fillText:"Some lines occupy one-dimensional" } ); |
| 710 add_canvas_text(data, "line1DDest2", |
| 711 { fillText:"sectors.", y:240 } ); |
| 712 add_canvas_text(data, "sectorDescXY9", |
| 713 { fillText:"X > 0 Y == 0", x:500, y:460, fillStyle:'"rgb(192,92,31)"'
} ); |
| 714 add_canvas_text(data, "sectorDescXY10", |
| 715 { fillText:"Y > 0 0 == X", x:500, y:460, fillStyle:'"rgb(31,92,192)"'
} ); |
| 716 add_canvas_text(data, "sectorDescXY11", |
| 717 { fillText:"X < 0 Y == X", x:500, y:460, fillStyle:'"rgb(127,63,127)"'
} ); |
| 718 var horz = add_canvas_stroke(paths, data, "horzSegment", '"rgb(192,92,31)"')
; |
| 719 add_canvas_style(horz, "ctx.lineWidth = " + 2 * animationState.resScale + ";
\n"); |
| 720 var vert = add_canvas_stroke(paths, data, "vertSegment", '"rgb(31,92,192)"')
; |
| 721 add_canvas_style(vert, "ctx.lineWidth = " + 2 * animationState.resScale + ";
\n"); |
| 722 var diag = add_canvas_stroke(paths, data, "diagSegment", '"rgb(127,63,127)"'
); |
| 723 add_canvas_style(diag, "ctx.lineWidth = " + 2 * animationState.resScale + ";
\n"); |
| 724 return data; |
| 725 } |
| 726 |
| 727 function keyframe7(grads, paths) { |
| 728 var data = []; |
| 729 setup_axes(paths, data); |
| 730 add_canvas_text(data, "curve1dDesc1", |
| 731 { fillText:"Some curves initially occupy" } ); |
| 732 add_canvas_text(data, "curve1dDesc2", |
| 733 { fillText:"one-dimensional sectors, then diverge.", y:240 } ); |
| 734 add_canvas_stroke(paths, data, "cubicSegment"); |
| 735 add_canvas_text(data, "sectorDescXY1", |
| 736 { fillText:"X > 0 Y < 0 -Y < X", x:500, y:460, fillStyle:'"rgb(192,6
3,192)"'} ); |
| 737 add_canvas_text(data, "sectorDescXY9", |
| 738 { fillText:"X > 0 Y == 0", x:500, y:460, fillStyle:'"rgb(192,92,31)"'
} ); |
| 739 var horz = add_canvas_stroke(paths, data, "horzSegment", '"rgb(192,92,31)"')
; |
| 740 add_canvas_style(horz, "ctx.lineWidth = " + 2 * animationState.resScale + ";
\n"); |
| 741 add_canvas_fill(paths, data, "wedgeXY1", "grads.grad4"); |
| 742 return data; |
| 743 } |
| 744 |
| 745 var canvasData = null; |
| 746 |
| 747 function CanvasInit(keyframe) { |
| 748 canvasData = window[keyframe](grads, paths); |
| 749 } |
| 750 |
| 751 </script> |
| 752 |
| 753 <script> |
| 754 |
| 755 function interp(A, B, t) { |
| 756 return A + (B - A) * t; |
| 757 } |
| 758 |
| 759 function interp_cubic_coords(x1, x2, x3, x4, t) |
| 760 { |
| 761 var ab = interp(x1, x2, t); |
| 762 var bc = interp(x2, x3, t); |
| 763 var cd = interp(x3, x4, t); |
| 764 var abc = interp(ab, bc, t); |
| 765 var bcd = interp(bc, cd, t); |
| 766 var abcd = interp(abc, bcd, t); |
| 767 return abcd; |
| 768 } |
| 769 |
| 770 function cubic_partial(value, p) { |
| 771 var x1 = p[0], y1 = p[1], x2 = p[2], y2 = p[3]; |
| 772 var x3 = p[4], y3 = p[5], x4 = p[6], y4 = p[7]; |
| 773 var t1 = 0, t2 = value; |
| 774 var ax = interp_cubic_coords(x1, x2, x3, x4, t1); |
| 775 var ay = interp_cubic_coords(y1, y2, y3, y4, t1); |
| 776 var ex = interp_cubic_coords(x1, x2, x3, x4, (t1*2+t2)/3); |
| 777 var ey = interp_cubic_coords(y1, y2, y3, y4, (t1*2+t2)/3); |
| 778 var fx = interp_cubic_coords(x1, x2, x3, x4, (t1+t2*2)/3); |
| 779 var fy = interp_cubic_coords(y1, y2, y3, y4, (t1+t2*2)/3); |
| 780 var dx = interp_cubic_coords(x1, x2, x3, x4, t2); |
| 781 var dy = interp_cubic_coords(y1, y2, y3, y4, t2); |
| 782 var mx = ex * 27 - ax * 8 - dx; |
| 783 var my = ey * 27 - ay * 8 - dy; |
| 784 var nx = fx * 27 - ax - dx * 8; |
| 785 var ny = fy * 27 - ay - dy * 8; |
| 786 var bx = (mx * 2 - nx) / 18; |
| 787 var by = (my * 2 - ny) / 18; |
| 788 var cx = (nx * 2 - mx) / 18; |
| 789 var cy = (ny * 2 - my) / 18; |
| 790 var array = [ |
| 791 ax, ay, bx, by, cx, cy, dx, dy |
| 792 ]; |
| 793 return array; |
| 794 } |
| 795 |
| 796 function evaluate_at(value, p) { |
| 797 var array = []; |
| 798 for (var index = 0; index < p.length; ++index) { |
| 799 var func = new Function('value', 'return ' + p[index] + ';'); |
| 800 array[index] = func(value); |
| 801 } |
| 802 return array; |
| 803 } |
| 804 |
| 805 function interpolate_at(value, p) { |
| 806 var array = []; |
| 807 var start = p[0]; |
| 808 var end = p[1]; |
| 809 assert(typeof end == typeof start); |
| 810 switch (typeof start) { |
| 811 case 'object': |
| 812 for (var index = 0; index < start.length; ++index) { |
| 813 array[index] = interp(start[index], end[index], value); |
| 814 } |
| 815 break; |
| 816 case 'number': |
| 817 array[index] = interp(start, end, value); |
| 818 break; |
| 819 default: |
| 820 debugger; |
| 821 } |
| 822 return array; |
| 823 } |
| 824 |
| 825 function AnimationAddCommon(timing, range, attr, inParams) { |
| 826 var animation = { |
| 827 timing: timing, |
| 828 range: range, |
| 829 attr: attr, |
| 830 inParams: inParams, |
| 831 duration: timing[1] - timing[0], |
| 832 remaining: timing[1] - timing[0], |
| 833 firstStep: true, |
| 834 } |
| 835 animationsPending.push(animation); |
| 836 return animation; |
| 837 } |
| 838 |
| 839 function AnimationAddSVG(timing, element, range, attr, inParams) { |
| 840 var animation = AnimationAddCommon(timing, range, attr, inParams); |
| 841 animation.element = element; |
| 842 return animation; |
| 843 } |
| 844 |
| 845 function AnimationAddCanvas(timing, element, range, attr, inParams) { |
| 846 var animation = AnimationAddCommon(timing, range, attr, inParams); |
| 847 animation.element = canvasData[element]; |
| 848 assert(animation.element); |
| 849 animation.firstElement = null; |
| 850 return animation; |
| 851 } |
| 852 |
| 853 function AnimationAdd(timing, e, range, attr, funct, inParams) { |
| 854 if (!range) { |
| 855 range = [0, 1]; |
| 856 } |
| 857 if (!attr) { |
| 858 attr = 'opacity'; |
| 859 } |
| 860 if (!funct) { |
| 861 funct = interpolate_at; |
| 862 } |
| 863 var element; |
| 864 switch (animationState.displayEngine) { |
| 865 case 'SVG': |
| 866 element = typeof e == 'string' ? document.getElementById(e) : e; |
| 867 break; |
| 868 case 'Canvas': |
| 869 element = typeof e == 'string' ? e : e.id; |
| 870 break; |
| 871 default: |
| 872 debugger; |
| 873 } |
| 874 assert(element); |
| 875 switch (attr) { |
| 876 case 'path': |
| 877 if (!inParams) { |
| 878 inParams = PathDataArray(element); |
| 879 } |
| 880 break; |
| 881 case 'opacity': |
| 882 if (!inParams) { |
| 883 inParams = [0, 1]; |
| 884 } |
| 885 break; |
| 886 default: |
| 887 debugger; |
| 888 } |
| 889 var funcBody = 'var outParams = ' + funct.name + '(value, inParams);\n'; |
| 890 switch (animationState.displayEngine) { |
| 891 case 'SVG': |
| 892 switch (attr) { |
| 893 case 'path': |
| 894 var verbArray = PathVerbArray(element); |
| 895 funcBody += 'return '; |
| 896 for (var index = 0; index < inParams.length; ++index) { |
| 897 funcBody += '"' + verbArray[index] + '"'; |
| 898 funcBody += 'outParams[' + index + '];\n'; |
| 899 } |
| 900 if (verbArray.length > inParams.length) { |
| 901 funcBody += '"' + verbArray[verbArray.length - 1] + '"'; |
| 902 } |
| 903 funcBody += ';\n'; |
| 904 var animation = AnimationAddSVG(timing, element, range, "d",
inParams); |
| 905 animation.func = new Function('value', 'inParams', funcBody)
; |
| 906 break; |
| 907 case 'opacity': |
| 908 if (animation.element.getAttribute("stroke-opacity")) { |
| 909 animation = AnimationAddSVG(timing, element, range, "str
oke-opacity", inParams); |
| 910 } |
| 911 if (animation.element.getAttribute("fill-opacity")) { |
| 912 animation = AnimationAddSVG(timing, element, range, "fil
l-opacity", inParams); |
| 913 } |
| 914 break; |
| 915 default: |
| 916 debugger; |
| 917 } |
| 918 case 'Canvas': |
| 919 switch (attr) { |
| 920 case 'path': |
| 921 var verbArray = PathVerbArray(element); |
| 922 for (var index = 0; index < inParams.length; ++index) { |
| 923 funcBody += verbArray[index]; |
| 924 funcBody += 'outParams[' + index + ']'; |
| 925 } |
| 926 if (verbArray.length > inParams.length) { |
| 927 funcBody += verbArray[verbArray.length - 1]; |
| 928 } |
| 929 animation = AnimationAddCanvas(timing, element, range, attr,
inParams); |
| 930 funcBody += animation.element.style + animation.element.draw
; |
| 931 animation.func = new Function('ctx', 'value', 'inParams', fu
ncBody); |
| 932 break; |
| 933 case 'opacity': |
| 934 animation = AnimationAddCanvas(timing, element, range, attr,
inParams); |
| 935 break; |
| 936 default: |
| 937 debugger; |
| 938 } |
| 939 break; |
| 940 default: |
| 941 debugger; |
| 942 } |
| 943 return animation; |
| 944 } |
| 945 |
| 946 function path_data_common(element, getValues) { |
| 947 var numRegEx = /-?\d+\.?\d*(?:e-?\d+)?/g; |
| 948 var data = []; |
| 949 var match; |
| 950 var path; |
| 951 switch (animationState.displayEngine) { |
| 952 case 'SVG': path = element.getAttribute("d"); break; |
| 953 case 'Canvas': path = paths[element].funcBody; break; |
| 954 default: debugger; |
| 955 } |
| 956 if (getValues) { |
| 957 while ((match = numRegEx.exec(path))) { |
| 958 data.push(Number(match[0])); |
| 959 } |
| 960 } else { |
| 961 var sIndex = 0; |
| 962 while ((match = numRegEx.exec(path))) { |
| 963 if (sIndex < match.index) { |
| 964 data.push(path.substring(sIndex, match.index)); |
| 965 } |
| 966 sIndex = match.index + match[0].length; |
| 967 } |
| 968 if (sIndex < path.length) { |
| 969 data.push(path.substring(sIndex, path.length)); |
| 970 } |
| 971 } |
| 972 return data; |
| 973 } |
| 974 |
| 975 function PathDataArray(element) { |
| 976 return path_data_common(element, true); |
| 977 } |
| 978 |
| 979 function PathVerbArray(element) { |
| 980 return path_data_common(element, false); |
| 981 } |
| 982 |
| 983 function PathSet(element, funct, value, params) { |
| 984 var pathVerbs = PathVerbArray(element); |
| 985 if (funct) { |
| 986 params = funct(value, params); |
| 987 } |
| 988 var setValue = ''; |
| 989 for (var index = 0; index < params.length; ++index) { |
| 990 setValue += pathVerbs[index]; |
| 991 setValue += params[index]; |
| 992 } |
| 993 if (pathVerbs.length > params.length) { |
| 994 setValue += pathVerbs[pathVerbs.length - 1]; |
| 995 } |
| 996 switch (animationState.displayEngine) { |
| 997 case 'SVG': |
| 998 element.setAttribute('d', setValue); |
| 999 break; |
| 1000 case 'Canvas': |
| 1001 element.func = new Function('ctx', setValue + element.style + elemen
t.draw); |
| 1002 break; |
| 1003 default: |
| 1004 debugger; |
| 1005 } |
| 1006 } |
| 1007 |
| 1008 function RemoveFromArray(array, element) { |
| 1009 for (var index in array) { |
| 1010 var record = array[index]; |
| 1011 if (record.element == element) { |
| 1012 array.splice(index, 1); |
| 1013 break; |
| 1014 } |
| 1015 } |
| 1016 } |
| 1017 |
| 1018 function EndAnimationCanvas(animation, visibleFinished) { |
| 1019 var changeAlpha = "opacity" == animation.attr; |
| 1020 if (!changeAlpha || animation.range[1] > 0) { |
| 1021 if (changeAlpha) { |
| 1022 ctx.save(); |
| 1023 ctx.globalAlpha = animation.range[1]; |
| 1024 } |
| 1025 if (animation.func) { |
| 1026 animation.func(ctx, animation.range[animation.range.length - 1], ani
mation.inParams); |
| 1027 } else { |
| 1028 animation.element.func(ctx); |
| 1029 } |
| 1030 if (changeAlpha) { |
| 1031 ctx.restore(); |
| 1032 } |
| 1033 // if (visibleFinished) { |
| 1034 // visibleFinished.push(animation); |
| 1035 // } |
| 1036 } else { |
| 1037 // if (visibleFinished) { |
| 1038 // RemoveFromArray(visibleFinished, animation.element); |
| 1039 // } |
| 1040 } |
| 1041 } |
| 1042 |
| 1043 /* start here |
| 1044 canvas: |
| 1045 |
| 1046 display list : |
| 1047 for each element (canvas) |
| 1048 save |
| 1049 set global alpha (override) |
| 1050 create geometry (override) |
| 1051 create style (override) |
| 1052 draw |
| 1053 restore |
| 1054 |
| 1055 maybe each action should have an override slot |
| 1056 animations write to the slot |
| 1057 each element in display list then iterates overrides once the animations complet
e the frame |
| 1058 |
| 1059 so, first -- |
| 1060 active animations update the display list |
| 1061 |
| 1062 next -- |
| 1063 active animations install themselves in override slots |
| 1064 |
| 1065 finally |
| 1066 display list is iterated, calling override slots |
| 1067 |
| 1068 ---------------- |
| 1069 |
| 1070 svg: |
| 1071 display list is implicit |
| 1072 |
| 1073 active animations write element attributes |
| 1074 */ |
| 1075 |
| 1076 function EndAnimationSVG(animation, visibleFinished) { |
| 1077 switch (animation.attr) { |
| 1078 case "opacity": |
| 1079 animation.element.setAttribute(animation.attribute, animation.range[
1]); |
| 1080 if (animation.range[1] > 0) { |
| 1081 visibleFinished.push(animation); |
| 1082 } else { |
| 1083 RemoveFromArray(visibleFinished, animation.element); |
| 1084 } |
| 1085 break; |
| 1086 case "path": |
| 1087 var attrStr = animation.func(animation.range[1], animation.inParams)
; |
| 1088 animation.element.setAttribute(animation.attribute, attrStr); |
| 1089 break; |
| 1090 default: |
| 1091 debugger; |
| 1092 } |
| 1093 } |
| 1094 |
| 1095 function StepAnimationCanvas(animation, value) { |
| 1096 var endValue = animation.range[animation.range.length - 1]; |
| 1097 var interp = animation.range[0] + (endValue - animation.range[0]) * (1 - val
ue); |
| 1098 if (animation.firstStep) { |
| 1099 RemoveFromArray(visibleFinished, animation.element); |
| 1100 animation.firstStep = false; |
| 1101 } |
| 1102 var changeAlpha = "opacity" == animation.attr; |
| 1103 if (changeAlpha) { |
| 1104 ctx.save(); |
| 1105 ctx.globalAlpha = interp; |
| 1106 } |
| 1107 if (animation.func) { |
| 1108 animation.func(ctx, interp, animation.inParams); |
| 1109 } else { |
| 1110 animation.element.func(ctx); |
| 1111 } |
| 1112 if (changeAlpha) { |
| 1113 ctx.restore(); |
| 1114 } |
| 1115 } |
| 1116 |
| 1117 function StepAnimationSVG(animation, value) { |
| 1118 var interp = animation.range[0] + (animation.range[1] - animation.range[0])
* (1 - value); |
| 1119 switch (animation.attr) { |
| 1120 case "opacity": |
| 1121 animation.element.setAttribute(animation.attribute, interp); |
| 1122 break; |
| 1123 case "path": |
| 1124 var attrStr = animation.func(interp, animation.inParams); |
| 1125 animation.element.setAttribute(animation.attribute, attrStr); |
| 1126 break; |
| 1127 default: |
| 1128 debugger; |
| 1129 } |
| 1130 } |
| 1131 |
| 1132 var animate_frame = 0; |
| 1133 |
| 1134 function AnimateList(now) { |
| 1135 ++animate_frame; |
| 1136 if (animationState.paused) { |
| 1137 return; |
| 1138 } |
| 1139 if (animationState.start == null) { |
| 1140 animationState.start = now - animationState.time; |
| 1141 } |
| 1142 animationState.time = now - animationState.start; |
| 1143 var stillPending = []; |
| 1144 for (var index in animationsPending) { |
| 1145 var animation = animationsPending[index]; |
| 1146 var interval = animationState.time - animation.timing[0]; |
| 1147 if (interval <= 0) { |
| 1148 stillPending.push(animation); |
| 1149 continue; |
| 1150 } |
| 1151 animationsActive.push(animation); |
| 1152 var inList = false; |
| 1153 for (var dlIndex in displayList) { |
| 1154 var displayable = displayList[dlIndex]; |
| 1155 if (displayable == animation.element) { |
| 1156 inList = true; |
| 1157 break; |
| 1158 } |
| 1159 } |
| 1160 if (!inList) { |
| 1161 displayList.push(animation.element); |
| 1162 } |
| 1163 } |
| 1164 animationsPending = stillPending; |
| 1165 var stillAnimating = []; |
| 1166 if ('Canvas' == animationState.displayEngine) { |
| 1167 ctx.clearRect(0, 0, canvas.width, canvas.height); |
| 1168 // for (var index in visibleFinished) { |
| 1169 // var animation = visibleFinished[index]; |
| 1170 // animation.endAnimation = false; |
| 1171 // } |
| 1172 } |
| 1173 for (var index in animationsActive) { |
| 1174 var animation = animationsActive[index]; |
| 1175 var interval = animationState.time - animation.timing[0]; |
| 1176 animation.remaining = animation.duration > interval ? animation.duration
- interval : 0; |
| 1177 animation.endAnimation = animation.remaining <= 0; |
| 1178 if (animation.endAnimation) { |
| 1179 switch (animationState.displayEngine) { |
| 1180 case 'SVG': EndAnimationSVG(animation, visibleFinished); break; |
| 1181 case 'Canvas': EndAnimationCanvas(animation, visibleFinished); b
reak; |
| 1182 default: debugger; |
| 1183 } |
| 1184 continue; |
| 1185 } |
| 1186 var value = animation.remaining / animation.duration; |
| 1187 switch (animationState.displayEngine) { |
| 1188 case 'SVG': StepAnimationSVG(animation, value); break; |
| 1189 case 'Canvas': |
| 1190 if (!animation.firstElement || !animation.firstElement.endAnimat
ion) { |
| 1191 StepAnimationCanvas(animation, value); |
| 1192 } |
| 1193 break; |
| 1194 default: debugger; |
| 1195 } |
| 1196 stillAnimating.push(animation); |
| 1197 } |
| 1198 if ('Canvas' == animationState.displayEngine) { |
| 1199 for (var index in visibleFinished) { |
| 1200 var animation = visibleFinished[index]; |
| 1201 if (!animation.endAnimation) { |
| 1202 EndAnimationCanvas(animation, null); |
| 1203 } |
| 1204 } |
| 1205 } |
| 1206 animationsActive = stillAnimating; |
| 1207 if (animationsPending.length || animationsActive.length) { |
| 1208 animationState.requestID = requestAnimationFrame(AnimateList); |
| 1209 } |
| 1210 } |
| 1211 |
| 1212 function CancelAnimate(now) { |
| 1213 if (animationState.start == null) { |
| 1214 animationState.start = now; |
| 1215 } |
| 1216 var time = now - animationState.start; |
| 1217 var stillAnimating = []; |
| 1218 for (var index in animationsActive) { |
| 1219 var animation = animationsActive[index]; |
| 1220 var remaining = animation.remaining - time; |
| 1221 var value = remaining / animation.duration; |
| 1222 switch (animationState.displayEngine) { |
| 1223 case 'SVG': animation.element.setAttribute(animation.attribute, valu
e); break; |
| 1224 case 'Canvas': break; |
| 1225 } |
| 1226 if (remaining <= 0) { |
| 1227 continue; |
| 1228 } |
| 1229 stillAnimating.push(animation); |
| 1230 } |
| 1231 animationsActive = stillAnimating; |
| 1232 if (animationsActive.length) { |
| 1233 animationState.requestID = requestAnimationFrame(CancelAnimate); |
| 1234 return; |
| 1235 } |
| 1236 animationsPending = []; |
| 1237 animationState.reset(); |
| 1238 if (keyFrameQueue.length > 0) { |
| 1239 var animationFunc = keyFrameQueue.pop(); |
| 1240 animationFunc(); |
| 1241 } |
| 1242 } |
| 1243 |
| 1244 function CancelAnimation() { |
| 1245 cancelAnimationFrame(animationState.requestID); |
| 1246 for (var index in animationsActive) { |
| 1247 var animation = animationsActive[index]; |
| 1248 switch (animation.attr) { |
| 1249 case "opacity": |
| 1250 var tmp = animation.range[0]; animation.range[0] = animation.ran
ge[1]; animation[1] = tmp; |
| 1251 animation.remaining = animation.duration - animation.remaining; |
| 1252 animation.remaining /= animation.duration / 1000; |
| 1253 animation.duration = 1000; |
| 1254 break; |
| 1255 case "fadeOut": |
| 1256 RemoveFromArray(visibleFinished, animation.element); |
| 1257 break; |
| 1258 case "path": |
| 1259 break; |
| 1260 default: |
| 1261 debugger; |
| 1262 |
| 1263 } |
| 1264 } |
| 1265 for (var index in visibleFinished) { |
| 1266 var animation = visibleFinished[index]; |
| 1267 animation.action = "fadeOut"; |
| 1268 animation.remaining = animation.duration = 1000; |
| 1269 animationsActive.push(animation); |
| 1270 } |
| 1271 visibleFinished = []; |
| 1272 animationState.reset(); |
| 1273 animationState.requestID = requestAnimationFrame(CancelAnimate); |
| 1274 } |
| 1275 |
| 1276 function PauseAnimation() { |
| 1277 animationState.paused = true; |
| 1278 } |
| 1279 |
| 1280 function QueueAnimation(animationFunc) { |
| 1281 if (null == animationState.requestID) { |
| 1282 animationFunc(); |
| 1283 return; |
| 1284 } |
| 1285 keyFrameQueue.push(animationFunc); |
| 1286 } |
| 1287 |
| 1288 function UnpauseAnimation() { |
| 1289 animationState.paused = false; |
| 1290 animationState.start = performance.now() - animationState.time; |
| 1291 animationState.requestID = requestAnimationFrame(AnimateList); |
| 1292 } |
| 1293 |
| 1294 function SetupTextSVG(t, x, y) { |
| 1295 var text; |
| 1296 if (typeof t == "string") { |
| 1297 text = document.getElementById(t); |
| 1298 } else { |
| 1299 text = t; |
| 1300 } |
| 1301 text.setAttribute("font-family", "Helvetica,Arial"); |
| 1302 text.setAttribute("font-size", "1.3rem"); |
| 1303 if (typeof x == 'number') { |
| 1304 text.setAttribute("x", x); |
| 1305 } else if (null == text.getAttribute("x")) { |
| 1306 text.setAttribute("x", 400); |
| 1307 } |
| 1308 if (typeof y == 'number') { |
| 1309 text.setAttribute("y", y); |
| 1310 } else if (null == text.getAttribute("y")) { |
| 1311 text.setAttribute("y", 200); |
| 1312 } |
| 1313 } |
| 1314 |
| 1315 function SetupTextCanvas(t, x, y) { |
| 1316 var text = typeof t == 'string' ? t : t.id; |
| 1317 var record = canvasData[text]; |
| 1318 if (typeof x == 'number') { |
| 1319 record.x = x; |
| 1320 } |
| 1321 if (typeof y == 'number') { |
| 1322 record.y = y; |
| 1323 } |
| 1324 record.position = canvas_xy(record); |
| 1325 record.func = new Function('ctx', record.style + record.draw + record.positi
on); |
| 1326 } |
| 1327 |
| 1328 function SetupText(t, x, y) { |
| 1329 switch (animationState.displayEngine) { |
| 1330 case 'SVG': |
| 1331 SetupTextSVG(t, x, y); |
| 1332 break; |
| 1333 case 'Canvas': |
| 1334 SetupTextCanvas(t, x, y); |
| 1335 break; |
| 1336 default: |
| 1337 debugger; |
| 1338 } |
| 1339 } |
| 1340 |
| 1341 function FirstText(text) { |
| 1342 SetupText(text); |
| 1343 AnimationAdd([0, 1000], text); |
| 1344 } |
| 1345 |
| 1346 |
| 1347 function EngineInit(keyframe) { |
| 1348 displayList = []; |
| 1349 switch (animationState.displayEngine) { |
| 1350 case 'SVG': break; |
| 1351 case 'Canvas': CanvasInit(keyframe); break; |
| 1352 default: debugger; |
| 1353 } |
| 1354 } |
| 1355 |
| 1356 function EngineStart() { |
| 1357 switch (animationState.displayEngine) { |
| 1358 case 'SVG': break; |
| 1359 case 'Canvas': |
| 1360 // associate fadeIn and fadeOut |
| 1361 for (var outerIndex in animationsPending) { |
| 1362 var outer = animationsPending[outerIndex]; |
| 1363 for (var innerIndex in animationsPending) { |
| 1364 if (outerIndex == innerIndex) { |
| 1365 continue; |
| 1366 } |
| 1367 var inner = animationsPending[innerIndex]; |
| 1368 if (inner.element == outer.element) { |
| 1369 inner.firstElement = outer; |
| 1370 continue; |
| 1371 } |
| 1372 } |
| 1373 } |
| 1374 break; |
| 1375 default: debugger; |
| 1376 } |
| 1377 animationState.reset(); |
| 1378 animationState.requestID = requestAnimationFrame(AnimateList); |
| 1379 } |
| 1380 |
| 1381 function AnimateSpanWedge() { |
| 1382 EngineInit('keyframe1'); |
| 1383 FirstText(spanWedgeDesc); |
| 1384 AnimationAdd([1000, 2000], span1); |
| 1385 AnimationAdd([1500, 3000], wedge1); |
| 1386 AnimationAdd([3500, 4000], span1, [1, 0]); |
| 1387 AnimationAdd([3500, 4000], wedge1, [1, 0]); |
| 1388 AnimationAdd([4000, 5000], span2); |
| 1389 AnimationAdd([4500, 6000], wedge2); |
| 1390 AnimationAdd([6500, 7000], span2, [1, 0]); |
| 1391 AnimationAdd([6500, 7000], wedge2, [1, 0]); |
| 1392 AnimationAdd([7000, 8000], span3); |
| 1393 AnimationAdd([7500, 9000], wedge3); |
| 1394 EngineStart(); |
| 1395 } |
| 1396 |
| 1397 function AnimateTrivialWedge() { |
| 1398 EngineInit('keyframe2'); |
| 1399 FirstText(trivialWedgeDesc1); |
| 1400 FirstText(trivialWedgeDesc2); |
| 1401 AnimationAdd([2000, 3500], span4); |
| 1402 AnimationAdd([2000, 3500], wedge4); |
| 1403 AnimationAdd([2000, 3500], span5); |
| 1404 AnimationAdd([2000, 3500], wedge5); |
| 1405 AnimationAdd([2000, 3500], span6); |
| 1406 AnimationAdd([2000, 3500], wedge6); |
| 1407 EngineStart(); |
| 1408 } |
| 1409 |
| 1410 function AnimateSectorDesc() { |
| 1411 EngineInit('keyframe3'); |
| 1412 FirstText(sectorDesc1); |
| 1413 FirstText(sectorDesc2); |
| 1414 AnimationAdd([ 0, 1000], xaxis); |
| 1415 AnimationAdd([ 500, 1500], yaxis); |
| 1416 AnimationAdd([2000, 3500], sectorDescXYA); |
| 1417 AnimationAdd([2000, 3500], wedgeXY8); |
| 1418 AnimationAdd([3000, 4500], sectorDescXYB); |
| 1419 AnimationAdd([3000, 4500], wedgeXY6); |
| 1420 AnimationAdd([4000, 5500], sectorDescXYC); |
| 1421 AnimationAdd([4000, 5500], wedgeXY3); |
| 1422 EngineStart(); |
| 1423 } |
| 1424 |
| 1425 function AnimateLineSingle() { |
| 1426 EngineInit('keyframe4'); |
| 1427 FirstText(lineSingleDesc); |
| 1428 for (var i = 1; i <= 8; ++i) { |
| 1429 SetupText("sectorDescXY" + i, 500, 260); |
| 1430 } |
| 1431 AnimationAdd([ 0, 1000], xaxis); |
| 1432 AnimationAdd([ 0, 1000], yaxis); |
| 1433 AnimationAdd([1000, 2000], lineSegment); |
| 1434 AnimationAdd([1000, 3000], lineSegment, [-22.5 * Math.PI / 180], "path", eva
luate_at, |
| 1435 [ circle.center.x, circle.center.y, |
| 1436 circle.center.x + " + " + circle.radius + " * Math.cos(value)", |
| 1437 circle.center.y + " + " + circle.radius + " * Math.sin(value)", |
| 1438 ]); |
| 1439 AnimationAdd([2000, 3000], sectorDescXY1); |
| 1440 AnimationAdd([2000, 3000], wedgeXY1); |
| 1441 AnimationAdd([3000, 7000], lineSegment, [-22.5 * Math.PI / 180, (-22.5 - 360
) * Math.PI / 180], |
| 1442 "path", evaluate_at, |
| 1443 [ circle.center.x, circle.center.y, |
| 1444 circle.center.x + " + " + circle.radius + " * Math.cos(value)", |
| 1445 circle.center.y + " + " + circle.radius + " * Math.sin(value)", |
| 1446 ]); |
| 1447 for (var i = 1; i < 8; ++i) { |
| 1448 AnimationAdd([2500 + 500 * i, 3000 + 500 * i], "sectorDescXY" + (i + 1))
; |
| 1449 AnimationAdd([2500 + 500 * i, 3000 + 500 * i], "wedgeXY" + (i + 1)); |
| 1450 AnimationAdd([2500 + 500 * i, 3000 + 500 * i], "sectorDescXY" + i,
[1, 0]); |
| 1451 AnimationAdd([2500 + 500 * i, 3000 + 500 * i], "wedgeXY" + i,
[1, 0]); |
| 1452 } |
| 1453 AnimationAdd([2500 + 500 * 8, 3000 + 500 * 8], sectorDescXY1); |
| 1454 AnimationAdd([2500 + 500 * 8, 3000 + 500 * 8], wedgeXY1); |
| 1455 AnimationAdd([2500 + 500 * 8, 3000 + 500 * 8], sectorDescXY8, [1, 0]); |
| 1456 AnimationAdd([2500 + 500 * 8, 3000 + 500 * 8], wedgeXY8, [1, 0]); |
| 1457 EngineStart(); |
| 1458 } |
| 1459 |
| 1460 function AnimateCurveMultiple() { |
| 1461 EngineInit('keyframe5'); |
| 1462 var cubicStart = PathDataArray(curveSegment1); |
| 1463 var cubicMid = PathDataArray(curveSegment2); |
| 1464 var cubicEnd = PathDataArray(curveSegment3); |
| 1465 FirstText(curveMultipleDesc1); |
| 1466 FirstText(curveMultipleDesc2); |
| 1467 for (var i = 1; i <= 6; ++i) { |
| 1468 SetupText("sectorDescXY" + i, 500, 260 + i * 25); |
| 1469 } |
| 1470 AnimationAdd([ 0, 1000], xaxis); |
| 1471 AnimationAdd([ 0, 1000], yaxis); |
| 1472 AnimationAdd([1000, 2000], curveSegment); |
| 1473 AnimationAdd([2000, 3000], sectorDescXY1); |
| 1474 AnimationAdd([2000, 3000], wedgeXY1); |
| 1475 AnimationAdd([3000, 4000], curveSegment, [0, 1], "path", interpolate_at, [cu
bicStart, cubicMid]); |
| 1476 AnimationAdd([4000, 5000], sectorDescXY2); |
| 1477 AnimationAdd([4000, 5000], wedgeXY2); |
| 1478 AnimationAdd([5000, 6000], curveSegment, [0, 1], "path", interpolate_at, [cu
bicMid, cubicEnd]); |
| 1479 AnimationAdd([6000, 7000], sectorDescXY3); |
| 1480 AnimationAdd([6000, 7000], wedgeXY3); |
| 1481 AnimationAdd([6000, 7000], sectorDescXY4); |
| 1482 AnimationAdd([6000, 7000], wedgeXY4); |
| 1483 AnimationAdd([6000, 7000], sectorDescXY5); |
| 1484 AnimationAdd([6000, 7000], wedgeXY5); |
| 1485 AnimationAdd([6000, 7000], sectorDescXY6); |
| 1486 AnimationAdd([6000, 7000], wedgeXY6); |
| 1487 EngineStart(); |
| 1488 } |
| 1489 |
| 1490 function AnimateOneDLines() { |
| 1491 EngineInit('keyframe6'); |
| 1492 FirstText(line1DDest1); |
| 1493 FirstText(line1DDest2); |
| 1494 for (var i = 9; i <= 11; ++i) { |
| 1495 SetupText("sectorDescXY" + i, 500, 260 + (i - 8) * 25); |
| 1496 } |
| 1497 AnimationAdd([ 0, 1000], xaxis); |
| 1498 AnimationAdd([ 0, 1000], yaxis); |
| 1499 AnimationAdd([2000, 3000], sectorDescXY9); |
| 1500 AnimationAdd([2000, 3000], horzSegment); |
| 1501 AnimationAdd([3000, 4000], sectorDescXY10); |
| 1502 AnimationAdd([3000, 4000], vertSegment); |
| 1503 AnimationAdd([4000, 5000], sectorDescXY11); |
| 1504 AnimationAdd([4000, 5000], diagSegment); |
| 1505 EngineStart(); |
| 1506 } |
| 1507 |
| 1508 function AnimateDiverging() { |
| 1509 EngineInit('keyframe7'); |
| 1510 var cubicData = PathDataArray(cubicSegment2); |
| 1511 FirstText(curve1dDesc1); |
| 1512 FirstText(curve1dDesc2); |
| 1513 SetupText("sectorDescXY9", 500, 285); |
| 1514 SetupText("sectorDescXY1", 500, 320); |
| 1515 AnimationAdd([ 0, 1000], xaxis); |
| 1516 AnimationAdd([ 0, 1000], yaxis); |
| 1517 AnimationAdd([1900, 1900], cubicSegment); |
| 1518 AnimationAdd([2000, 3000], cubicSegment, [0, 1], "path", cubic_partial, cubi
cData); |
| 1519 AnimationAdd([2000, 3000], sectorDescXY9); |
| 1520 AnimationAdd([2000, 3000], horzSegment); |
| 1521 AnimationAdd([3000, 4000], sectorDescXY1); |
| 1522 AnimationAdd([3000, 4000], wedgeXY1); |
| 1523 EngineStart(); |
| 1524 } |
| 1525 |
| 1526 circle.animate = AnimateCircle; |
| 1527 circle.start = null; |
| 1528 |
| 1529 function AngleToPt(center, radius, degrees) { |
| 1530 var radians = degrees * Math.PI / 180.0; |
| 1531 return { |
| 1532 x: center.x + (radius * Math.cos(radians)), |
| 1533 y: center.y - (radius * Math.sin(radians)) |
| 1534 }; |
| 1535 } |
| 1536 |
| 1537 function PtsToSweep(pt1, pt2, center) { // unused |
| 1538 return { |
| 1539 start: 180 / Math.PI * Math.atan2(pt1.y - center.y, pt1.x - center.x), |
| 1540 end: 180 / Math.PI * Math.atan2(pt2.y - center.y, pt2.x - center.x) |
| 1541 }; |
| 1542 } |
| 1543 |
| 1544 |
| 1545 function ArcStr(center, radius, startAngle, endAngle) { |
| 1546 var endPt = AngleToPt(center, radius, endAngle); |
| 1547 var arcSweep = endAngle - startAngle <= 180 ? "0" : "1"; |
| 1548 return ["A", radius, radius, 0, arcSweep, 0, endPt.x, endPt.y].join(" "); |
| 1549 } |
| 1550 |
| 1551 function ArcStart(center, radius, startAngle, endAngle) { |
| 1552 var startPt = AngleToPt(center, radius, startAngle); |
| 1553 return [ startPt.x, startPt.y, ArcStr(center, radius, startAngle, endAngle)
].join(" "); |
| 1554 } |
| 1555 |
| 1556 function MakeArc(arcStart) { |
| 1557 return "M" + arcStart; |
| 1558 } |
| 1559 |
| 1560 function MakeWedge(center, arcStart) { |
| 1561 return ["M", center.x, center.y, "L", arcStart, "z"].join(" "); |
| 1562 } |
| 1563 |
| 1564 function Animate(path, now, dur) { |
| 1565 if (path.start == null) { |
| 1566 path.start = now; |
| 1567 // console.log("start=" + now); |
| 1568 } |
| 1569 if (now - path.start < dur) { |
| 1570 requestAnimationFrame(path.animate); |
| 1571 return true; |
| 1572 } |
| 1573 return false; |
| 1574 } |
| 1575 |
| 1576 function AnimateCircle(now) { |
| 1577 if (circle.start == null) { |
| 1578 circleFill.setAttribute("fill-opacity", "0.3"); |
| 1579 } |
| 1580 var dur = 2 * 1000; |
| 1581 var animating = Animate(circle, now, dur); |
| 1582 // console.log("now=" + now + "circle.start=" + circle.start ) |
| 1583 var pathStr = ArcStart(circle.center, circle.radius, 0, (now - circle.start)
/ (dur / 359.9)); |
| 1584 |
| 1585 circle.setAttribute("d", MakeArc(pathStr)); |
| 1586 circleFill.setAttribute("d", MakeWedge(circle.center, pathStr)); |
| 1587 if (!animating) { |
| 1588 var delay = dur - (now - circle.start); |
| 1589 setTimeout(CircleFinal, delay); |
| 1590 } |
| 1591 } |
| 1592 |
| 1593 function CircleFinal() { |
| 1594 var firstHalf = ArcStart(circle.center, circle.radius, 0, 180); |
| 1595 var secondHalf = ArcStr(circle.center, circle.radius, 180, 360); |
| 1596 circle.setAttribute("d", "M" + firstHalf + secondHalf + "z"); |
| 1597 circleFill.setAttribute("d", "M" + firstHalf + secondHalf + "z"); |
| 1598 } |
| 1599 |
| 1600 var svgNS = "http://www.w3.org/2000/svg"; |
| 1601 |
| 1602 function CreateTextLabels() |
| 1603 { |
| 1604 for (var i = 0; i < 32; ++i) { |
| 1605 var text = document.createElementNS(svgNS, "text"); |
| 1606 var pt = AngleToPt(circle.center, circle.radius + 80, i * 360 / 32); |
| 1607 text.setAttribute("id", "t" + i); |
| 1608 text.setAttribute("x", pt.x); |
| 1609 text.setAttribute("y", pt.y); |
| 1610 text.setAttribute("text-anchor", "middle"); |
| 1611 text.setAttribute("alignment-baseline", "mathematical"); |
| 1612 var textNode = document.createTextNode(i); |
| 1613 text.appendChild(textNode); |
| 1614 document.getElementById("svg").appendChild(text); |
| 1615 } |
| 1616 } |
| 1617 |
| 1618 // CreateTextLabels(); |
| 1619 |
| 1620 var keyframeArray = [ |
| 1621 AnimateSpanWedge, |
| 1622 AnimateTrivialWedge, |
| 1623 AnimateSectorDesc, |
| 1624 AnimateLineSingle, |
| 1625 AnimateCurveMultiple, |
| 1626 AnimateOneDLines, |
| 1627 AnimateDiverging, |
| 1628 ]; |
| 1629 |
| 1630 var keyframeIndex = 3; // keyframeArray.length - 1; // normally 0 ; set to debu
g a particular frame |
| 1631 |
| 1632 function QueueKeyframe() { |
| 1633 QueueAnimation(keyframeArray[keyframeIndex]); |
| 1634 if (keyframeIndex < keyframeArray.length - 1) { |
| 1635 ++keyframeIndex; |
| 1636 } |
| 1637 } |
| 1638 |
| 1639 var grads; |
| 1640 var paths; |
| 1641 var canvas; |
| 1642 var ctx; |
| 1643 |
| 1644 function canvasSetup() { |
| 1645 canvas = document.getElementById("canvas"); |
| 1646 ctx = canvas ? canvas.getContext("2d") : null; |
| 1647 assert(ctx); |
| 1648 var resScale = animationState.resScale = window.devicePixelRatio ? window.de
vicePixelRatio : 1; |
| 1649 var unscaledWidth = canvas.width; |
| 1650 var unscaledHeight = canvas.height; |
| 1651 canvas.width = unscaledWidth * resScale; |
| 1652 canvas.height = unscaledHeight * resScale; |
| 1653 canvas.style.width = unscaledWidth + 'px'; |
| 1654 canvas.style.height = unscaledHeight + 'px'; |
| 1655 if (resScale != 1) { |
| 1656 ctx.scale(resScale, resScale); |
| 1657 } |
| 1658 |
| 1659 grads = CanvasGrads(ctx); |
| 1660 paths = CanvasPaths(ctx); |
| 1661 } |
| 1662 |
| 1663 function Onload() { |
| 1664 canvasSetup(); |
| 1665 var startBtn = document.getElementById('startBtn'); |
| 1666 var stopBtn = document.getElementById('stopBtn'); |
| 1667 var resetBtn = document.getElementById('resetBtn'); |
| 1668 |
| 1669 startBtn.addEventListener('click', function(e) { |
| 1670 e.preventDefault(); |
| 1671 e.srcElement.innerText = "Next"; |
| 1672 CancelAnimation(); |
| 1673 QueueKeyframe(); |
| 1674 }); |
| 1675 |
| 1676 stopBtn.addEventListener('click', function(e) { |
| 1677 e.preventDefault(); |
| 1678 |
| 1679 if (!animationState.paused) { |
| 1680 PauseAnimation(); |
| 1681 e.srcElement.innerText = "Resume"; |
| 1682 } else { |
| 1683 UnpauseAnimation(); |
| 1684 e.srcElement.innerText = "Pause"; |
| 1685 } |
| 1686 }); |
| 1687 |
| 1688 resetBtn.addEventListener('click', function(e) { |
| 1689 e.preventDefault(); |
| 1690 CancelAnimation(); |
| 1691 keyframeIndex = 0; |
| 1692 startBtn.innerText = "Start"; |
| 1693 QueueKeyframe(); |
| 1694 }); |
| 1695 } |
| 1696 |
| 1697 </script> |
| 1698 |
| 1699 </head> |
| 1700 |
| 1701 <body onLoad="Onload()"> |
| 1702 |
| 1703 <div class="controls"> |
| 1704 <button type="button" id="startBtn">Start</button> |
| 1705 <button type="button" id="stopBtn">Pause</button> |
| 1706 <button type="button" id="resetBtn">Restart</button> |
| 1707 </div> |
| 1708 |
| 1709 <canvas id="canvas" width="800" height="500" /> |
| 1710 |
| 1711 </body> |
| 1712 </html> |
OLD | NEW |