|
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 ]; |