OLD | NEW |
| (Empty) |
1 // | |
2 // Copyright 2014 Google Inc. All rights reserved. | |
3 // | |
4 // Use of this source code is governed by a BSD-style | |
5 // license that can be found in the LICENSE file or at | |
6 // https://developers.google.com/open-source/licenses/bsd | |
7 // | |
8 | |
9 /// A [window.requestAnimationFrame] based timer for use with transitions. | |
10 /// Uses [dart.async.Timer] when the time until next timeout is too long. | |
11 library charted.core.timer; | |
12 | |
13 import 'dart:async'; | |
14 import 'dart:html' show window; | |
15 import 'dart:collection'; | |
16 | |
17 typedef bool TimerCallback(int time); | |
18 | |
19 class AnimationTimer extends LinkedListEntry { | |
20 static LinkedList<AnimationTimer> _queue = new LinkedList<AnimationTimer>(); | |
21 | |
22 /// true if we are already waiting for window.animationFrame. At any given | |
23 /// time, only one of _timerScheduled and _animationFrameRequested are set | |
24 static bool _animationFrameRequested = false; | |
25 | |
26 /// Instance of currently scheduled timer. At any given time, only one | |
27 /// of _timerScheduled and _animationFrameRequested are set. | |
28 static Timer _timerScheduled; | |
29 | |
30 /// Currently active timer. | |
31 static AnimationTimer active; | |
32 | |
33 /// Callback function that is called when the timer is fired. | |
34 final TimerCallback callback; | |
35 | |
36 /// Start time of the animation. | |
37 final int time; | |
38 | |
39 /// Schedule a new [callback] to be called [delay] micro-seconds after | |
40 /// [then] micro-seconds since epoch. | |
41 AnimationTimer(this.callback, { int delay: 0, int then: null }) | |
42 : time = then == null | |
43 ? new DateTime.now().millisecondsSinceEpoch + delay | |
44 : then + delay { | |
45 _queue.add(this); | |
46 if (!_animationFrameRequested) { | |
47 if (_timerScheduled != null) { | |
48 _timerScheduled.cancel(); | |
49 } | |
50 _animationFrameRequested = true; | |
51 window.animationFrame.then(_step); | |
52 } | |
53 } | |
54 | |
55 /// Iterate through all timers, call the callbacks where necessary and | |
56 /// return milliseconds until next timer. | |
57 static int flush() { | |
58 int now = new DateTime.now().millisecondsSinceEpoch; | |
59 int earliest = null; | |
60 AnimationTimer timer = _queue.isEmpty ? null : _queue.first; | |
61 | |
62 while(timer != null) { | |
63 bool finished = false; | |
64 AnimationTimer ref = timer; | |
65 | |
66 if (now > timer.time) { | |
67 active = timer; | |
68 finished = timer.callback(now - timer.time); | |
69 } | |
70 if (!finished && (earliest == null || timer.time < earliest)) { | |
71 earliest = timer.time; | |
72 } | |
73 timer = timer.next; | |
74 if (finished) ref.unlink(); | |
75 } | |
76 active = null; | |
77 return earliest == null ? earliest : earliest - now; | |
78 } | |
79 | |
80 /// Internal timer and animation frame handler. | |
81 _step([_]) { | |
82 int delay = flush(); | |
83 | |
84 if (delay == null) { | |
85 _animationFrameRequested = false; | |
86 } | |
87 else if (delay > 24) { | |
88 if (_timerScheduled != null) { | |
89 _timerScheduled.cancel(); | |
90 } | |
91 _timerScheduled = new Timer(new Duration(milliseconds: delay), _step); | |
92 _animationFrameRequested = false; | |
93 } | |
94 else { | |
95 _animationFrameRequested = true; | |
96 window.animationFrame.then(_step); | |
97 } | |
98 } | |
99 } | |
OLD | NEW |