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