toolkit/javascript/d3/src/core/interpolate.js
changeset 47 c0b4a8b5a012
equal deleted inserted replaced
46:efd9c589177a 47:c0b4a8b5a012
       
     1 d3.interpolate = function(a, b) {
       
     2   var i = d3.interpolators.length, f;
       
     3   while (--i >= 0 && !(f = d3.interpolators[i](a, b)));
       
     4   return f;
       
     5 };
       
     6 
       
     7 d3.interpolateNumber = function(a, b) {
       
     8   b -= a;
       
     9   return function(t) { return a + b * t; };
       
    10 };
       
    11 
       
    12 d3.interpolateRound = function(a, b) {
       
    13   b -= a;
       
    14   return function(t) { return Math.round(a + b * t); };
       
    15 };
       
    16 
       
    17 d3.interpolateString = function(a, b) {
       
    18   var m, // current match
       
    19       i, // current index
       
    20       j, // current index (for coallescing)
       
    21       s0 = 0, // start index of current string prefix
       
    22       s1 = 0, // end index of current string prefix
       
    23       s = [], // string constants and placeholders
       
    24       q = [], // number interpolators
       
    25       n, // q.length
       
    26       o;
       
    27 
       
    28   // Reset our regular expression!
       
    29   d3_interpolate_number.lastIndex = 0;
       
    30 
       
    31   // Find all numbers in b.
       
    32   for (i = 0; m = d3_interpolate_number.exec(b); ++i) {
       
    33     if (m.index) s.push(b.substring(s0, s1 = m.index));
       
    34     q.push({i: s.length, x: m[0]});
       
    35     s.push(null);
       
    36     s0 = d3_interpolate_number.lastIndex;
       
    37   }
       
    38   if (s0 < b.length) s.push(b.substring(s0));
       
    39 
       
    40   // Find all numbers in a.
       
    41   for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) {
       
    42     o = q[i];
       
    43     if (o.x == m[0]) { // The numbers match, so coallesce.
       
    44       if (o.i) {
       
    45         if (s[o.i + 1] == null) { // This match is followed by another number.
       
    46           s[o.i - 1] += o.x;
       
    47           s.splice(o.i, 1);
       
    48           for (j = i + 1; j < n; ++j) q[j].i--;
       
    49         } else { // This match is followed by a string, so coallesce twice.
       
    50           s[o.i - 1] += o.x + s[o.i + 1];
       
    51           s.splice(o.i, 2);
       
    52           for (j = i + 1; j < n; ++j) q[j].i -= 2;
       
    53         }
       
    54       } else {
       
    55           if (s[o.i + 1] == null) { // This match is followed by another number.
       
    56           s[o.i] = o.x;
       
    57         } else { // This match is followed by a string, so coallesce twice.
       
    58           s[o.i] = o.x + s[o.i + 1];
       
    59           s.splice(o.i + 1, 1);
       
    60           for (j = i + 1; j < n; ++j) q[j].i--;
       
    61         }
       
    62       }
       
    63       q.splice(i, 1);
       
    64       n--;
       
    65       i--;
       
    66     } else {
       
    67       o.x = d3.interpolateNumber(parseFloat(m[0]), parseFloat(o.x));
       
    68     }
       
    69   }
       
    70 
       
    71   // Remove any numbers in b not found in a.
       
    72   while (i < n) {
       
    73     o = q.pop();
       
    74     if (s[o.i + 1] == null) { // This match is followed by another number.
       
    75       s[o.i] = o.x;
       
    76     } else { // This match is followed by a string, so coallesce twice.
       
    77       s[o.i] = o.x + s[o.i + 1];
       
    78       s.splice(o.i + 1, 1);
       
    79     }
       
    80     n--;
       
    81   }
       
    82 
       
    83   // Special optimization for only a single match.
       
    84   if (s.length === 1) {
       
    85     return s[0] == null ? q[0].x : function() { return b; };
       
    86   }
       
    87 
       
    88   // Otherwise, interpolate each of the numbers and rejoin the string.
       
    89   return function(t) {
       
    90     for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t);
       
    91     return s.join("");
       
    92   };
       
    93 };
       
    94 
       
    95 d3.interpolateTransform = function(a, b) {
       
    96   return d3.interpolateString(d3.transform(a) + "", d3.transform(b) + "");
       
    97 };
       
    98 
       
    99 d3.interpolateRgb = function(a, b) {
       
   100   a = d3.rgb(a);
       
   101   b = d3.rgb(b);
       
   102   var ar = a.r,
       
   103       ag = a.g,
       
   104       ab = a.b,
       
   105       br = b.r - ar,
       
   106       bg = b.g - ag,
       
   107       bb = b.b - ab;
       
   108   return function(t) {
       
   109     return "#"
       
   110         + d3_rgb_hex(Math.round(ar + br * t))
       
   111         + d3_rgb_hex(Math.round(ag + bg * t))
       
   112         + d3_rgb_hex(Math.round(ab + bb * t));
       
   113   };
       
   114 };
       
   115 
       
   116 // interpolates HSL space, but outputs RGB string (for compatibility)
       
   117 d3.interpolateHsl = function(a, b) {
       
   118   a = d3.hsl(a);
       
   119   b = d3.hsl(b);
       
   120   var h0 = a.h,
       
   121       s0 = a.s,
       
   122       l0 = a.l,
       
   123       h1 = b.h - h0,
       
   124       s1 = b.s - s0,
       
   125       l1 = b.l - l0;
       
   126   return function(t) {
       
   127     return d3_hsl_rgb(h0 + h1 * t, s0 + s1 * t, l0 + l1 * t).toString();
       
   128   };
       
   129 };
       
   130 
       
   131 d3.interpolateArray = function(a, b) {
       
   132   var x = [],
       
   133       c = [],
       
   134       na = a.length,
       
   135       nb = b.length,
       
   136       n0 = Math.min(a.length, b.length),
       
   137       i;
       
   138   for (i = 0; i < n0; ++i) x.push(d3.interpolate(a[i], b[i]));
       
   139   for (; i < na; ++i) c[i] = a[i];
       
   140   for (; i < nb; ++i) c[i] = b[i];
       
   141   return function(t) {
       
   142     for (i = 0; i < n0; ++i) c[i] = x[i](t);
       
   143     return c;
       
   144   };
       
   145 };
       
   146 
       
   147 d3.interpolateObject = function(a, b) {
       
   148   var i = {},
       
   149       c = {},
       
   150       k;
       
   151   for (k in a) {
       
   152     if (k in b) {
       
   153       i[k] = d3_interpolateByName(k)(a[k], b[k]);
       
   154     } else {
       
   155       c[k] = a[k];
       
   156     }
       
   157   }
       
   158   for (k in b) {
       
   159     if (!(k in a)) {
       
   160       c[k] = b[k];
       
   161     }
       
   162   }
       
   163   return function(t) {
       
   164     for (k in i) c[k] = i[k](t);
       
   165     return c;
       
   166   };
       
   167 }
       
   168 
       
   169 var d3_interpolate_number = /[-+]?(?:\d*\.?\d+)(?:[eE][-+]?\d+)?/g;
       
   170 
       
   171 function d3_interpolateByName(n) {
       
   172   return n == "transform"
       
   173       ? d3.interpolateTransform
       
   174       : d3.interpolate;
       
   175 }
       
   176 
       
   177 d3.interpolators = [
       
   178   d3.interpolateObject,
       
   179   function(a, b) { return (b instanceof Array) && d3.interpolateArray(a, b); },
       
   180   function(a, b) { return (typeof b === "string") && d3.interpolateString(a + "", b); },
       
   181   function(a, b) { return (typeof b === "string" ? b in d3_rgb_names || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Rgb || b instanceof d3_Hsl) && d3.interpolateRgb(a + "", b); },
       
   182   function(a, b) { return (typeof b === "number") && d3.interpolateNumber(+a, b); }
       
   183 ];