1 | package gov.va.med.edp.widget {
|
---|
2 |
|
---|
3 | import flash.events.TimerEvent;
|
---|
4 |
|
---|
5 | import flash.utils.Timer;
|
---|
6 |
|
---|
7 |
|
---|
8 |
|
---|
9 | import mx.core.UIComponent;
|
---|
10 |
|
---|
11 | import mx.events.FlexEvent;
|
---|
12 |
|
---|
13 | import mx.styles.CSSStyleDeclaration;
|
---|
14 |
|
---|
15 | import mx.styles.StyleManager;
|
---|
16 |
|
---|
17 |
|
---|
18 |
|
---|
19 |
|
---|
20 |
|
---|
21 | [Style(name="tickColor",type="uint",format="Color",inherit="no")]
|
---|
22 |
|
---|
23 | public class Spinner extends UIComponent {
|
---|
24 |
|
---|
25 | private static var STYLE_TICK_COLOR:String = "tickColor";
|
---|
26 |
|
---|
27 | private var tickColorChanged:Boolean;
|
---|
28 |
|
---|
29 |
|
---|
30 |
|
---|
31 | private static var classConstructed:Boolean = classConstruct();
|
---|
32 |
|
---|
33 |
|
---|
34 |
|
---|
35 | // Make sure we create the ticks the first time updateDisplayList is called
|
---|
36 |
|
---|
37 | private var creation:Boolean = true;
|
---|
38 |
|
---|
39 |
|
---|
40 |
|
---|
41 |
|
---|
42 |
|
---|
43 | private var fadeTimer:Timer;
|
---|
44 |
|
---|
45 | private var _isPlaying:Boolean;
|
---|
46 |
|
---|
47 |
|
---|
48 |
|
---|
49 | private var _numTicks:int = 12;
|
---|
50 |
|
---|
51 | private var numTicksChanged:Boolean;
|
---|
52 |
|
---|
53 |
|
---|
54 |
|
---|
55 | private var _size:Number = 30;
|
---|
56 |
|
---|
57 | private var sizeChanged:Boolean;
|
---|
58 |
|
---|
59 |
|
---|
60 |
|
---|
61 | private var _tickWidth:Number = 3;
|
---|
62 |
|
---|
63 | private var tickWidthChanged:Boolean;
|
---|
64 |
|
---|
65 |
|
---|
66 |
|
---|
67 | private var _speed:int = 1000;
|
---|
68 |
|
---|
69 | [Bindable] public var fadeSpeed:int = 600;
|
---|
70 |
|
---|
71 |
|
---|
72 |
|
---|
73 | public var autoPlay:Boolean = true;
|
---|
74 |
|
---|
75 |
|
---|
76 |
|
---|
77 |
|
---|
78 |
|
---|
79 | public function Spinner() {
|
---|
80 |
|
---|
81 | super();
|
---|
82 |
|
---|
83 |
|
---|
84 |
|
---|
85 | addEventListener(FlexEvent.CREATION_COMPLETE, handleCreationComplete);
|
---|
86 |
|
---|
87 | }
|
---|
88 |
|
---|
89 |
|
---|
90 |
|
---|
91 |
|
---|
92 |
|
---|
93 | private function handleCreationComplete(e:FlexEvent):void {
|
---|
94 |
|
---|
95 | removeEventListener(FlexEvent.CREATION_COMPLETE, handleCreationComplete);
|
---|
96 |
|
---|
97 | if (autoPlay) {
|
---|
98 |
|
---|
99 | play();
|
---|
100 |
|
---|
101 | }
|
---|
102 |
|
---|
103 | }
|
---|
104 |
|
---|
105 |
|
---|
106 |
|
---|
107 |
|
---|
108 |
|
---|
109 | /**
|
---|
110 |
|
---|
111 | * Set the height and width based on the size of the spinner. This should be more robust, but oh well.
|
---|
112 |
|
---|
113 | */
|
---|
114 |
|
---|
115 | override protected function measure():void {
|
---|
116 |
|
---|
117 | super.measure();
|
---|
118 |
|
---|
119 |
|
---|
120 |
|
---|
121 | width = _size;
|
---|
122 |
|
---|
123 | height = _size;
|
---|
124 |
|
---|
125 | }
|
---|
126 |
|
---|
127 |
|
---|
128 |
|
---|
129 |
|
---|
130 |
|
---|
131 | /**
|
---|
132 |
|
---|
133 | * Override the updateDisplayList method
|
---|
134 |
|
---|
135 | */
|
---|
136 |
|
---|
137 | override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
|
---|
138 |
|
---|
139 | if (tickColorChanged || numTicksChanged || sizeChanged || tickWidthChanged || creation) {
|
---|
140 |
|
---|
141 | creation = false;
|
---|
142 |
|
---|
143 | // Find out whether it's playing so we can restart it later if we need to
|
---|
144 |
|
---|
145 | var wasPlaying:Boolean = _isPlaying;
|
---|
146 |
|
---|
147 |
|
---|
148 |
|
---|
149 | // stop the spinning
|
---|
150 |
|
---|
151 | stop();
|
---|
152 |
|
---|
153 |
|
---|
154 |
|
---|
155 | // Remove all children
|
---|
156 |
|
---|
157 | for (var i:int = numChildren - 1; i >= 0; i--) {
|
---|
158 |
|
---|
159 | removeChildAt(i);
|
---|
160 |
|
---|
161 | }
|
---|
162 |
|
---|
163 |
|
---|
164 |
|
---|
165 | // Re-create the children
|
---|
166 |
|
---|
167 | var radius:Number = size / 2;
|
---|
168 |
|
---|
169 | var angle:Number = 2 * Math.PI / _numTicks; // The angle between each tick
|
---|
170 |
|
---|
171 | var tickWidth:Number = (_tickWidth != -1) ? _tickWidth : size / 10;
|
---|
172 |
|
---|
173 | var tickColor:uint = getStyle(STYLE_TICK_COLOR);
|
---|
174 |
|
---|
175 |
|
---|
176 |
|
---|
177 | var currentAngle:Number = 0;
|
---|
178 |
|
---|
179 | for (var j:int = 0; j < _numTicks; j++) {
|
---|
180 |
|
---|
181 |
|
---|
182 |
|
---|
183 | var xStart:Number = radius + Math.sin(currentAngle) * ((_numTicks + 2) * tickWidth / 2 / Math.PI);
|
---|
184 |
|
---|
185 | var yStart:Number = radius - Math.cos(currentAngle) * ((_numTicks + 2) * tickWidth / 2 / Math.PI);
|
---|
186 |
|
---|
187 | var xEnd:Number = radius + Math.sin(currentAngle) * (radius - tickWidth);
|
---|
188 |
|
---|
189 | var yEnd:Number = radius - Math.cos(currentAngle) * (radius - tickWidth);
|
---|
190 |
|
---|
191 |
|
---|
192 |
|
---|
193 | var t:Tick = new Tick(xStart, yStart, xEnd, yEnd, tickWidth, tickColor);
|
---|
194 |
|
---|
195 | t.alpha = 0.1;
|
---|
196 |
|
---|
197 |
|
---|
198 |
|
---|
199 | this.addChild(t);
|
---|
200 |
|
---|
201 |
|
---|
202 |
|
---|
203 | currentAngle += angle;
|
---|
204 |
|
---|
205 | }
|
---|
206 |
|
---|
207 |
|
---|
208 |
|
---|
209 | // Start the spinning again if it was playing when this function was called.
|
---|
210 |
|
---|
211 | if (wasPlaying) {
|
---|
212 |
|
---|
213 | play();
|
---|
214 |
|
---|
215 | }
|
---|
216 |
|
---|
217 |
|
---|
218 |
|
---|
219 | tickColorChanged = false;
|
---|
220 |
|
---|
221 | numTicksChanged = false;
|
---|
222 |
|
---|
223 | sizeChanged = false;
|
---|
224 |
|
---|
225 | tickWidthChanged = false;
|
---|
226 |
|
---|
227 | }
|
---|
228 |
|
---|
229 | }
|
---|
230 |
|
---|
231 |
|
---|
232 |
|
---|
233 |
|
---|
234 |
|
---|
235 | private static function classConstruct():Boolean {
|
---|
236 |
|
---|
237 | if (!StyleManager.getStyleDeclaration("Spinner")) {
|
---|
238 |
|
---|
239 | // If there is no CSS definition for StyledRectangle,
|
---|
240 |
|
---|
241 | // then create one and set the default value.
|
---|
242 |
|
---|
243 | var newStyleDeclaration:CSSStyleDeclaration = new CSSStyleDeclaration();
|
---|
244 |
|
---|
245 | newStyleDeclaration.setStyle(STYLE_TICK_COLOR, 0x000000);
|
---|
246 |
|
---|
247 | StyleManager.setStyleDeclaration("Spinner", newStyleDeclaration, true);
|
---|
248 |
|
---|
249 | }
|
---|
250 |
|
---|
251 | return true;
|
---|
252 |
|
---|
253 | }
|
---|
254 |
|
---|
255 |
|
---|
256 |
|
---|
257 | override public function styleChanged(styleProp:String):void {
|
---|
258 |
|
---|
259 | if (styleProp == STYLE_TICK_COLOR) {
|
---|
260 |
|
---|
261 | tickColorChanged = true;
|
---|
262 |
|
---|
263 | invalidateDisplayList();
|
---|
264 |
|
---|
265 | }
|
---|
266 |
|
---|
267 | }
|
---|
268 |
|
---|
269 |
|
---|
270 |
|
---|
271 |
|
---|
272 |
|
---|
273 | /**
|
---|
274 |
|
---|
275 | * Begin the circular fading of the ticks.
|
---|
276 |
|
---|
277 | */
|
---|
278 |
|
---|
279 | public function play():void {
|
---|
280 |
|
---|
281 | if (! _isPlaying) {
|
---|
282 |
|
---|
283 | fadeTimer = new Timer(speed / _numTicks, 0);
|
---|
284 |
|
---|
285 | // Anonymous functions are especially useful as simple event handlers
|
---|
286 |
|
---|
287 | fadeTimer.addEventListener(TimerEvent.TIMER, function (e:TimerEvent):void {
|
---|
288 |
|
---|
289 | var tickNum:int = int(fadeTimer.currentCount % _numTicks);
|
---|
290 |
|
---|
291 |
|
---|
292 |
|
---|
293 | if (numChildren > tickNum) {
|
---|
294 |
|
---|
295 | var tick:Tick = getChildAt(tickNum) as Tick;
|
---|
296 |
|
---|
297 | tick.fade(fadeSpeed != 1 ? fadeSpeed : speed * 6 / 10);
|
---|
298 |
|
---|
299 | }
|
---|
300 |
|
---|
301 | });
|
---|
302 |
|
---|
303 | fadeTimer.start();
|
---|
304 |
|
---|
305 | _isPlaying = true;
|
---|
306 |
|
---|
307 | }
|
---|
308 |
|
---|
309 | }
|
---|
310 |
|
---|
311 |
|
---|
312 |
|
---|
313 | /**
|
---|
314 |
|
---|
315 | * Stop the spinning.
|
---|
316 |
|
---|
317 | */
|
---|
318 |
|
---|
319 | public function stop():void {
|
---|
320 |
|
---|
321 | if (fadeTimer != null && fadeTimer.running) {
|
---|
322 |
|
---|
323 | _isPlaying = false;
|
---|
324 |
|
---|
325 | fadeTimer.stop();
|
---|
326 |
|
---|
327 | }
|
---|
328 |
|
---|
329 | }
|
---|
330 |
|
---|
331 |
|
---|
332 |
|
---|
333 | /**
|
---|
334 |
|
---|
335 | * The overall diameter of the spinner; also the height and width.
|
---|
336 |
|
---|
337 | */
|
---|
338 |
|
---|
339 | [Bindable]
|
---|
340 |
|
---|
341 | public function set size(value:Number):void {
|
---|
342 |
|
---|
343 | if (value != _size) {
|
---|
344 |
|
---|
345 | _size = value;
|
---|
346 |
|
---|
347 | sizeChanged = true;
|
---|
348 |
|
---|
349 | invalidateDisplayList();
|
---|
350 |
|
---|
351 | invalidateSize();
|
---|
352 |
|
---|
353 | }
|
---|
354 |
|
---|
355 | }
|
---|
356 |
|
---|
357 |
|
---|
358 |
|
---|
359 | public function get size():Number {
|
---|
360 |
|
---|
361 | return _size;
|
---|
362 |
|
---|
363 | }
|
---|
364 |
|
---|
365 |
|
---|
366 |
|
---|
367 | /**
|
---|
368 |
|
---|
369 | * The number of 'spokes' on the spinner.
|
---|
370 |
|
---|
371 | */
|
---|
372 |
|
---|
373 | [Bindable]
|
---|
374 |
|
---|
375 | public function set numTicks(value:int):void {
|
---|
376 |
|
---|
377 | if (value != _numTicks) {
|
---|
378 |
|
---|
379 | _numTicks = value;
|
---|
380 |
|
---|
381 | numTicksChanged = true;
|
---|
382 |
|
---|
383 | invalidateDisplayList();
|
---|
384 |
|
---|
385 | }
|
---|
386 |
|
---|
387 | }
|
---|
388 |
|
---|
389 |
|
---|
390 |
|
---|
391 | public function get numTicks():int {
|
---|
392 |
|
---|
393 | return _numTicks;
|
---|
394 |
|
---|
395 | }
|
---|
396 |
|
---|
397 |
|
---|
398 |
|
---|
399 | /**
|
---|
400 |
|
---|
401 | * The width of the 'spokes' on the spinner.
|
---|
402 |
|
---|
403 | */
|
---|
404 |
|
---|
405 | [Bindable]
|
---|
406 |
|
---|
407 | public function set tickWidth(value:int):void {
|
---|
408 |
|
---|
409 | if (value != _tickWidth) {
|
---|
410 |
|
---|
411 | _tickWidth = value;
|
---|
412 |
|
---|
413 | tickWidthChanged = true;
|
---|
414 |
|
---|
415 | invalidateDisplayList();
|
---|
416 |
|
---|
417 | }
|
---|
418 |
|
---|
419 | }
|
---|
420 |
|
---|
421 |
|
---|
422 |
|
---|
423 | public function get tickWidth():int {
|
---|
424 |
|
---|
425 | return _tickWidth;
|
---|
426 |
|
---|
427 | }
|
---|
428 |
|
---|
429 |
|
---|
430 |
|
---|
431 | /**
|
---|
432 |
|
---|
433 | * The duration (in milliseconds) that it takes for the spinner to make one revolution.
|
---|
434 |
|
---|
435 | */
|
---|
436 |
|
---|
437 | [Bindable]
|
---|
438 |
|
---|
439 | public function set speed(value:int):void {
|
---|
440 |
|
---|
441 | if (value != _speed) {
|
---|
442 |
|
---|
443 | _speed = value;
|
---|
444 |
|
---|
445 | fadeTimer.stop();
|
---|
446 |
|
---|
447 | fadeTimer.delay = value / _numTicks;
|
---|
448 |
|
---|
449 | fadeTimer.start();
|
---|
450 |
|
---|
451 | }
|
---|
452 |
|
---|
453 | }
|
---|
454 |
|
---|
455 |
|
---|
456 |
|
---|
457 | public function get speed():int {
|
---|
458 |
|
---|
459 | return _speed;
|
---|
460 |
|
---|
461 | }
|
---|
462 |
|
---|
463 |
|
---|
464 |
|
---|
465 |
|
---|
466 |
|
---|
467 | public function get isPlaying():Boolean {
|
---|
468 |
|
---|
469 | return _isPlaying;
|
---|
470 |
|
---|
471 | }
|
---|
472 |
|
---|
473 | }
|
---|
474 |
|
---|
475 | }
|
---|