toolkit/javascript/d3/src/core/timer.js
changeset 47 c0b4a8b5a012
equal deleted inserted replaced
46:efd9c589177a 47:c0b4a8b5a012
       
     1 var d3_timer_queue = null,
       
     2     d3_timer_interval, // is an interval (or frame) active?
       
     3     d3_timer_timeout; // is a timeout active?
       
     4 
       
     5 // The timer will continue to fire until callback returns true.
       
     6 d3.timer = function(callback, delay, then) {
       
     7   var found = false,
       
     8       t0,
       
     9       t1 = d3_timer_queue;
       
    10 
       
    11   if (arguments.length < 3) {
       
    12     if (arguments.length < 2) delay = 0;
       
    13     else if (!isFinite(delay)) return;
       
    14     then = Date.now();
       
    15   }
       
    16 
       
    17   // See if the callback's already in the queue.
       
    18   while (t1) {
       
    19     if (t1.callback === callback) {
       
    20       t1.then = then;
       
    21       t1.delay = delay;
       
    22       found = true;
       
    23       break;
       
    24     }
       
    25     t0 = t1;
       
    26     t1 = t1.next;
       
    27   }
       
    28 
       
    29   // Otherwise, add the callback to the queue.
       
    30   if (!found) d3_timer_queue = {
       
    31     callback: callback,
       
    32     then: then,
       
    33     delay: delay,
       
    34     next: d3_timer_queue
       
    35   };
       
    36 
       
    37   // Start animatin'!
       
    38   if (!d3_timer_interval) {
       
    39     d3_timer_timeout = clearTimeout(d3_timer_timeout);
       
    40     d3_timer_interval = 1;
       
    41     d3_timer_frame(d3_timer_step);
       
    42   }
       
    43 }
       
    44 
       
    45 function d3_timer_step() {
       
    46   var elapsed,
       
    47       now = Date.now(),
       
    48       t1 = d3_timer_queue;
       
    49 
       
    50   while (t1) {
       
    51     elapsed = now - t1.then;
       
    52     if (elapsed >= t1.delay) t1.flush = t1.callback(elapsed);
       
    53     t1 = t1.next;
       
    54   }
       
    55 
       
    56   var delay = d3_timer_flush() - now;
       
    57   if (delay > 24) {
       
    58     if (isFinite(delay)) {
       
    59       clearTimeout(d3_timer_timeout);
       
    60       d3_timer_timeout = setTimeout(d3_timer_step, delay);
       
    61     }
       
    62     d3_timer_interval = 0;
       
    63   } else {
       
    64     d3_timer_interval = 1;
       
    65     d3_timer_frame(d3_timer_step);
       
    66   }
       
    67 }
       
    68 
       
    69 d3.timer.flush = function() {
       
    70   var elapsed,
       
    71       now = Date.now(),
       
    72       t1 = d3_timer_queue;
       
    73 
       
    74   while (t1) {
       
    75     elapsed = now - t1.then;
       
    76     if (!t1.delay) t1.flush = t1.callback(elapsed);
       
    77     t1 = t1.next;
       
    78   }
       
    79 
       
    80   d3_timer_flush();
       
    81 };
       
    82 
       
    83 // Flush after callbacks, to avoid concurrent queue modification.
       
    84 function d3_timer_flush() {
       
    85   var t0 = null,
       
    86       t1 = d3_timer_queue,
       
    87       then = Infinity;
       
    88   while (t1) {
       
    89     if (t1.flush) {
       
    90       t1 = t0 ? t0.next = t1.next : d3_timer_queue = t1.next;
       
    91     } else {
       
    92       then = Math.min(then, t1.then + t1.delay);
       
    93       t1 = (t0 = t1).next;
       
    94     }
       
    95   }
       
    96   return then;
       
    97 }
       
    98 
       
    99 var d3_timer_frame = window.requestAnimationFrame
       
   100     || window.webkitRequestAnimationFrame
       
   101     || window.mozRequestAnimationFrame
       
   102     || window.oRequestAnimationFrame
       
   103     || window.msRequestAnimationFrame
       
   104     || function(callback) { setTimeout(callback, 17); };