|
1 (function(){if (!Date.now) Date.now = function() { |
|
2 return +new Date; |
|
3 }; |
|
4 try { |
|
5 document.createElement("div").style.setProperty("opacity", 0, ""); |
|
6 } catch (error) { |
|
7 var d3_style_prototype = CSSStyleDeclaration.prototype, |
|
8 d3_style_setProperty = d3_style_prototype.setProperty; |
|
9 d3_style_prototype.setProperty = function(name, value, priority) { |
|
10 d3_style_setProperty.call(this, name, value + "", priority); |
|
11 }; |
|
12 } |
|
13 d3 = {version: "2.5.0"}; // semver |
|
14 var d3_array = d3_arraySlice; // conversion for NodeLists |
|
15 |
|
16 function d3_arrayCopy(pseudoarray) { |
|
17 var i = -1, n = pseudoarray.length, array = []; |
|
18 while (++i < n) array.push(pseudoarray[i]); |
|
19 return array; |
|
20 } |
|
21 |
|
22 function d3_arraySlice(pseudoarray) { |
|
23 return Array.prototype.slice.call(pseudoarray); |
|
24 } |
|
25 |
|
26 try { |
|
27 d3_array(document.documentElement.childNodes)[0].nodeType; |
|
28 } catch(e) { |
|
29 d3_array = d3_arrayCopy; |
|
30 } |
|
31 |
|
32 var d3_arraySubclass = [].__proto__? |
|
33 |
|
34 // Until ECMAScript supports array subclassing, prototype injection works well. |
|
35 function(array, prototype) { |
|
36 array.__proto__ = prototype; |
|
37 }: |
|
38 |
|
39 // And if your browser doesn't support __proto__, we'll use direct extension. |
|
40 function(array, prototype) { |
|
41 for (var property in prototype) array[property] = prototype[property]; |
|
42 }; |
|
43 function d3_this() { |
|
44 return this; |
|
45 } |
|
46 d3.functor = function(v) { |
|
47 return typeof v === "function" ? v : function() { return v; }; |
|
48 }; |
|
49 // A getter-setter method that preserves the appropriate `this` context. |
|
50 d3.rebind = function(object, method) { |
|
51 return function() { |
|
52 var x = method.apply(object, arguments); |
|
53 return arguments.length ? object : x; |
|
54 }; |
|
55 }; |
|
56 d3.ascending = function(a, b) { |
|
57 return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; |
|
58 }; |
|
59 d3.descending = function(a, b) { |
|
60 return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; |
|
61 }; |
|
62 d3.mean = function(array, f) { |
|
63 var n = array.length, |
|
64 a, |
|
65 m = 0, |
|
66 i = -1, |
|
67 j = 0; |
|
68 if (arguments.length === 1) { |
|
69 while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j; |
|
70 } else { |
|
71 while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j; |
|
72 } |
|
73 return j ? m : undefined; |
|
74 }; |
|
75 d3.median = function(array, f) { |
|
76 if (arguments.length > 1) array = array.map(f); |
|
77 array = array.filter(d3_number); |
|
78 return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined; |
|
79 }; |
|
80 d3.min = function(array, f) { |
|
81 var i = -1, |
|
82 n = array.length, |
|
83 a, |
|
84 b; |
|
85 if (arguments.length === 1) { |
|
86 while (++i < n && ((a = array[i]) == null || a != a)) a = undefined; |
|
87 while (++i < n) if ((b = array[i]) != null && a > b) a = b; |
|
88 } else { |
|
89 while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined; |
|
90 while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b; |
|
91 } |
|
92 return a; |
|
93 }; |
|
94 d3.max = function(array, f) { |
|
95 var i = -1, |
|
96 n = array.length, |
|
97 a, |
|
98 b; |
|
99 if (arguments.length === 1) { |
|
100 while (++i < n && ((a = array[i]) == null || a != a)) a = undefined; |
|
101 while (++i < n) if ((b = array[i]) != null && b > a) a = b; |
|
102 } else { |
|
103 while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined; |
|
104 while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b; |
|
105 } |
|
106 return a; |
|
107 }; |
|
108 d3.extent = function(array, f) { |
|
109 var i = -1, |
|
110 n = array.length, |
|
111 a, |
|
112 b, |
|
113 c; |
|
114 if (arguments.length === 1) { |
|
115 while (++i < n && ((a = c = array[i]) == null || a != a)) a = c = undefined; |
|
116 while (++i < n) if ((b = array[i]) != null) { |
|
117 if (a > b) a = b; |
|
118 if (c < b) c = b; |
|
119 } |
|
120 } else { |
|
121 while (++i < n && ((a = c = f.call(array, array[i], i)) == null || a != a)) a = undefined; |
|
122 while (++i < n) if ((b = f.call(array, array[i], i)) != null) { |
|
123 if (a > b) a = b; |
|
124 if (c < b) c = b; |
|
125 } |
|
126 } |
|
127 return [a, c]; |
|
128 }; |
|
129 d3.random = { |
|
130 normal: function(mean, deviation) { |
|
131 if (arguments.length < 2) deviation = 1; |
|
132 if (arguments.length < 1) mean = 0; |
|
133 return function() { |
|
134 var x, y, r; |
|
135 do { |
|
136 x = Math.random() * 2 - 1; |
|
137 y = Math.random() * 2 - 1; |
|
138 r = x * x + y * y; |
|
139 } while (!r || r > 1); |
|
140 return mean + deviation * x * Math.sqrt(-2 * Math.log(r) / r); |
|
141 }; |
|
142 } |
|
143 }; |
|
144 function d3_number(x) { |
|
145 return x != null && !isNaN(x); |
|
146 } |
|
147 d3.sum = function(array, f) { |
|
148 var s = 0, |
|
149 n = array.length, |
|
150 a, |
|
151 i = -1; |
|
152 |
|
153 if (arguments.length === 1) { |
|
154 while (++i < n) if (!isNaN(a = +array[i])) s += a; |
|
155 } else { |
|
156 while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a; |
|
157 } |
|
158 |
|
159 return s; |
|
160 }; |
|
161 // R-7 per <http://en.wikipedia.org/wiki/Quantile> |
|
162 d3.quantile = function(values, p) { |
|
163 var H = (values.length - 1) * p + 1, |
|
164 h = Math.floor(H), |
|
165 v = values[h - 1], |
|
166 e = H - h; |
|
167 return e ? v + e * (values[h] - v) : v; |
|
168 }; |
|
169 d3.zip = function() { |
|
170 if (!(n = arguments.length)) return []; |
|
171 for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m;) { |
|
172 for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n;) { |
|
173 zip[j] = arguments[j][i]; |
|
174 } |
|
175 } |
|
176 return zips; |
|
177 }; |
|
178 |
|
179 function d3_zipLength(d) { |
|
180 return d.length; |
|
181 } |
|
182 // Locate the insertion point for x in a to maintain sorted order. The |
|
183 // arguments lo and hi may be used to specify a subset of the array which should |
|
184 // be considered; by default the entire array is used. If x is already present |
|
185 // in a, the insertion point will be before (to the left of) any existing |
|
186 // entries. The return value is suitable for use as the first argument to |
|
187 // `array.splice` assuming that a is already sorted. |
|
188 // |
|
189 // The returned insertion point i partitions the array a into two halves so that |
|
190 // all v < x for v in a[lo:i] for the left side and all v >= x for v in a[i:hi] |
|
191 // for the right side. |
|
192 d3.bisectLeft = function(a, x, lo, hi) { |
|
193 if (arguments.length < 3) lo = 0; |
|
194 if (arguments.length < 4) hi = a.length; |
|
195 while (lo < hi) { |
|
196 var mid = (lo + hi) >> 1; |
|
197 if (a[mid] < x) lo = mid + 1; |
|
198 else hi = mid; |
|
199 } |
|
200 return lo; |
|
201 }; |
|
202 |
|
203 // Similar to bisectLeft, but returns an insertion point which comes after (to |
|
204 // the right of) any existing entries of x in a. |
|
205 // |
|
206 // The returned insertion point i partitions the array into two halves so that |
|
207 // all v <= x for v in a[lo:i] for the left side and all v > x for v in a[i:hi] |
|
208 // for the right side. |
|
209 d3.bisect = |
|
210 d3.bisectRight = function(a, x, lo, hi) { |
|
211 if (arguments.length < 3) lo = 0; |
|
212 if (arguments.length < 4) hi = a.length; |
|
213 while (lo < hi) { |
|
214 var mid = (lo + hi) >> 1; |
|
215 if (x < a[mid]) hi = mid; |
|
216 else lo = mid + 1; |
|
217 } |
|
218 return lo; |
|
219 }; |
|
220 d3.first = function(array, f) { |
|
221 var i = 0, |
|
222 n = array.length, |
|
223 a = array[0], |
|
224 b; |
|
225 if (arguments.length === 1) f = d3.ascending; |
|
226 while (++i < n) { |
|
227 if (f.call(array, a, b = array[i]) > 0) { |
|
228 a = b; |
|
229 } |
|
230 } |
|
231 return a; |
|
232 }; |
|
233 d3.last = function(array, f) { |
|
234 var i = 0, |
|
235 n = array.length, |
|
236 a = array[0], |
|
237 b; |
|
238 if (arguments.length === 1) f = d3.ascending; |
|
239 while (++i < n) { |
|
240 if (f.call(array, a, b = array[i]) <= 0) { |
|
241 a = b; |
|
242 } |
|
243 } |
|
244 return a; |
|
245 }; |
|
246 d3.nest = function() { |
|
247 var nest = {}, |
|
248 keys = [], |
|
249 sortKeys = [], |
|
250 sortValues, |
|
251 rollup; |
|
252 |
|
253 function map(array, depth) { |
|
254 if (depth >= keys.length) return rollup |
|
255 ? rollup.call(nest, array) : (sortValues |
|
256 ? array.sort(sortValues) |
|
257 : array); |
|
258 |
|
259 var i = -1, |
|
260 n = array.length, |
|
261 key = keys[depth++], |
|
262 keyValue, |
|
263 object, |
|
264 o = {}; |
|
265 |
|
266 while (++i < n) { |
|
267 if ((keyValue = key(object = array[i])) in o) { |
|
268 o[keyValue].push(object); |
|
269 } else { |
|
270 o[keyValue] = [object]; |
|
271 } |
|
272 } |
|
273 |
|
274 for (keyValue in o) { |
|
275 o[keyValue] = map(o[keyValue], depth); |
|
276 } |
|
277 |
|
278 return o; |
|
279 } |
|
280 |
|
281 function entries(map, depth) { |
|
282 if (depth >= keys.length) return map; |
|
283 |
|
284 var a = [], |
|
285 sortKey = sortKeys[depth++], |
|
286 key; |
|
287 |
|
288 for (key in map) { |
|
289 a.push({key: key, values: entries(map[key], depth)}); |
|
290 } |
|
291 |
|
292 if (sortKey) a.sort(function(a, b) { |
|
293 return sortKey(a.key, b.key); |
|
294 }); |
|
295 |
|
296 return a; |
|
297 } |
|
298 |
|
299 nest.map = function(array) { |
|
300 return map(array, 0); |
|
301 }; |
|
302 |
|
303 nest.entries = function(array) { |
|
304 return entries(map(array, 0), 0); |
|
305 }; |
|
306 |
|
307 nest.key = function(d) { |
|
308 keys.push(d); |
|
309 return nest; |
|
310 }; |
|
311 |
|
312 // Specifies the order for the most-recently specified key. |
|
313 // Note: only applies to entries. Map keys are unordered! |
|
314 nest.sortKeys = function(order) { |
|
315 sortKeys[keys.length - 1] = order; |
|
316 return nest; |
|
317 }; |
|
318 |
|
319 // Specifies the order for leaf values. |
|
320 // Applies to both maps and entries array. |
|
321 nest.sortValues = function(order) { |
|
322 sortValues = order; |
|
323 return nest; |
|
324 }; |
|
325 |
|
326 nest.rollup = function(f) { |
|
327 rollup = f; |
|
328 return nest; |
|
329 }; |
|
330 |
|
331 return nest; |
|
332 }; |
|
333 d3.keys = function(map) { |
|
334 var keys = []; |
|
335 for (var key in map) keys.push(key); |
|
336 return keys; |
|
337 }; |
|
338 d3.values = function(map) { |
|
339 var values = []; |
|
340 for (var key in map) values.push(map[key]); |
|
341 return values; |
|
342 }; |
|
343 d3.entries = function(map) { |
|
344 var entries = []; |
|
345 for (var key in map) entries.push({key: key, value: map[key]}); |
|
346 return entries; |
|
347 }; |
|
348 d3.permute = function(array, indexes) { |
|
349 var permutes = [], |
|
350 i = -1, |
|
351 n = indexes.length; |
|
352 while (++i < n) permutes[i] = array[indexes[i]]; |
|
353 return permutes; |
|
354 }; |
|
355 d3.merge = function(arrays) { |
|
356 return Array.prototype.concat.apply([], arrays); |
|
357 }; |
|
358 d3.split = function(array, f) { |
|
359 var arrays = [], |
|
360 values = [], |
|
361 value, |
|
362 i = -1, |
|
363 n = array.length; |
|
364 if (arguments.length < 2) f = d3_splitter; |
|
365 while (++i < n) { |
|
366 if (f.call(values, value = array[i], i)) { |
|
367 values = []; |
|
368 } else { |
|
369 if (!values.length) arrays.push(values); |
|
370 values.push(value); |
|
371 } |
|
372 } |
|
373 return arrays; |
|
374 }; |
|
375 |
|
376 function d3_splitter(d) { |
|
377 return d == null; |
|
378 } |
|
379 function d3_collapse(s) { |
|
380 return s.replace(/(^\s+)|(\s+$)/g, "").replace(/\s+/g, " "); |
|
381 } |
|
382 /** |
|
383 * @param {number} start |
|
384 * @param {number=} stop |
|
385 * @param {number=} step |
|
386 */ |
|
387 d3.range = function(start, stop, step) { |
|
388 if (arguments.length < 3) { |
|
389 step = 1; |
|
390 if (arguments.length < 2) { |
|
391 stop = start; |
|
392 start = 0; |
|
393 } |
|
394 } |
|
395 if ((stop - start) / step == Infinity) throw new Error("infinite range"); |
|
396 var range = [], |
|
397 i = -1, |
|
398 j; |
|
399 if (step < 0) while ((j = start + step * ++i) > stop) range.push(j); |
|
400 else while ((j = start + step * ++i) < stop) range.push(j); |
|
401 return range; |
|
402 }; |
|
403 d3.requote = function(s) { |
|
404 return s.replace(d3_requote_re, "\\$&"); |
|
405 }; |
|
406 |
|
407 var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g; |
|
408 d3.round = function(x, n) { |
|
409 return n |
|
410 ? Math.round(x * Math.pow(10, n)) * Math.pow(10, -n) |
|
411 : Math.round(x); |
|
412 }; |
|
413 d3.xhr = function(url, mime, callback) { |
|
414 var req = new XMLHttpRequest; |
|
415 if (arguments.length < 3) callback = mime; |
|
416 else if (mime && req.overrideMimeType) req.overrideMimeType(mime); |
|
417 req.open("GET", url, true); |
|
418 req.onreadystatechange = function() { |
|
419 if (req.readyState === 4) callback(req.status < 300 ? req : null); |
|
420 }; |
|
421 req.send(null); |
|
422 }; |
|
423 d3.text = function(url, mime, callback) { |
|
424 function ready(req) { |
|
425 callback(req && req.responseText); |
|
426 } |
|
427 if (arguments.length < 3) { |
|
428 callback = mime; |
|
429 mime = null; |
|
430 } |
|
431 d3.xhr(url, mime, ready); |
|
432 }; |
|
433 d3.json = function(url, callback) { |
|
434 d3.text(url, "application/json", function(text) { |
|
435 callback(text ? JSON.parse(text) : null); |
|
436 }); |
|
437 }; |
|
438 d3.html = function(url, callback) { |
|
439 d3.text(url, "text/html", function(text) { |
|
440 if (text != null) { // Treat empty string as valid HTML. |
|
441 var range = document.createRange(); |
|
442 range.selectNode(document.body); |
|
443 text = range.createContextualFragment(text); |
|
444 } |
|
445 callback(text); |
|
446 }); |
|
447 }; |
|
448 d3.xml = function(url, mime, callback) { |
|
449 function ready(req) { |
|
450 callback(req && req.responseXML); |
|
451 } |
|
452 if (arguments.length < 3) { |
|
453 callback = mime; |
|
454 mime = null; |
|
455 } |
|
456 d3.xhr(url, mime, ready); |
|
457 }; |
|
458 d3.ns = { |
|
459 |
|
460 prefix: { |
|
461 svg: "http://www.w3.org/2000/svg", |
|
462 xhtml: "http://www.w3.org/1999/xhtml", |
|
463 xlink: "http://www.w3.org/1999/xlink", |
|
464 xml: "http://www.w3.org/XML/1998/namespace", |
|
465 xmlns: "http://www.w3.org/2000/xmlns/" |
|
466 }, |
|
467 |
|
468 qualify: function(name) { |
|
469 var i = name.indexOf(":"); |
|
470 return i < 0 ? name : { |
|
471 space: d3.ns.prefix[name.substring(0, i)], |
|
472 local: name.substring(i + 1) |
|
473 }; |
|
474 } |
|
475 |
|
476 }; |
|
477 d3.dispatch = function() { |
|
478 var dispatch = new d3_dispatch(), |
|
479 i = -1, |
|
480 n = arguments.length; |
|
481 while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(); |
|
482 return dispatch; |
|
483 }; |
|
484 |
|
485 function d3_dispatch() {} |
|
486 |
|
487 d3_dispatch.prototype.on = function(type, listener) { |
|
488 var i = type.indexOf("."), |
|
489 name = ""; |
|
490 |
|
491 // Extract optional namespace, e.g., "click.foo" |
|
492 if (i > 0) { |
|
493 name = type.substring(i + 1); |
|
494 type = type.substring(0, i); |
|
495 } |
|
496 |
|
497 this[type].on(name, listener); |
|
498 }; |
|
499 |
|
500 function d3_dispatch_event() { |
|
501 var listeners = [], |
|
502 listenerByName = {}; |
|
503 |
|
504 function dispatch() { |
|
505 var z = listeners, // defensive reference |
|
506 i = -1, |
|
507 n = z.length, |
|
508 l; |
|
509 while (++i < n) if ((l = z[i])._on) l.apply(this, arguments); |
|
510 } |
|
511 |
|
512 dispatch.on = function(name, listener) { |
|
513 var l, i; |
|
514 |
|
515 // remove the old listener, if any |
|
516 if (l = listenerByName[name]) { |
|
517 l._on = false; |
|
518 listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1)); |
|
519 delete listenerByName[name]; |
|
520 } |
|
521 |
|
522 // add the new listener, if any |
|
523 if (listener) { |
|
524 listener._on = true; |
|
525 listeners.push(listener); |
|
526 listenerByName[name] = listener; |
|
527 } |
|
528 |
|
529 return dispatch; |
|
530 }; |
|
531 |
|
532 return dispatch; |
|
533 }; |
|
534 // TODO align |
|
535 d3.format = function(specifier) { |
|
536 var match = d3_format_re.exec(specifier), |
|
537 fill = match[1] || " ", |
|
538 sign = match[3] || "", |
|
539 zfill = match[5], |
|
540 width = +match[6], |
|
541 comma = match[7], |
|
542 precision = match[8], |
|
543 type = match[9], |
|
544 scale = 1, |
|
545 suffix = "", |
|
546 integer = false; |
|
547 |
|
548 if (precision) precision = +precision.substring(1); |
|
549 |
|
550 if (zfill) { |
|
551 fill = "0"; // TODO align = "="; |
|
552 if (comma) width -= Math.floor((width - 1) / 4); |
|
553 } |
|
554 |
|
555 switch (type) { |
|
556 case "n": comma = true; type = "g"; break; |
|
557 case "%": scale = 100; suffix = "%"; type = "f"; break; |
|
558 case "p": scale = 100; suffix = "%"; type = "r"; break; |
|
559 case "d": integer = true; precision = 0; break; |
|
560 case "s": scale = -1; type = "r"; break; |
|
561 } |
|
562 |
|
563 // If no precision is specified for r, fallback to general notation. |
|
564 if (type == "r" && !precision) type = "g"; |
|
565 |
|
566 type = d3_format_types[type] || d3_format_typeDefault; |
|
567 |
|
568 return function(value) { |
|
569 |
|
570 // Return the empty string for floats formatted as ints. |
|
571 if (integer && (value % 1)) return ""; |
|
572 |
|
573 // Convert negative to positive, and record the sign prefix. |
|
574 var negative = (value < 0) && (value = -value) ? "\u2212" : sign; |
|
575 |
|
576 // Apply the scale, computing it from the value's exponent for si format. |
|
577 if (scale < 0) { |
|
578 var prefix = d3.formatPrefix(value, precision); |
|
579 value *= prefix.scale; |
|
580 suffix = prefix.symbol; |
|
581 } else { |
|
582 value *= scale; |
|
583 } |
|
584 |
|
585 // Convert to the desired precision. |
|
586 value = type(value, precision); |
|
587 |
|
588 // If the fill character is 0, the sign and group is applied after the fill. |
|
589 if (zfill) { |
|
590 var length = value.length + negative.length; |
|
591 if (length < width) value = new Array(width - length + 1).join(fill) + value; |
|
592 if (comma) value = d3_format_group(value); |
|
593 value = negative + value; |
|
594 } |
|
595 |
|
596 // Otherwise (e.g., space-filling), the sign and group is applied before. |
|
597 else { |
|
598 if (comma) value = d3_format_group(value); |
|
599 value = negative + value; |
|
600 var length = value.length; |
|
601 if (length < width) value = new Array(width - length + 1).join(fill) + value; |
|
602 } |
|
603 |
|
604 return value + suffix; |
|
605 }; |
|
606 }; |
|
607 |
|
608 // [[fill]align][sign][#][0][width][,][.precision][type] |
|
609 var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/; |
|
610 |
|
611 var d3_format_types = { |
|
612 g: function(x, p) { return x.toPrecision(p); }, |
|
613 e: function(x, p) { return x.toExponential(p); }, |
|
614 f: function(x, p) { return x.toFixed(p); }, |
|
615 r: function(x, p) { return d3.round(x, p = d3_format_precision(x, p)).toFixed(Math.max(0, Math.min(20, p))); } |
|
616 }; |
|
617 |
|
618 function d3_format_precision(x, p) { |
|
619 return p - (x ? 1 + Math.floor(Math.log(x + Math.pow(10, 1 + Math.floor(Math.log(x) / Math.LN10) - p)) / Math.LN10) : 1); |
|
620 } |
|
621 |
|
622 function d3_format_typeDefault(x) { |
|
623 return x + ""; |
|
624 } |
|
625 |
|
626 // Apply comma grouping for thousands. |
|
627 function d3_format_group(value) { |
|
628 var i = value.lastIndexOf("."), |
|
629 f = i >= 0 ? value.substring(i) : (i = value.length, ""), |
|
630 t = []; |
|
631 while (i > 0) t.push(value.substring(i -= 3, i + 3)); |
|
632 return t.reverse().join(",") + f; |
|
633 } |
|
634 var d3_formatPrefixes = ["y","z","a","f","p","n","μ","m","","k","M","G","T","P","E","Z","Y"].map(d3_formatPrefix); |
|
635 |
|
636 d3.formatPrefix = function(value, precision) { |
|
637 var i = 0; |
|
638 if (value) { |
|
639 if (value < 0) value *= -1; |
|
640 if (precision) value = d3.round(value, d3_format_precision(value, precision)); |
|
641 i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10); |
|
642 i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3)); |
|
643 } |
|
644 return d3_formatPrefixes[8 + i / 3]; |
|
645 }; |
|
646 |
|
647 function d3_formatPrefix(d, i) { |
|
648 return { |
|
649 scale: Math.pow(10, (8 - i) * 3), |
|
650 symbol: d |
|
651 }; |
|
652 } |
|
653 |
|
654 /* |
|
655 * TERMS OF USE - EASING EQUATIONS |
|
656 * |
|
657 * Open source under the BSD License. |
|
658 * |
|
659 * Copyright 2001 Robert Penner |
|
660 * All rights reserved. |
|
661 * |
|
662 * Redistribution and use in source and binary forms, with or without |
|
663 * modification, are permitted provided that the following conditions are met: |
|
664 * |
|
665 * - Redistributions of source code must retain the above copyright notice, this |
|
666 * list of conditions and the following disclaimer. |
|
667 * |
|
668 * - Redistributions in binary form must reproduce the above copyright notice, |
|
669 * this list of conditions and the following disclaimer in the documentation |
|
670 * and/or other materials provided with the distribution. |
|
671 * |
|
672 * - Neither the name of the author nor the names of contributors may be used to |
|
673 * endorse or promote products derived from this software without specific |
|
674 * prior written permission. |
|
675 * |
|
676 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
677 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
678 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
679 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
|
680 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
681 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
682 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
683 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
684 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
685 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
686 * POSSIBILITY OF SUCH DAMAGE. |
|
687 */ |
|
688 |
|
689 var d3_ease_quad = d3_ease_poly(2), |
|
690 d3_ease_cubic = d3_ease_poly(3); |
|
691 |
|
692 var d3_ease = { |
|
693 linear: function() { return d3_ease_linear; }, |
|
694 poly: d3_ease_poly, |
|
695 quad: function() { return d3_ease_quad; }, |
|
696 cubic: function() { return d3_ease_cubic; }, |
|
697 sin: function() { return d3_ease_sin; }, |
|
698 exp: function() { return d3_ease_exp; }, |
|
699 circle: function() { return d3_ease_circle; }, |
|
700 elastic: d3_ease_elastic, |
|
701 back: d3_ease_back, |
|
702 bounce: function() { return d3_ease_bounce; } |
|
703 }; |
|
704 |
|
705 var d3_ease_mode = { |
|
706 "in": function(f) { return f; }, |
|
707 "out": d3_ease_reverse, |
|
708 "in-out": d3_ease_reflect, |
|
709 "out-in": function(f) { return d3_ease_reflect(d3_ease_reverse(f)); } |
|
710 }; |
|
711 |
|
712 d3.ease = function(name) { |
|
713 var i = name.indexOf("-"), |
|
714 t = i >= 0 ? name.substring(0, i) : name, |
|
715 m = i >= 0 ? name.substring(i + 1) : "in"; |
|
716 return d3_ease_clamp(d3_ease_mode[m](d3_ease[t].apply(null, Array.prototype.slice.call(arguments, 1)))); |
|
717 }; |
|
718 |
|
719 function d3_ease_clamp(f) { |
|
720 return function(t) { |
|
721 return t <= 0 ? 0 : t >= 1 ? 1 : f(t); |
|
722 }; |
|
723 } |
|
724 |
|
725 function d3_ease_reverse(f) { |
|
726 return function(t) { |
|
727 return 1 - f(1 - t); |
|
728 }; |
|
729 } |
|
730 |
|
731 function d3_ease_reflect(f) { |
|
732 return function(t) { |
|
733 return .5 * (t < .5 ? f(2 * t) : (2 - f(2 - 2 * t))); |
|
734 }; |
|
735 } |
|
736 |
|
737 function d3_ease_linear(t) { |
|
738 return t; |
|
739 } |
|
740 |
|
741 function d3_ease_poly(e) { |
|
742 return function(t) { |
|
743 return Math.pow(t, e); |
|
744 } |
|
745 } |
|
746 |
|
747 function d3_ease_sin(t) { |
|
748 return 1 - Math.cos(t * Math.PI / 2); |
|
749 } |
|
750 |
|
751 function d3_ease_exp(t) { |
|
752 return Math.pow(2, 10 * (t - 1)); |
|
753 } |
|
754 |
|
755 function d3_ease_circle(t) { |
|
756 return 1 - Math.sqrt(1 - t * t); |
|
757 } |
|
758 |
|
759 function d3_ease_elastic(a, p) { |
|
760 var s; |
|
761 if (arguments.length < 2) p = 0.45; |
|
762 if (arguments.length < 1) { a = 1; s = p / 4; } |
|
763 else s = p / (2 * Math.PI) * Math.asin(1 / a); |
|
764 return function(t) { |
|
765 return 1 + a * Math.pow(2, 10 * -t) * Math.sin((t - s) * 2 * Math.PI / p); |
|
766 }; |
|
767 } |
|
768 |
|
769 function d3_ease_back(s) { |
|
770 if (!s) s = 1.70158; |
|
771 return function(t) { |
|
772 return t * t * ((s + 1) * t - s); |
|
773 }; |
|
774 } |
|
775 |
|
776 function d3_ease_bounce(t) { |
|
777 return t < 1 / 2.75 ? 7.5625 * t * t |
|
778 : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 |
|
779 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 |
|
780 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375; |
|
781 } |
|
782 d3.event = null; |
|
783 |
|
784 function d3_eventCancel() { |
|
785 d3.event.stopPropagation(); |
|
786 d3.event.preventDefault(); |
|
787 } |
|
788 d3.interpolate = function(a, b) { |
|
789 var i = d3.interpolators.length, f; |
|
790 while (--i >= 0 && !(f = d3.interpolators[i](a, b))); |
|
791 return f; |
|
792 }; |
|
793 |
|
794 d3.interpolateNumber = function(a, b) { |
|
795 b -= a; |
|
796 return function(t) { return a + b * t; }; |
|
797 }; |
|
798 |
|
799 d3.interpolateRound = function(a, b) { |
|
800 b -= a; |
|
801 return function(t) { return Math.round(a + b * t); }; |
|
802 }; |
|
803 |
|
804 d3.interpolateString = function(a, b) { |
|
805 var m, // current match |
|
806 i, // current index |
|
807 j, // current index (for coallescing) |
|
808 s0 = 0, // start index of current string prefix |
|
809 s1 = 0, // end index of current string prefix |
|
810 s = [], // string constants and placeholders |
|
811 q = [], // number interpolators |
|
812 n, // q.length |
|
813 o; |
|
814 |
|
815 // Reset our regular expression! |
|
816 d3_interpolate_number.lastIndex = 0; |
|
817 |
|
818 // Find all numbers in b. |
|
819 for (i = 0; m = d3_interpolate_number.exec(b); ++i) { |
|
820 if (m.index) s.push(b.substring(s0, s1 = m.index)); |
|
821 q.push({i: s.length, x: m[0]}); |
|
822 s.push(null); |
|
823 s0 = d3_interpolate_number.lastIndex; |
|
824 } |
|
825 if (s0 < b.length) s.push(b.substring(s0)); |
|
826 |
|
827 // Find all numbers in a. |
|
828 for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) { |
|
829 o = q[i]; |
|
830 if (o.x == m[0]) { // The numbers match, so coallesce. |
|
831 if (o.i) { |
|
832 if (s[o.i + 1] == null) { // This match is followed by another number. |
|
833 s[o.i - 1] += o.x; |
|
834 s.splice(o.i, 1); |
|
835 for (j = i + 1; j < n; ++j) q[j].i--; |
|
836 } else { // This match is followed by a string, so coallesce twice. |
|
837 s[o.i - 1] += o.x + s[o.i + 1]; |
|
838 s.splice(o.i, 2); |
|
839 for (j = i + 1; j < n; ++j) q[j].i -= 2; |
|
840 } |
|
841 } else { |
|
842 if (s[o.i + 1] == null) { // This match is followed by another number. |
|
843 s[o.i] = o.x; |
|
844 } else { // This match is followed by a string, so coallesce twice. |
|
845 s[o.i] = o.x + s[o.i + 1]; |
|
846 s.splice(o.i + 1, 1); |
|
847 for (j = i + 1; j < n; ++j) q[j].i--; |
|
848 } |
|
849 } |
|
850 q.splice(i, 1); |
|
851 n--; |
|
852 i--; |
|
853 } else { |
|
854 o.x = d3.interpolateNumber(parseFloat(m[0]), parseFloat(o.x)); |
|
855 } |
|
856 } |
|
857 |
|
858 // Remove any numbers in b not found in a. |
|
859 while (i < n) { |
|
860 o = q.pop(); |
|
861 if (s[o.i + 1] == null) { // This match is followed by another number. |
|
862 s[o.i] = o.x; |
|
863 } else { // This match is followed by a string, so coallesce twice. |
|
864 s[o.i] = o.x + s[o.i + 1]; |
|
865 s.splice(o.i + 1, 1); |
|
866 } |
|
867 n--; |
|
868 } |
|
869 |
|
870 // Special optimization for only a single match. |
|
871 if (s.length === 1) { |
|
872 return s[0] == null ? q[0].x : function() { return b; }; |
|
873 } |
|
874 |
|
875 // Otherwise, interpolate each of the numbers and rejoin the string. |
|
876 return function(t) { |
|
877 for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t); |
|
878 return s.join(""); |
|
879 }; |
|
880 }; |
|
881 |
|
882 d3.interpolateTransform = function(a, b) { |
|
883 return d3.interpolateString(d3.transform(a) + "", d3.transform(b) + ""); |
|
884 }; |
|
885 |
|
886 d3.interpolateRgb = function(a, b) { |
|
887 a = d3.rgb(a); |
|
888 b = d3.rgb(b); |
|
889 var ar = a.r, |
|
890 ag = a.g, |
|
891 ab = a.b, |
|
892 br = b.r - ar, |
|
893 bg = b.g - ag, |
|
894 bb = b.b - ab; |
|
895 return function(t) { |
|
896 return "#" |
|
897 + d3_rgb_hex(Math.round(ar + br * t)) |
|
898 + d3_rgb_hex(Math.round(ag + bg * t)) |
|
899 + d3_rgb_hex(Math.round(ab + bb * t)); |
|
900 }; |
|
901 }; |
|
902 |
|
903 // interpolates HSL space, but outputs RGB string (for compatibility) |
|
904 d3.interpolateHsl = function(a, b) { |
|
905 a = d3.hsl(a); |
|
906 b = d3.hsl(b); |
|
907 var h0 = a.h, |
|
908 s0 = a.s, |
|
909 l0 = a.l, |
|
910 h1 = b.h - h0, |
|
911 s1 = b.s - s0, |
|
912 l1 = b.l - l0; |
|
913 return function(t) { |
|
914 return d3_hsl_rgb(h0 + h1 * t, s0 + s1 * t, l0 + l1 * t).toString(); |
|
915 }; |
|
916 }; |
|
917 |
|
918 d3.interpolateArray = function(a, b) { |
|
919 var x = [], |
|
920 c = [], |
|
921 na = a.length, |
|
922 nb = b.length, |
|
923 n0 = Math.min(a.length, b.length), |
|
924 i; |
|
925 for (i = 0; i < n0; ++i) x.push(d3.interpolate(a[i], b[i])); |
|
926 for (; i < na; ++i) c[i] = a[i]; |
|
927 for (; i < nb; ++i) c[i] = b[i]; |
|
928 return function(t) { |
|
929 for (i = 0; i < n0; ++i) c[i] = x[i](t); |
|
930 return c; |
|
931 }; |
|
932 }; |
|
933 |
|
934 d3.interpolateObject = function(a, b) { |
|
935 var i = {}, |
|
936 c = {}, |
|
937 k; |
|
938 for (k in a) { |
|
939 if (k in b) { |
|
940 i[k] = d3_interpolateByName(k)(a[k], b[k]); |
|
941 } else { |
|
942 c[k] = a[k]; |
|
943 } |
|
944 } |
|
945 for (k in b) { |
|
946 if (!(k in a)) { |
|
947 c[k] = b[k]; |
|
948 } |
|
949 } |
|
950 return function(t) { |
|
951 for (k in i) c[k] = i[k](t); |
|
952 return c; |
|
953 }; |
|
954 } |
|
955 |
|
956 var d3_interpolate_number = /[-+]?(?:\d*\.?\d+)(?:[eE][-+]?\d+)?/g; |
|
957 |
|
958 function d3_interpolateByName(n) { |
|
959 return n == "transform" |
|
960 ? d3.interpolateTransform |
|
961 : d3.interpolate; |
|
962 } |
|
963 |
|
964 d3.interpolators = [ |
|
965 d3.interpolateObject, |
|
966 function(a, b) { return (b instanceof Array) && d3.interpolateArray(a, b); }, |
|
967 function(a, b) { return (typeof b === "string") && d3.interpolateString(a + "", b); }, |
|
968 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); }, |
|
969 function(a, b) { return (typeof b === "number") && d3.interpolateNumber(+a, b); } |
|
970 ]; |
|
971 function d3_uninterpolateNumber(a, b) { |
|
972 b = b - (a = +a) ? 1 / (b - a) : 0; |
|
973 return function(x) { return (x - a) * b; }; |
|
974 } |
|
975 |
|
976 function d3_uninterpolateClamp(a, b) { |
|
977 b = b - (a = +a) ? 1 / (b - a) : 0; |
|
978 return function(x) { return Math.max(0, Math.min(1, (x - a) * b)); }; |
|
979 } |
|
980 d3.rgb = function(r, g, b) { |
|
981 return arguments.length === 1 |
|
982 ? (r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) |
|
983 : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb)) |
|
984 : d3_rgb(~~r, ~~g, ~~b); |
|
985 }; |
|
986 |
|
987 function d3_rgb(r, g, b) { |
|
988 return new d3_Rgb(r, g, b); |
|
989 } |
|
990 |
|
991 function d3_Rgb(r, g, b) { |
|
992 this.r = r; |
|
993 this.g = g; |
|
994 this.b = b; |
|
995 } |
|
996 |
|
997 d3_Rgb.prototype.brighter = function(k) { |
|
998 k = Math.pow(0.7, arguments.length ? k : 1); |
|
999 var r = this.r, |
|
1000 g = this.g, |
|
1001 b = this.b, |
|
1002 i = 30; |
|
1003 if (!r && !g && !b) return d3_rgb(i, i, i); |
|
1004 if (r && r < i) r = i; |
|
1005 if (g && g < i) g = i; |
|
1006 if (b && b < i) b = i; |
|
1007 return d3_rgb( |
|
1008 Math.min(255, Math.floor(r / k)), |
|
1009 Math.min(255, Math.floor(g / k)), |
|
1010 Math.min(255, Math.floor(b / k))); |
|
1011 }; |
|
1012 |
|
1013 d3_Rgb.prototype.darker = function(k) { |
|
1014 k = Math.pow(0.7, arguments.length ? k : 1); |
|
1015 return d3_rgb( |
|
1016 Math.floor(k * this.r), |
|
1017 Math.floor(k * this.g), |
|
1018 Math.floor(k * this.b)); |
|
1019 }; |
|
1020 |
|
1021 d3_Rgb.prototype.hsl = function() { |
|
1022 return d3_rgb_hsl(this.r, this.g, this.b); |
|
1023 }; |
|
1024 |
|
1025 d3_Rgb.prototype.toString = function() { |
|
1026 return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b); |
|
1027 }; |
|
1028 |
|
1029 function d3_rgb_hex(v) { |
|
1030 return v < 0x10 |
|
1031 ? "0" + Math.max(0, v).toString(16) |
|
1032 : Math.min(255, v).toString(16); |
|
1033 } |
|
1034 |
|
1035 function d3_rgb_parse(format, rgb, hsl) { |
|
1036 var r = 0, // red channel; int in [0, 255] |
|
1037 g = 0, // green channel; int in [0, 255] |
|
1038 b = 0, // blue channel; int in [0, 255] |
|
1039 m1, // CSS color specification match |
|
1040 m2, // CSS color specification type (e.g., rgb) |
|
1041 name; |
|
1042 |
|
1043 /* Handle hsl, rgb. */ |
|
1044 m1 = /([a-z]+)\((.*)\)/i.exec(format); |
|
1045 if (m1) { |
|
1046 m2 = m1[2].split(","); |
|
1047 switch (m1[1]) { |
|
1048 case "hsl": { |
|
1049 return hsl( |
|
1050 parseFloat(m2[0]), // degrees |
|
1051 parseFloat(m2[1]) / 100, // percentage |
|
1052 parseFloat(m2[2]) / 100 // percentage |
|
1053 ); |
|
1054 } |
|
1055 case "rgb": { |
|
1056 return rgb( |
|
1057 d3_rgb_parseNumber(m2[0]), |
|
1058 d3_rgb_parseNumber(m2[1]), |
|
1059 d3_rgb_parseNumber(m2[2]) |
|
1060 ); |
|
1061 } |
|
1062 } |
|
1063 } |
|
1064 |
|
1065 /* Named colors. */ |
|
1066 if (name = d3_rgb_names[format]) return rgb(name.r, name.g, name.b); |
|
1067 |
|
1068 /* Hexadecimal colors: #rgb and #rrggbb. */ |
|
1069 if (format != null && format.charAt(0) === "#") { |
|
1070 if (format.length === 4) { |
|
1071 r = format.charAt(1); r += r; |
|
1072 g = format.charAt(2); g += g; |
|
1073 b = format.charAt(3); b += b; |
|
1074 } else if (format.length === 7) { |
|
1075 r = format.substring(1, 3); |
|
1076 g = format.substring(3, 5); |
|
1077 b = format.substring(5, 7); |
|
1078 } |
|
1079 r = parseInt(r, 16); |
|
1080 g = parseInt(g, 16); |
|
1081 b = parseInt(b, 16); |
|
1082 } |
|
1083 |
|
1084 return rgb(r, g, b); |
|
1085 } |
|
1086 |
|
1087 function d3_rgb_hsl(r, g, b) { |
|
1088 var min = Math.min(r /= 255, g /= 255, b /= 255), |
|
1089 max = Math.max(r, g, b), |
|
1090 d = max - min, |
|
1091 h, |
|
1092 s, |
|
1093 l = (max + min) / 2; |
|
1094 if (d) { |
|
1095 s = l < .5 ? d / (max + min) : d / (2 - max - min); |
|
1096 if (r == max) h = (g - b) / d + (g < b ? 6 : 0); |
|
1097 else if (g == max) h = (b - r) / d + 2; |
|
1098 else h = (r - g) / d + 4; |
|
1099 h *= 60; |
|
1100 } else { |
|
1101 s = h = 0; |
|
1102 } |
|
1103 return d3_hsl(h, s, l); |
|
1104 } |
|
1105 |
|
1106 function d3_rgb_parseNumber(c) { // either integer or percentage |
|
1107 var f = parseFloat(c); |
|
1108 return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f; |
|
1109 } |
|
1110 |
|
1111 var d3_rgb_names = { |
|
1112 aliceblue: "#f0f8ff", |
|
1113 antiquewhite: "#faebd7", |
|
1114 aqua: "#00ffff", |
|
1115 aquamarine: "#7fffd4", |
|
1116 azure: "#f0ffff", |
|
1117 beige: "#f5f5dc", |
|
1118 bisque: "#ffe4c4", |
|
1119 black: "#000000", |
|
1120 blanchedalmond: "#ffebcd", |
|
1121 blue: "#0000ff", |
|
1122 blueviolet: "#8a2be2", |
|
1123 brown: "#a52a2a", |
|
1124 burlywood: "#deb887", |
|
1125 cadetblue: "#5f9ea0", |
|
1126 chartreuse: "#7fff00", |
|
1127 chocolate: "#d2691e", |
|
1128 coral: "#ff7f50", |
|
1129 cornflowerblue: "#6495ed", |
|
1130 cornsilk: "#fff8dc", |
|
1131 crimson: "#dc143c", |
|
1132 cyan: "#00ffff", |
|
1133 darkblue: "#00008b", |
|
1134 darkcyan: "#008b8b", |
|
1135 darkgoldenrod: "#b8860b", |
|
1136 darkgray: "#a9a9a9", |
|
1137 darkgreen: "#006400", |
|
1138 darkgrey: "#a9a9a9", |
|
1139 darkkhaki: "#bdb76b", |
|
1140 darkmagenta: "#8b008b", |
|
1141 darkolivegreen: "#556b2f", |
|
1142 darkorange: "#ff8c00", |
|
1143 darkorchid: "#9932cc", |
|
1144 darkred: "#8b0000", |
|
1145 darksalmon: "#e9967a", |
|
1146 darkseagreen: "#8fbc8f", |
|
1147 darkslateblue: "#483d8b", |
|
1148 darkslategray: "#2f4f4f", |
|
1149 darkslategrey: "#2f4f4f", |
|
1150 darkturquoise: "#00ced1", |
|
1151 darkviolet: "#9400d3", |
|
1152 deeppink: "#ff1493", |
|
1153 deepskyblue: "#00bfff", |
|
1154 dimgray: "#696969", |
|
1155 dimgrey: "#696969", |
|
1156 dodgerblue: "#1e90ff", |
|
1157 firebrick: "#b22222", |
|
1158 floralwhite: "#fffaf0", |
|
1159 forestgreen: "#228b22", |
|
1160 fuchsia: "#ff00ff", |
|
1161 gainsboro: "#dcdcdc", |
|
1162 ghostwhite: "#f8f8ff", |
|
1163 gold: "#ffd700", |
|
1164 goldenrod: "#daa520", |
|
1165 gray: "#808080", |
|
1166 green: "#008000", |
|
1167 greenyellow: "#adff2f", |
|
1168 grey: "#808080", |
|
1169 honeydew: "#f0fff0", |
|
1170 hotpink: "#ff69b4", |
|
1171 indianred: "#cd5c5c", |
|
1172 indigo: "#4b0082", |
|
1173 ivory: "#fffff0", |
|
1174 khaki: "#f0e68c", |
|
1175 lavender: "#e6e6fa", |
|
1176 lavenderblush: "#fff0f5", |
|
1177 lawngreen: "#7cfc00", |
|
1178 lemonchiffon: "#fffacd", |
|
1179 lightblue: "#add8e6", |
|
1180 lightcoral: "#f08080", |
|
1181 lightcyan: "#e0ffff", |
|
1182 lightgoldenrodyellow: "#fafad2", |
|
1183 lightgray: "#d3d3d3", |
|
1184 lightgreen: "#90ee90", |
|
1185 lightgrey: "#d3d3d3", |
|
1186 lightpink: "#ffb6c1", |
|
1187 lightsalmon: "#ffa07a", |
|
1188 lightseagreen: "#20b2aa", |
|
1189 lightskyblue: "#87cefa", |
|
1190 lightslategray: "#778899", |
|
1191 lightslategrey: "#778899", |
|
1192 lightsteelblue: "#b0c4de", |
|
1193 lightyellow: "#ffffe0", |
|
1194 lime: "#00ff00", |
|
1195 limegreen: "#32cd32", |
|
1196 linen: "#faf0e6", |
|
1197 magenta: "#ff00ff", |
|
1198 maroon: "#800000", |
|
1199 mediumaquamarine: "#66cdaa", |
|
1200 mediumblue: "#0000cd", |
|
1201 mediumorchid: "#ba55d3", |
|
1202 mediumpurple: "#9370db", |
|
1203 mediumseagreen: "#3cb371", |
|
1204 mediumslateblue: "#7b68ee", |
|
1205 mediumspringgreen: "#00fa9a", |
|
1206 mediumturquoise: "#48d1cc", |
|
1207 mediumvioletred: "#c71585", |
|
1208 midnightblue: "#191970", |
|
1209 mintcream: "#f5fffa", |
|
1210 mistyrose: "#ffe4e1", |
|
1211 moccasin: "#ffe4b5", |
|
1212 navajowhite: "#ffdead", |
|
1213 navy: "#000080", |
|
1214 oldlace: "#fdf5e6", |
|
1215 olive: "#808000", |
|
1216 olivedrab: "#6b8e23", |
|
1217 orange: "#ffa500", |
|
1218 orangered: "#ff4500", |
|
1219 orchid: "#da70d6", |
|
1220 palegoldenrod: "#eee8aa", |
|
1221 palegreen: "#98fb98", |
|
1222 paleturquoise: "#afeeee", |
|
1223 palevioletred: "#db7093", |
|
1224 papayawhip: "#ffefd5", |
|
1225 peachpuff: "#ffdab9", |
|
1226 peru: "#cd853f", |
|
1227 pink: "#ffc0cb", |
|
1228 plum: "#dda0dd", |
|
1229 powderblue: "#b0e0e6", |
|
1230 purple: "#800080", |
|
1231 red: "#ff0000", |
|
1232 rosybrown: "#bc8f8f", |
|
1233 royalblue: "#4169e1", |
|
1234 saddlebrown: "#8b4513", |
|
1235 salmon: "#fa8072", |
|
1236 sandybrown: "#f4a460", |
|
1237 seagreen: "#2e8b57", |
|
1238 seashell: "#fff5ee", |
|
1239 sienna: "#a0522d", |
|
1240 silver: "#c0c0c0", |
|
1241 skyblue: "#87ceeb", |
|
1242 slateblue: "#6a5acd", |
|
1243 slategray: "#708090", |
|
1244 slategrey: "#708090", |
|
1245 snow: "#fffafa", |
|
1246 springgreen: "#00ff7f", |
|
1247 steelblue: "#4682b4", |
|
1248 tan: "#d2b48c", |
|
1249 teal: "#008080", |
|
1250 thistle: "#d8bfd8", |
|
1251 tomato: "#ff6347", |
|
1252 turquoise: "#40e0d0", |
|
1253 violet: "#ee82ee", |
|
1254 wheat: "#f5deb3", |
|
1255 white: "#ffffff", |
|
1256 whitesmoke: "#f5f5f5", |
|
1257 yellow: "#ffff00", |
|
1258 yellowgreen: "#9acd32" |
|
1259 }; |
|
1260 |
|
1261 for (var d3_rgb_name in d3_rgb_names) { |
|
1262 d3_rgb_names[d3_rgb_name] = d3_rgb_parse( |
|
1263 d3_rgb_names[d3_rgb_name], |
|
1264 d3_rgb, |
|
1265 d3_hsl_rgb); |
|
1266 } |
|
1267 d3.hsl = function(h, s, l) { |
|
1268 return arguments.length === 1 |
|
1269 ? (h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) |
|
1270 : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl)) |
|
1271 : d3_hsl(+h, +s, +l); |
|
1272 }; |
|
1273 |
|
1274 function d3_hsl(h, s, l) { |
|
1275 return new d3_Hsl(h, s, l); |
|
1276 } |
|
1277 |
|
1278 function d3_Hsl(h, s, l) { |
|
1279 this.h = h; |
|
1280 this.s = s; |
|
1281 this.l = l; |
|
1282 } |
|
1283 |
|
1284 d3_Hsl.prototype.brighter = function(k) { |
|
1285 k = Math.pow(0.7, arguments.length ? k : 1); |
|
1286 return d3_hsl(this.h, this.s, this.l / k); |
|
1287 }; |
|
1288 |
|
1289 d3_Hsl.prototype.darker = function(k) { |
|
1290 k = Math.pow(0.7, arguments.length ? k : 1); |
|
1291 return d3_hsl(this.h, this.s, k * this.l); |
|
1292 }; |
|
1293 |
|
1294 d3_Hsl.prototype.rgb = function() { |
|
1295 return d3_hsl_rgb(this.h, this.s, this.l); |
|
1296 }; |
|
1297 |
|
1298 d3_Hsl.prototype.toString = function() { |
|
1299 return this.rgb().toString(); |
|
1300 }; |
|
1301 |
|
1302 function d3_hsl_rgb(h, s, l) { |
|
1303 var m1, |
|
1304 m2; |
|
1305 |
|
1306 /* Some simple corrections for h, s and l. */ |
|
1307 h = h % 360; if (h < 0) h += 360; |
|
1308 s = s < 0 ? 0 : s > 1 ? 1 : s; |
|
1309 l = l < 0 ? 0 : l > 1 ? 1 : l; |
|
1310 |
|
1311 /* From FvD 13.37, CSS Color Module Level 3 */ |
|
1312 m2 = l <= .5 ? l * (1 + s) : l + s - l * s; |
|
1313 m1 = 2 * l - m2; |
|
1314 |
|
1315 function v(h) { |
|
1316 if (h > 360) h -= 360; |
|
1317 else if (h < 0) h += 360; |
|
1318 if (h < 60) return m1 + (m2 - m1) * h / 60; |
|
1319 if (h < 180) return m2; |
|
1320 if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60; |
|
1321 return m1; |
|
1322 } |
|
1323 |
|
1324 function vv(h) { |
|
1325 return Math.round(v(h) * 255); |
|
1326 } |
|
1327 |
|
1328 return d3_rgb(vv(h + 120), vv(h), vv(h - 120)); |
|
1329 } |
|
1330 function d3_selection(groups) { |
|
1331 d3_arraySubclass(groups, d3_selectionPrototype); |
|
1332 return groups; |
|
1333 } |
|
1334 |
|
1335 var d3_select = function(s, n) { return n.querySelector(s); }, |
|
1336 d3_selectAll = function(s, n) { return n.querySelectorAll(s); }; |
|
1337 |
|
1338 // Prefer Sizzle, if available. |
|
1339 if (typeof Sizzle === "function") { |
|
1340 d3_select = function(s, n) { return Sizzle(s, n)[0]; }; |
|
1341 d3_selectAll = function(s, n) { return Sizzle.uniqueSort(Sizzle(s, n)); }; |
|
1342 } |
|
1343 |
|
1344 var d3_selectionPrototype = []; |
|
1345 |
|
1346 d3.selection = function() { |
|
1347 return d3_selectionRoot; |
|
1348 }; |
|
1349 |
|
1350 d3.selection.prototype = d3_selectionPrototype; |
|
1351 d3_selectionPrototype.select = function(selector) { |
|
1352 var subgroups = [], |
|
1353 subgroup, |
|
1354 subnode, |
|
1355 group, |
|
1356 node; |
|
1357 |
|
1358 if (typeof selector !== "function") selector = d3_selection_selector(selector); |
|
1359 |
|
1360 for (var j = -1, m = this.length; ++j < m;) { |
|
1361 subgroups.push(subgroup = []); |
|
1362 subgroup.parentNode = (group = this[j]).parentNode; |
|
1363 for (var i = -1, n = group.length; ++i < n;) { |
|
1364 if (node = group[i]) { |
|
1365 subgroup.push(subnode = selector.call(node, node.__data__, i)); |
|
1366 if (subnode && "__data__" in node) subnode.__data__ = node.__data__; |
|
1367 } else { |
|
1368 subgroup.push(null); |
|
1369 } |
|
1370 } |
|
1371 } |
|
1372 |
|
1373 return d3_selection(subgroups); |
|
1374 }; |
|
1375 |
|
1376 function d3_selection_selector(selector) { |
|
1377 return function() { |
|
1378 return d3_select(selector, this); |
|
1379 }; |
|
1380 } |
|
1381 d3_selectionPrototype.selectAll = function(selector) { |
|
1382 var subgroups = [], |
|
1383 subgroup, |
|
1384 node; |
|
1385 |
|
1386 if (typeof selector !== "function") selector = d3_selection_selectorAll(selector); |
|
1387 |
|
1388 for (var j = -1, m = this.length; ++j < m;) { |
|
1389 for (var group = this[j], i = -1, n = group.length; ++i < n;) { |
|
1390 if (node = group[i]) { |
|
1391 subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i))); |
|
1392 subgroup.parentNode = node; |
|
1393 } |
|
1394 } |
|
1395 } |
|
1396 |
|
1397 return d3_selection(subgroups); |
|
1398 }; |
|
1399 |
|
1400 function d3_selection_selectorAll(selector) { |
|
1401 return function() { |
|
1402 return d3_selectAll(selector, this); |
|
1403 }; |
|
1404 } |
|
1405 d3_selectionPrototype.attr = function(name, value) { |
|
1406 name = d3.ns.qualify(name); |
|
1407 |
|
1408 // If no value is specified, return the first value. |
|
1409 if (arguments.length < 2) { |
|
1410 var node = this.node(); |
|
1411 return name.local |
|
1412 ? node.getAttributeNS(name.space, name.local) |
|
1413 : node.getAttribute(name); |
|
1414 } |
|
1415 |
|
1416 function attrNull() { |
|
1417 this.removeAttribute(name); |
|
1418 } |
|
1419 |
|
1420 function attrNullNS() { |
|
1421 this.removeAttributeNS(name.space, name.local); |
|
1422 } |
|
1423 |
|
1424 function attrConstant() { |
|
1425 this.setAttribute(name, value); |
|
1426 } |
|
1427 |
|
1428 function attrConstantNS() { |
|
1429 this.setAttributeNS(name.space, name.local, value); |
|
1430 } |
|
1431 |
|
1432 function attrFunction() { |
|
1433 var x = value.apply(this, arguments); |
|
1434 if (x == null) this.removeAttribute(name); |
|
1435 else this.setAttribute(name, x); |
|
1436 } |
|
1437 |
|
1438 function attrFunctionNS() { |
|
1439 var x = value.apply(this, arguments); |
|
1440 if (x == null) this.removeAttributeNS(name.space, name.local); |
|
1441 else this.setAttributeNS(name.space, name.local, x); |
|
1442 } |
|
1443 |
|
1444 return this.each(value == null |
|
1445 ? (name.local ? attrNullNS : attrNull) : (typeof value === "function" |
|
1446 ? (name.local ? attrFunctionNS : attrFunction) |
|
1447 : (name.local ? attrConstantNS : attrConstant))); |
|
1448 }; |
|
1449 d3_selectionPrototype.classed = function(name, value) { |
|
1450 var names = name.split(d3_selection_classedWhitespace), |
|
1451 n = names.length, |
|
1452 i = -1; |
|
1453 if (arguments.length > 1) { |
|
1454 while (++i < n) d3_selection_classed.call(this, names[i], value); |
|
1455 return this; |
|
1456 } else { |
|
1457 while (++i < n) if (!d3_selection_classed.call(this, names[i])) return false; |
|
1458 return true; |
|
1459 } |
|
1460 }; |
|
1461 |
|
1462 var d3_selection_classedWhitespace = /\s+/g; |
|
1463 |
|
1464 function d3_selection_classed(name, value) { |
|
1465 var re = new RegExp("(^|\\s+)" + d3.requote(name) + "(\\s+|$)", "g"); |
|
1466 |
|
1467 // If no value is specified, return the first value. |
|
1468 if (arguments.length < 2) { |
|
1469 var node = this.node(); |
|
1470 if (c = node.classList) return c.contains(name); |
|
1471 var c = node.className; |
|
1472 re.lastIndex = 0; |
|
1473 return re.test(c.baseVal != null ? c.baseVal : c); |
|
1474 } |
|
1475 |
|
1476 function classedAdd() { |
|
1477 if (c = this.classList) return c.add(name); |
|
1478 var c = this.className, |
|
1479 cb = c.baseVal != null, |
|
1480 cv = cb ? c.baseVal : c; |
|
1481 re.lastIndex = 0; |
|
1482 if (!re.test(cv)) { |
|
1483 cv = d3_collapse(cv + " " + name); |
|
1484 if (cb) c.baseVal = cv; |
|
1485 else this.className = cv; |
|
1486 } |
|
1487 } |
|
1488 |
|
1489 function classedRemove() { |
|
1490 if (c = this.classList) return c.remove(name); |
|
1491 var c = this.className, |
|
1492 cb = c.baseVal != null, |
|
1493 cv = cb ? c.baseVal : c; |
|
1494 cv = d3_collapse(cv.replace(re, " ")); |
|
1495 if (cb) c.baseVal = cv; |
|
1496 else this.className = cv; |
|
1497 } |
|
1498 |
|
1499 function classedFunction() { |
|
1500 (value.apply(this, arguments) |
|
1501 ? classedAdd |
|
1502 : classedRemove).call(this); |
|
1503 } |
|
1504 |
|
1505 return this.each(typeof value === "function" |
|
1506 ? classedFunction : value |
|
1507 ? classedAdd |
|
1508 : classedRemove); |
|
1509 } |
|
1510 d3_selectionPrototype.style = function(name, value, priority) { |
|
1511 if (arguments.length < 3) priority = ""; |
|
1512 |
|
1513 // If no value is specified, return the first value. |
|
1514 if (arguments.length < 2) return window |
|
1515 .getComputedStyle(this.node(), null) |
|
1516 .getPropertyValue(name); |
|
1517 |
|
1518 function styleNull() { |
|
1519 this.style.removeProperty(name); |
|
1520 } |
|
1521 |
|
1522 function styleConstant() { |
|
1523 this.style.setProperty(name, value, priority); |
|
1524 } |
|
1525 |
|
1526 function styleFunction() { |
|
1527 var x = value.apply(this, arguments); |
|
1528 if (x == null) this.style.removeProperty(name); |
|
1529 else this.style.setProperty(name, x, priority); |
|
1530 } |
|
1531 |
|
1532 return this.each(value == null |
|
1533 ? styleNull : (typeof value === "function" |
|
1534 ? styleFunction : styleConstant)); |
|
1535 }; |
|
1536 d3_selectionPrototype.property = function(name, value) { |
|
1537 |
|
1538 // If no value is specified, return the first value. |
|
1539 if (arguments.length < 2) return this.node()[name]; |
|
1540 |
|
1541 function propertyNull() { |
|
1542 delete this[name]; |
|
1543 } |
|
1544 |
|
1545 function propertyConstant() { |
|
1546 this[name] = value; |
|
1547 } |
|
1548 |
|
1549 function propertyFunction() { |
|
1550 var x = value.apply(this, arguments); |
|
1551 if (x == null) delete this[name]; |
|
1552 else this[name] = x; |
|
1553 } |
|
1554 |
|
1555 return this.each(value == null |
|
1556 ? propertyNull : (typeof value === "function" |
|
1557 ? propertyFunction : propertyConstant)); |
|
1558 }; |
|
1559 d3_selectionPrototype.text = function(value) { |
|
1560 return arguments.length < 1 ? this.node().textContent |
|
1561 : (this.each(typeof value === "function" |
|
1562 ? function() { this.textContent = value.apply(this, arguments); } |
|
1563 : function() { this.textContent = value; })); |
|
1564 }; |
|
1565 d3_selectionPrototype.html = function(value) { |
|
1566 return arguments.length < 1 ? this.node().innerHTML |
|
1567 : (this.each(typeof value === "function" |
|
1568 ? function() { this.innerHTML = value.apply(this, arguments); } |
|
1569 : function() { this.innerHTML = value; })); |
|
1570 }; |
|
1571 // TODO append(node)? |
|
1572 // TODO append(function)? |
|
1573 d3_selectionPrototype.append = function(name) { |
|
1574 name = d3.ns.qualify(name); |
|
1575 |
|
1576 function append() { |
|
1577 return this.appendChild(document.createElement(name)); |
|
1578 } |
|
1579 |
|
1580 function appendNS() { |
|
1581 return this.appendChild(document.createElementNS(name.space, name.local)); |
|
1582 } |
|
1583 |
|
1584 return this.select(name.local ? appendNS : append); |
|
1585 }; |
|
1586 // TODO insert(node, function)? |
|
1587 // TODO insert(function, string)? |
|
1588 // TODO insert(function, function)? |
|
1589 d3_selectionPrototype.insert = function(name, before) { |
|
1590 name = d3.ns.qualify(name); |
|
1591 |
|
1592 function insert() { |
|
1593 return this.insertBefore( |
|
1594 document.createElement(name), |
|
1595 d3_select(before, this)); |
|
1596 } |
|
1597 |
|
1598 function insertNS() { |
|
1599 return this.insertBefore( |
|
1600 document.createElementNS(name.space, name.local), |
|
1601 d3_select(before, this)); |
|
1602 } |
|
1603 |
|
1604 return this.select(name.local ? insertNS : insert); |
|
1605 }; |
|
1606 // TODO remove(selector)? |
|
1607 // TODO remove(node)? |
|
1608 // TODO remove(function)? |
|
1609 d3_selectionPrototype.remove = function() { |
|
1610 return this.each(function() { |
|
1611 var parent = this.parentNode; |
|
1612 if (parent) parent.removeChild(this); |
|
1613 }); |
|
1614 }; |
|
1615 // TODO data(null) for clearing data? |
|
1616 d3_selectionPrototype.data = function(data, join) { |
|
1617 var enter = [], |
|
1618 update = [], |
|
1619 exit = []; |
|
1620 |
|
1621 function bind(group, groupData) { |
|
1622 var i, |
|
1623 n = group.length, |
|
1624 m = groupData.length, |
|
1625 n0 = Math.min(n, m), |
|
1626 n1 = Math.max(n, m), |
|
1627 updateNodes = [], |
|
1628 enterNodes = [], |
|
1629 exitNodes = [], |
|
1630 node, |
|
1631 nodeData; |
|
1632 |
|
1633 if (join) { |
|
1634 var nodeByKey = {}, |
|
1635 keys = [], |
|
1636 key, |
|
1637 j = groupData.length; |
|
1638 |
|
1639 for (i = -1; ++i < n;) { |
|
1640 key = join.call(node = group[i], node.__data__, i); |
|
1641 if (key in nodeByKey) { |
|
1642 exitNodes[j++] = node; // duplicate key |
|
1643 } else { |
|
1644 nodeByKey[key] = node; |
|
1645 } |
|
1646 keys.push(key); |
|
1647 } |
|
1648 |
|
1649 for (i = -1; ++i < m;) { |
|
1650 node = nodeByKey[key = join.call(groupData, nodeData = groupData[i], i)]; |
|
1651 if (node) { |
|
1652 node.__data__ = nodeData; |
|
1653 updateNodes[i] = node; |
|
1654 enterNodes[i] = exitNodes[i] = null; |
|
1655 } else { |
|
1656 enterNodes[i] = d3_selection_dataNode(nodeData); |
|
1657 updateNodes[i] = exitNodes[i] = null; |
|
1658 } |
|
1659 delete nodeByKey[key]; |
|
1660 } |
|
1661 |
|
1662 for (i = -1; ++i < n;) { |
|
1663 if (keys[i] in nodeByKey) { |
|
1664 exitNodes[i] = group[i]; |
|
1665 } |
|
1666 } |
|
1667 } else { |
|
1668 for (i = -1; ++i < n0;) { |
|
1669 node = group[i]; |
|
1670 nodeData = groupData[i]; |
|
1671 if (node) { |
|
1672 node.__data__ = nodeData; |
|
1673 updateNodes[i] = node; |
|
1674 enterNodes[i] = exitNodes[i] = null; |
|
1675 } else { |
|
1676 enterNodes[i] = d3_selection_dataNode(nodeData); |
|
1677 updateNodes[i] = exitNodes[i] = null; |
|
1678 } |
|
1679 } |
|
1680 for (; i < m; ++i) { |
|
1681 enterNodes[i] = d3_selection_dataNode(groupData[i]); |
|
1682 updateNodes[i] = exitNodes[i] = null; |
|
1683 } |
|
1684 for (; i < n1; ++i) { |
|
1685 exitNodes[i] = group[i]; |
|
1686 enterNodes[i] = updateNodes[i] = null; |
|
1687 } |
|
1688 } |
|
1689 |
|
1690 enterNodes.update |
|
1691 = updateNodes; |
|
1692 |
|
1693 enterNodes.parentNode |
|
1694 = updateNodes.parentNode |
|
1695 = exitNodes.parentNode |
|
1696 = group.parentNode; |
|
1697 |
|
1698 enter.push(enterNodes); |
|
1699 update.push(updateNodes); |
|
1700 exit.push(exitNodes); |
|
1701 } |
|
1702 |
|
1703 var i = -1, |
|
1704 n = this.length, |
|
1705 group; |
|
1706 if (typeof data === "function") { |
|
1707 while (++i < n) { |
|
1708 bind(group = this[i], data.call(group, group.parentNode.__data__, i)); |
|
1709 } |
|
1710 } else { |
|
1711 while (++i < n) { |
|
1712 bind(group = this[i], data); |
|
1713 } |
|
1714 } |
|
1715 |
|
1716 var selection = d3_selection(update); |
|
1717 selection.enter = function() { return d3_selection_enter(enter); }; |
|
1718 selection.exit = function() { return d3_selection(exit); }; |
|
1719 return selection; |
|
1720 }; |
|
1721 |
|
1722 function d3_selection_dataNode(data) { |
|
1723 return {__data__: data}; |
|
1724 } |
|
1725 // TODO preserve null elements to maintain index? |
|
1726 d3_selectionPrototype.filter = function(filter) { |
|
1727 var subgroups = [], |
|
1728 subgroup, |
|
1729 group, |
|
1730 node; |
|
1731 |
|
1732 for (var j = 0, m = this.length; j < m; j++) { |
|
1733 subgroups.push(subgroup = []); |
|
1734 subgroup.parentNode = (group = this[j]).parentNode; |
|
1735 for (var i = 0, n = group.length; i < n; i++) { |
|
1736 if ((node = group[i]) && filter.call(node, node.__data__, i)) { |
|
1737 subgroup.push(node); |
|
1738 } |
|
1739 } |
|
1740 } |
|
1741 |
|
1742 return d3_selection(subgroups); |
|
1743 }; |
|
1744 d3_selectionPrototype.map = function(map) { |
|
1745 return this.each(function() { |
|
1746 this.__data__ = map.apply(this, arguments); |
|
1747 }); |
|
1748 }; |
|
1749 d3_selectionPrototype.sort = function(comparator) { |
|
1750 comparator = d3_selection_sortComparator.apply(this, arguments); |
|
1751 for (var j = 0, m = this.length; j < m; j++) { |
|
1752 for (var group = this[j].sort(comparator), i = 1, n = group.length, prev = group[0]; i < n; i++) { |
|
1753 var node = group[i]; |
|
1754 if (node) { |
|
1755 if (prev) prev.parentNode.insertBefore(node, prev.nextSibling); |
|
1756 prev = node; |
|
1757 } |
|
1758 } |
|
1759 } |
|
1760 return this; |
|
1761 }; |
|
1762 |
|
1763 function d3_selection_sortComparator(comparator) { |
|
1764 if (!arguments.length) comparator = d3.ascending; |
|
1765 return function(a, b) { |
|
1766 return comparator(a && a.__data__, b && b.__data__); |
|
1767 }; |
|
1768 } |
|
1769 // type can be namespaced, e.g., "click.foo" |
|
1770 // listener can be null for removal |
|
1771 d3_selectionPrototype.on = function(type, listener, capture) { |
|
1772 if (arguments.length < 3) capture = false; |
|
1773 |
|
1774 // parse the type specifier |
|
1775 var name = "__on" + type, i = type.indexOf("."); |
|
1776 if (i > 0) type = type.substring(0, i); |
|
1777 |
|
1778 // if called with only one argument, return the current listener |
|
1779 if (arguments.length < 2) return (i = this.node()[name]) && i._; |
|
1780 |
|
1781 // remove the old event listener, and add the new event listener |
|
1782 return this.each(function(d, i) { |
|
1783 var node = this; |
|
1784 |
|
1785 if (node[name]) node.removeEventListener(type, node[name], capture); |
|
1786 if (listener) node.addEventListener(type, node[name] = l, capture); |
|
1787 |
|
1788 // wrapped event listener that preserves i |
|
1789 function l(e) { |
|
1790 var o = d3.event; // Events can be reentrant (e.g., focus). |
|
1791 d3.event = e; |
|
1792 try { |
|
1793 listener.call(node, node.__data__, i); |
|
1794 } finally { |
|
1795 d3.event = o; |
|
1796 } |
|
1797 } |
|
1798 |
|
1799 // stash the unwrapped listener for retrieval |
|
1800 l._ = listener; |
|
1801 }); |
|
1802 }; |
|
1803 d3_selectionPrototype.each = function(callback) { |
|
1804 for (var j = -1, m = this.length; ++j < m;) { |
|
1805 for (var group = this[j], i = -1, n = group.length; ++i < n;) { |
|
1806 var node = group[i]; |
|
1807 if (node) callback.call(node, node.__data__, i, j); |
|
1808 } |
|
1809 } |
|
1810 return this; |
|
1811 }; |
|
1812 // |
|
1813 // Note: assigning to the arguments array simultaneously changes the value of |
|
1814 // the corresponding argument! |
|
1815 // |
|
1816 // TODO The `this` argument probably shouldn't be the first argument to the |
|
1817 // callback, anyway, since it's redundant. However, that will require a major |
|
1818 // version bump due to backwards compatibility, so I'm not changing it right |
|
1819 // away. |
|
1820 // |
|
1821 d3_selectionPrototype.call = function(callback) { |
|
1822 callback.apply(this, (arguments[0] = this, arguments)); |
|
1823 return this; |
|
1824 }; |
|
1825 d3_selectionPrototype.empty = function() { |
|
1826 return !this.node(); |
|
1827 }; |
|
1828 d3_selectionPrototype.node = function(callback) { |
|
1829 for (var j = 0, m = this.length; j < m; j++) { |
|
1830 for (var group = this[j], i = 0, n = group.length; i < n; i++) { |
|
1831 var node = group[i]; |
|
1832 if (node) return node; |
|
1833 } |
|
1834 } |
|
1835 return null; |
|
1836 }; |
|
1837 d3_selectionPrototype.transition = function() { |
|
1838 var subgroups = [], |
|
1839 subgroup, |
|
1840 node; |
|
1841 |
|
1842 for (var j = -1, m = this.length; ++j < m;) { |
|
1843 subgroups.push(subgroup = []); |
|
1844 for (var group = this[j], i = -1, n = group.length; ++i < n;) { |
|
1845 subgroup.push((node = group[i]) ? {node: node, delay: 0, duration: 250} : null); |
|
1846 } |
|
1847 } |
|
1848 |
|
1849 return d3_transition(subgroups, d3_transitionInheritId || ++d3_transitionId, Date.now()); |
|
1850 }; |
|
1851 var d3_selectionRoot = d3_selection([[document]]); |
|
1852 |
|
1853 d3_selectionRoot[0].parentNode = document.documentElement; |
|
1854 |
|
1855 // TODO fast singleton implementation! |
|
1856 // TODO select(function) |
|
1857 d3.select = function(selector) { |
|
1858 return typeof selector === "string" |
|
1859 ? d3_selectionRoot.select(selector) |
|
1860 : d3_selection([[selector]]); // assume node |
|
1861 }; |
|
1862 |
|
1863 // TODO selectAll(function) |
|
1864 d3.selectAll = function(selector) { |
|
1865 return typeof selector === "string" |
|
1866 ? d3_selectionRoot.selectAll(selector) |
|
1867 : d3_selection([d3_array(selector)]); // assume node[] |
|
1868 }; |
|
1869 function d3_selection_enter(selection) { |
|
1870 d3_arraySubclass(selection, d3_selection_enterPrototype); |
|
1871 return selection; |
|
1872 } |
|
1873 |
|
1874 var d3_selection_enterPrototype = []; |
|
1875 |
|
1876 d3_selection_enterPrototype.append = d3_selectionPrototype.append; |
|
1877 d3_selection_enterPrototype.insert = d3_selectionPrototype.insert; |
|
1878 d3_selection_enterPrototype.empty = d3_selectionPrototype.empty; |
|
1879 d3_selection_enterPrototype.node = d3_selectionPrototype.node; |
|
1880 d3_selection_enterPrototype.select = function(selector) { |
|
1881 var subgroups = [], |
|
1882 subgroup, |
|
1883 subnode, |
|
1884 upgroup, |
|
1885 group, |
|
1886 node; |
|
1887 |
|
1888 for (var j = -1, m = this.length; ++j < m;) { |
|
1889 upgroup = (group = this[j]).update; |
|
1890 subgroups.push(subgroup = []); |
|
1891 subgroup.parentNode = group.parentNode; |
|
1892 for (var i = -1, n = group.length; ++i < n;) { |
|
1893 if (node = group[i]) { |
|
1894 subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i)); |
|
1895 subnode.__data__ = node.__data__; |
|
1896 } else { |
|
1897 subgroup.push(null); |
|
1898 } |
|
1899 } |
|
1900 } |
|
1901 |
|
1902 return d3_selection(subgroups); |
|
1903 }; |
|
1904 function d3_transition(groups, id, time) { |
|
1905 d3_arraySubclass(groups, d3_transitionPrototype); |
|
1906 |
|
1907 var tweens = {}, |
|
1908 event = d3.dispatch("start", "end"), |
|
1909 ease = d3_transitionEase; |
|
1910 |
|
1911 groups.id = id; |
|
1912 |
|
1913 groups.time = time; |
|
1914 |
|
1915 groups.tween = function(name, tween) { |
|
1916 if (arguments.length < 2) return tweens[name]; |
|
1917 if (tween == null) delete tweens[name]; |
|
1918 else tweens[name] = tween; |
|
1919 return groups; |
|
1920 }; |
|
1921 |
|
1922 groups.ease = function(value) { |
|
1923 if (!arguments.length) return ease; |
|
1924 ease = typeof value === "function" ? value : d3.ease.apply(d3, arguments); |
|
1925 return groups; |
|
1926 }; |
|
1927 |
|
1928 groups.each = function(type, listener) { |
|
1929 if (arguments.length < 2) return d3_transition_each.call(groups, type); |
|
1930 event.on(type, listener); |
|
1931 return groups; |
|
1932 }; |
|
1933 |
|
1934 d3.timer(function(elapsed) { |
|
1935 groups.each(function(d, i, j) { |
|
1936 var tweened = [], |
|
1937 node = this, |
|
1938 delay = groups[j][i].delay, |
|
1939 duration = groups[j][i].duration, |
|
1940 lock = node.__transition__ || (node.__transition__ = {active: 0, count: 0}); |
|
1941 |
|
1942 ++lock.count; |
|
1943 |
|
1944 delay <= elapsed ? start(elapsed) : d3.timer(start, delay, time); |
|
1945 |
|
1946 function start(elapsed) { |
|
1947 if (lock.active > id) return stop(); |
|
1948 lock.active = id; |
|
1949 |
|
1950 for (var tween in tweens) { |
|
1951 if (tween = tweens[tween].call(node, d, i)) { |
|
1952 tweened.push(tween); |
|
1953 } |
|
1954 } |
|
1955 |
|
1956 event.start.call(node, d, i); |
|
1957 if (!tick(elapsed)) d3.timer(tick, 0, time); |
|
1958 return 1; |
|
1959 } |
|
1960 |
|
1961 function tick(elapsed) { |
|
1962 if (lock.active !== id) return stop(); |
|
1963 |
|
1964 var t = (elapsed - delay) / duration, |
|
1965 e = ease(t), |
|
1966 n = tweened.length; |
|
1967 |
|
1968 while (n > 0) { |
|
1969 tweened[--n].call(node, e); |
|
1970 } |
|
1971 |
|
1972 if (t >= 1) { |
|
1973 stop(); |
|
1974 d3_transitionInheritId = id; |
|
1975 event.end.call(node, d, i); |
|
1976 d3_transitionInheritId = 0; |
|
1977 return 1; |
|
1978 } |
|
1979 } |
|
1980 |
|
1981 function stop() { |
|
1982 if (!--lock.count) delete node.__transition__; |
|
1983 return 1; |
|
1984 } |
|
1985 }); |
|
1986 return 1; |
|
1987 }, 0, time); |
|
1988 |
|
1989 return groups; |
|
1990 } |
|
1991 |
|
1992 var d3_transitionRemove = {}; |
|
1993 |
|
1994 function d3_transitionNull(d, i, a) { |
|
1995 return a != "" && d3_transitionRemove; |
|
1996 } |
|
1997 |
|
1998 function d3_transitionTween(name, b) { |
|
1999 var interpolate = d3_interpolateByName(name); |
|
2000 |
|
2001 function transitionFunction(d, i, a) { |
|
2002 var v = b.call(this, d, i); |
|
2003 return v == null |
|
2004 ? a != "" && d3_transitionRemove |
|
2005 : a != v && interpolate(a, v); |
|
2006 } |
|
2007 |
|
2008 function transitionString(d, i, a) { |
|
2009 return a != b && interpolate(a, b); |
|
2010 } |
|
2011 |
|
2012 return typeof b === "function" ? transitionFunction |
|
2013 : b == null ? d3_transitionNull |
|
2014 : (b += "", transitionString); |
|
2015 } |
|
2016 |
|
2017 var d3_transitionPrototype = [], |
|
2018 d3_transitionId = 0, |
|
2019 d3_transitionInheritId = 0, |
|
2020 d3_transitionEase = d3.ease("cubic-in-out"); |
|
2021 |
|
2022 d3_transitionPrototype.call = d3_selectionPrototype.call; |
|
2023 |
|
2024 d3.transition = function() { |
|
2025 return d3_selectionRoot.transition(); |
|
2026 }; |
|
2027 |
|
2028 d3.transition.prototype = d3_transitionPrototype; |
|
2029 d3_transitionPrototype.select = function(selector) { |
|
2030 var subgroups = [], |
|
2031 subgroup, |
|
2032 subnode, |
|
2033 node; |
|
2034 |
|
2035 if (typeof selector !== "function") selector = d3_selection_selector(selector); |
|
2036 |
|
2037 for (var j = -1, m = this.length; ++j < m;) { |
|
2038 subgroups.push(subgroup = []); |
|
2039 for (var group = this[j], i = -1, n = group.length; ++i < n;) { |
|
2040 if ((node = group[i]) && (subnode = selector.call(node.node, node.node.__data__, i))) { |
|
2041 if ("__data__" in node.node) subnode.__data__ = node.node.__data__; |
|
2042 subgroup.push({node: subnode, delay: node.delay, duration: node.duration}); |
|
2043 } else { |
|
2044 subgroup.push(null); |
|
2045 } |
|
2046 } |
|
2047 } |
|
2048 |
|
2049 return d3_transition(subgroups, this.id, this.time).ease(this.ease()); |
|
2050 }; |
|
2051 d3_transitionPrototype.selectAll = function(selector) { |
|
2052 var subgroups = [], |
|
2053 subgroup, |
|
2054 subnodes, |
|
2055 node; |
|
2056 |
|
2057 if (typeof selector !== "function") selector = d3_selection_selectorAll(selector); |
|
2058 |
|
2059 for (var j = -1, m = this.length; ++j < m;) { |
|
2060 for (var group = this[j], i = -1, n = group.length; ++i < n;) { |
|
2061 if (node = group[i]) { |
|
2062 subnodes = selector.call(node.node, node.node.__data__, i); |
|
2063 subgroups.push(subgroup = []); |
|
2064 for (var k = -1, o = subnodes.length; ++k < o;) { |
|
2065 subgroup.push({node: subnodes[k], delay: node.delay, duration: node.duration}); |
|
2066 } |
|
2067 } |
|
2068 } |
|
2069 } |
|
2070 |
|
2071 return d3_transition(subgroups, this.id, this.time).ease(this.ease()); |
|
2072 }; |
|
2073 d3_transitionPrototype.attr = function(name, value) { |
|
2074 return this.attrTween(name, d3_transitionTween(name, value)); |
|
2075 }; |
|
2076 |
|
2077 d3_transitionPrototype.attrTween = function(nameNS, tween) { |
|
2078 var name = d3.ns.qualify(nameNS); |
|
2079 |
|
2080 function attrTween(d, i) { |
|
2081 var f = tween.call(this, d, i, this.getAttribute(name)); |
|
2082 return f === d3_transitionRemove |
|
2083 ? (this.removeAttribute(name), null) |
|
2084 : f && function(t) { this.setAttribute(name, f(t)); }; |
|
2085 } |
|
2086 |
|
2087 function attrTweenNS(d, i) { |
|
2088 var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local)); |
|
2089 return f === d3_transitionRemove |
|
2090 ? (this.removeAttributeNS(name.space, name.local), null) |
|
2091 : f && function(t) { this.setAttributeNS(name.space, name.local, f(t)); }; |
|
2092 } |
|
2093 |
|
2094 return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween); |
|
2095 }; |
|
2096 d3_transitionPrototype.style = function(name, value, priority) { |
|
2097 if (arguments.length < 3) priority = ""; |
|
2098 return this.styleTween(name, d3_transitionTween(name, value), priority); |
|
2099 }; |
|
2100 |
|
2101 d3_transitionPrototype.styleTween = function(name, tween, priority) { |
|
2102 if (arguments.length < 3) priority = ""; |
|
2103 return this.tween("style." + name, function(d, i) { |
|
2104 var f = tween.call(this, d, i, window.getComputedStyle(this, null).getPropertyValue(name)); |
|
2105 return f === d3_transitionRemove |
|
2106 ? (this.style.removeProperty(name), null) |
|
2107 : f && function(t) { this.style.setProperty(name, f(t), priority); }; |
|
2108 }); |
|
2109 }; |
|
2110 d3_transitionPrototype.text = function(value) { |
|
2111 return this.tween("text", function(d, i) { |
|
2112 this.textContent = typeof value === "function" |
|
2113 ? value.call(this, d, i) |
|
2114 : value; |
|
2115 }); |
|
2116 }; |
|
2117 d3_transitionPrototype.remove = function() { |
|
2118 return this.each("end", function() { |
|
2119 var p; |
|
2120 if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this); |
|
2121 }); |
|
2122 }; |
|
2123 d3_transitionPrototype.delay = function(value) { |
|
2124 var groups = this; |
|
2125 return groups.each(typeof value === "function" |
|
2126 ? function(d, i, j) { groups[j][i].delay = +value.apply(this, arguments); } |
|
2127 : (value = +value, function(d, i, j) { groups[j][i].delay = value; })); |
|
2128 }; |
|
2129 d3_transitionPrototype.duration = function(value) { |
|
2130 var groups = this; |
|
2131 return groups.each(typeof value === "function" |
|
2132 ? function(d, i, j) { groups[j][i].duration = +value.apply(this, arguments); } |
|
2133 : (value = +value, function(d, i, j) { groups[j][i].duration = value; })); |
|
2134 }; |
|
2135 function d3_transition_each(callback) { |
|
2136 for (var j = 0, m = this.length; j < m; j++) { |
|
2137 for (var group = this[j], i = 0, n = group.length; i < n; i++) { |
|
2138 var node = group[i]; |
|
2139 if (node) callback.call(node = node.node, node.__data__, i, j); |
|
2140 } |
|
2141 } |
|
2142 return this; |
|
2143 } |
|
2144 d3_transitionPrototype.transition = function() { |
|
2145 return this.select(d3_this); |
|
2146 }; |
|
2147 var d3_timer_queue = null, |
|
2148 d3_timer_interval, // is an interval (or frame) active? |
|
2149 d3_timer_timeout; // is a timeout active? |
|
2150 |
|
2151 // The timer will continue to fire until callback returns true. |
|
2152 d3.timer = function(callback, delay, then) { |
|
2153 var found = false, |
|
2154 t0, |
|
2155 t1 = d3_timer_queue; |
|
2156 |
|
2157 if (arguments.length < 3) { |
|
2158 if (arguments.length < 2) delay = 0; |
|
2159 else if (!isFinite(delay)) return; |
|
2160 then = Date.now(); |
|
2161 } |
|
2162 |
|
2163 // See if the callback's already in the queue. |
|
2164 while (t1) { |
|
2165 if (t1.callback === callback) { |
|
2166 t1.then = then; |
|
2167 t1.delay = delay; |
|
2168 found = true; |
|
2169 break; |
|
2170 } |
|
2171 t0 = t1; |
|
2172 t1 = t1.next; |
|
2173 } |
|
2174 |
|
2175 // Otherwise, add the callback to the queue. |
|
2176 if (!found) d3_timer_queue = { |
|
2177 callback: callback, |
|
2178 then: then, |
|
2179 delay: delay, |
|
2180 next: d3_timer_queue |
|
2181 }; |
|
2182 |
|
2183 // Start animatin'! |
|
2184 if (!d3_timer_interval) { |
|
2185 d3_timer_timeout = clearTimeout(d3_timer_timeout); |
|
2186 d3_timer_interval = 1; |
|
2187 d3_timer_frame(d3_timer_step); |
|
2188 } |
|
2189 } |
|
2190 |
|
2191 function d3_timer_step() { |
|
2192 var elapsed, |
|
2193 now = Date.now(), |
|
2194 t1 = d3_timer_queue; |
|
2195 |
|
2196 while (t1) { |
|
2197 elapsed = now - t1.then; |
|
2198 if (elapsed >= t1.delay) t1.flush = t1.callback(elapsed); |
|
2199 t1 = t1.next; |
|
2200 } |
|
2201 |
|
2202 var delay = d3_timer_flush() - now; |
|
2203 if (delay > 24) { |
|
2204 if (isFinite(delay)) { |
|
2205 clearTimeout(d3_timer_timeout); |
|
2206 d3_timer_timeout = setTimeout(d3_timer_step, delay); |
|
2207 } |
|
2208 d3_timer_interval = 0; |
|
2209 } else { |
|
2210 d3_timer_interval = 1; |
|
2211 d3_timer_frame(d3_timer_step); |
|
2212 } |
|
2213 } |
|
2214 |
|
2215 d3.timer.flush = function() { |
|
2216 var elapsed, |
|
2217 now = Date.now(), |
|
2218 t1 = d3_timer_queue; |
|
2219 |
|
2220 while (t1) { |
|
2221 elapsed = now - t1.then; |
|
2222 if (!t1.delay) t1.flush = t1.callback(elapsed); |
|
2223 t1 = t1.next; |
|
2224 } |
|
2225 |
|
2226 d3_timer_flush(); |
|
2227 }; |
|
2228 |
|
2229 // Flush after callbacks, to avoid concurrent queue modification. |
|
2230 function d3_timer_flush() { |
|
2231 var t0 = null, |
|
2232 t1 = d3_timer_queue, |
|
2233 then = Infinity; |
|
2234 while (t1) { |
|
2235 if (t1.flush) { |
|
2236 t1 = t0 ? t0.next = t1.next : d3_timer_queue = t1.next; |
|
2237 } else { |
|
2238 then = Math.min(then, t1.then + t1.delay); |
|
2239 t1 = (t0 = t1).next; |
|
2240 } |
|
2241 } |
|
2242 return then; |
|
2243 } |
|
2244 |
|
2245 var d3_timer_frame = window.requestAnimationFrame |
|
2246 || window.webkitRequestAnimationFrame |
|
2247 || window.mozRequestAnimationFrame |
|
2248 || window.oRequestAnimationFrame |
|
2249 || window.msRequestAnimationFrame |
|
2250 || function(callback) { setTimeout(callback, 17); }; |
|
2251 d3.transform = function(string) { |
|
2252 d3_transformG.setAttribute("transform", string); |
|
2253 return new d3_transform(d3_transformG.transform.baseVal.consolidate().matrix); |
|
2254 }; |
|
2255 |
|
2256 // Compute x-scale and normalize the first row. |
|
2257 // Compute shear and make second row orthogonal to first. |
|
2258 // Compute y-scale and normalize the second row. |
|
2259 // Finally, compute the rotation. |
|
2260 function d3_transform(m) { |
|
2261 var r0 = [m.a, m.b], |
|
2262 r1 = [m.c, m.d], |
|
2263 kx = d3_transformNormalize(r0), |
|
2264 kz = d3_transformDot(r0, r1), |
|
2265 ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)); |
|
2266 this.translate = [m.e, m.f]; |
|
2267 this.rotate = Math.atan2(m.b, m.a) * d3_transformDegrees; |
|
2268 this.scale = [kx, ky || 0]; |
|
2269 this.skew = ky ? kz / ky * d3_transformDegrees : 0; |
|
2270 }; |
|
2271 |
|
2272 d3_transform.prototype.toString = function() { |
|
2273 return "translate(" + this.translate |
|
2274 + ")rotate(" + this.rotate |
|
2275 + ")skewX(" + this.skew |
|
2276 + ")scale(" + this.scale |
|
2277 + ")"; |
|
2278 }; |
|
2279 |
|
2280 function d3_transformDot(a, b) { |
|
2281 return a[0] * b[0] + a[1] * b[1]; |
|
2282 } |
|
2283 |
|
2284 function d3_transformNormalize(a) { |
|
2285 var k = Math.sqrt(d3_transformDot(a, a)); |
|
2286 a[0] /= k; |
|
2287 a[1] /= k; |
|
2288 return k; |
|
2289 } |
|
2290 |
|
2291 function d3_transformCombine(a, b, k) { |
|
2292 a[0] += k * b[0]; |
|
2293 a[1] += k * b[1]; |
|
2294 return a; |
|
2295 } |
|
2296 |
|
2297 var d3_transformG = document.createElementNS(d3.ns.prefix.svg, "g"), |
|
2298 d3_transformDegrees = 180 / Math.PI; |
|
2299 function d3_noop() {} |
|
2300 d3.scale = {}; |
|
2301 |
|
2302 function d3_scaleExtent(domain) { |
|
2303 var start = domain[0], stop = domain[domain.length - 1]; |
|
2304 return start < stop ? [start, stop] : [stop, start]; |
|
2305 } |
|
2306 function d3_scale_nice(domain, nice) { |
|
2307 var i0 = 0, |
|
2308 i1 = domain.length - 1, |
|
2309 x0 = domain[i0], |
|
2310 x1 = domain[i1], |
|
2311 dx; |
|
2312 |
|
2313 if (x1 < x0) { |
|
2314 dx = i0; i0 = i1; i1 = dx; |
|
2315 dx = x0; x0 = x1; x1 = dx; |
|
2316 } |
|
2317 |
|
2318 if (dx = x1 - x0) { |
|
2319 nice = nice(dx); |
|
2320 domain[i0] = nice.floor(x0); |
|
2321 domain[i1] = nice.ceil(x1); |
|
2322 } |
|
2323 |
|
2324 return domain; |
|
2325 } |
|
2326 |
|
2327 function d3_scale_niceDefault() { |
|
2328 return Math; |
|
2329 } |
|
2330 d3.scale.linear = function() { |
|
2331 return d3_scale_linear([0, 1], [0, 1], d3.interpolate, false); |
|
2332 }; |
|
2333 |
|
2334 function d3_scale_linear(domain, range, interpolate, clamp) { |
|
2335 var output, |
|
2336 input; |
|
2337 |
|
2338 function rescale() { |
|
2339 var linear = domain.length == 2 ? d3_scale_bilinear : d3_scale_polylinear, |
|
2340 uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber; |
|
2341 output = linear(domain, range, uninterpolate, interpolate); |
|
2342 input = linear(range, domain, uninterpolate, d3.interpolate); |
|
2343 return scale; |
|
2344 } |
|
2345 |
|
2346 function scale(x) { |
|
2347 return output(x); |
|
2348 } |
|
2349 |
|
2350 // Note: requires range is coercible to number! |
|
2351 scale.invert = function(y) { |
|
2352 return input(y); |
|
2353 }; |
|
2354 |
|
2355 scale.domain = function(x) { |
|
2356 if (!arguments.length) return domain; |
|
2357 domain = x.map(Number); |
|
2358 return rescale(); |
|
2359 }; |
|
2360 |
|
2361 scale.range = function(x) { |
|
2362 if (!arguments.length) return range; |
|
2363 range = x; |
|
2364 return rescale(); |
|
2365 }; |
|
2366 |
|
2367 scale.rangeRound = function(x) { |
|
2368 return scale.range(x).interpolate(d3.interpolateRound); |
|
2369 }; |
|
2370 |
|
2371 scale.clamp = function(x) { |
|
2372 if (!arguments.length) return clamp; |
|
2373 clamp = x; |
|
2374 return rescale(); |
|
2375 }; |
|
2376 |
|
2377 scale.interpolate = function(x) { |
|
2378 if (!arguments.length) return interpolate; |
|
2379 interpolate = x; |
|
2380 return rescale(); |
|
2381 }; |
|
2382 |
|
2383 scale.ticks = function(m) { |
|
2384 return d3_scale_linearTicks(domain, m); |
|
2385 }; |
|
2386 |
|
2387 scale.tickFormat = function(m) { |
|
2388 return d3_scale_linearTickFormat(domain, m); |
|
2389 }; |
|
2390 |
|
2391 scale.nice = function() { |
|
2392 d3_scale_nice(domain, d3_scale_linearNice); |
|
2393 return rescale(); |
|
2394 }; |
|
2395 |
|
2396 scale.copy = function() { |
|
2397 return d3_scale_linear(domain, range, interpolate, clamp); |
|
2398 }; |
|
2399 |
|
2400 return rescale(); |
|
2401 }; |
|
2402 |
|
2403 function d3_scale_linearRebind(scale, linear) { |
|
2404 scale.range = d3.rebind(scale, linear.range); |
|
2405 scale.rangeRound = d3.rebind(scale, linear.rangeRound); |
|
2406 scale.interpolate = d3.rebind(scale, linear.interpolate); |
|
2407 scale.clamp = d3.rebind(scale, linear.clamp); |
|
2408 return scale; |
|
2409 } |
|
2410 |
|
2411 function d3_scale_linearNice(dx) { |
|
2412 dx = Math.pow(10, Math.round(Math.log(dx) / Math.LN10) - 1); |
|
2413 return { |
|
2414 floor: function(x) { return Math.floor(x / dx) * dx; }, |
|
2415 ceil: function(x) { return Math.ceil(x / dx) * dx; } |
|
2416 }; |
|
2417 } |
|
2418 |
|
2419 // TODO Dates? Ugh. |
|
2420 function d3_scale_linearTickRange(domain, m) { |
|
2421 var extent = d3_scaleExtent(domain), |
|
2422 span = extent[1] - extent[0], |
|
2423 step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), |
|
2424 err = m / span * step; |
|
2425 |
|
2426 // Filter ticks to get closer to the desired count. |
|
2427 if (err <= .15) step *= 10; |
|
2428 else if (err <= .35) step *= 5; |
|
2429 else if (err <= .75) step *= 2; |
|
2430 |
|
2431 // Round start and stop values to step interval. |
|
2432 extent[0] = Math.ceil(extent[0] / step) * step; |
|
2433 extent[1] = Math.floor(extent[1] / step) * step + step * .5; // inclusive |
|
2434 extent[2] = step; |
|
2435 return extent; |
|
2436 } |
|
2437 |
|
2438 function d3_scale_linearTicks(domain, m) { |
|
2439 return d3.range.apply(d3, d3_scale_linearTickRange(domain, m)); |
|
2440 } |
|
2441 |
|
2442 function d3_scale_linearTickFormat(domain, m) { |
|
2443 return d3.format(",." + Math.max(0, -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01)) + "f"); |
|
2444 } |
|
2445 function d3_scale_bilinear(domain, range, uninterpolate, interpolate) { |
|
2446 var u = uninterpolate(domain[0], domain[1]), |
|
2447 i = interpolate(range[0], range[1]); |
|
2448 return function(x) { |
|
2449 return i(u(x)); |
|
2450 }; |
|
2451 } |
|
2452 function d3_scale_polylinear(domain, range, uninterpolate, interpolate) { |
|
2453 var u = [], |
|
2454 i = [], |
|
2455 j = 0, |
|
2456 n = domain.length; |
|
2457 |
|
2458 while (++j < n) { |
|
2459 u.push(uninterpolate(domain[j - 1], domain[j])); |
|
2460 i.push(interpolate(range[j - 1], range[j])); |
|
2461 } |
|
2462 |
|
2463 return function(x) { |
|
2464 var j = d3.bisect(domain, x, 1, domain.length - 1) - 1; |
|
2465 return i[j](u[j](x)); |
|
2466 }; |
|
2467 } |
|
2468 d3.scale.log = function() { |
|
2469 return d3_scale_log(d3.scale.linear(), d3_scale_logp); |
|
2470 }; |
|
2471 |
|
2472 function d3_scale_log(linear, log) { |
|
2473 var pow = log.pow; |
|
2474 |
|
2475 function scale(x) { |
|
2476 return linear(log(x)); |
|
2477 } |
|
2478 |
|
2479 scale.invert = function(x) { |
|
2480 return pow(linear.invert(x)); |
|
2481 }; |
|
2482 |
|
2483 scale.domain = function(x) { |
|
2484 if (!arguments.length) return linear.domain().map(pow); |
|
2485 log = x[0] < 0 ? d3_scale_logn : d3_scale_logp; |
|
2486 pow = log.pow; |
|
2487 linear.domain(x.map(log)); |
|
2488 return scale; |
|
2489 }; |
|
2490 |
|
2491 scale.nice = function() { |
|
2492 linear.domain(d3_scale_nice(linear.domain(), d3_scale_niceDefault)); |
|
2493 return scale; |
|
2494 }; |
|
2495 |
|
2496 scale.ticks = function() { |
|
2497 var extent = d3_scaleExtent(linear.domain()), |
|
2498 ticks = []; |
|
2499 if (extent.every(isFinite)) { |
|
2500 var i = Math.floor(extent[0]), |
|
2501 j = Math.ceil(extent[1]), |
|
2502 u = Math.round(pow(extent[0])), |
|
2503 v = Math.round(pow(extent[1])); |
|
2504 if (log === d3_scale_logn) { |
|
2505 ticks.push(pow(i)); |
|
2506 for (; i++ < j;) for (var k = 9; k > 0; k--) ticks.push(pow(i) * k); |
|
2507 } else { |
|
2508 for (; i < j; i++) for (var k = 1; k < 10; k++) ticks.push(pow(i) * k); |
|
2509 ticks.push(pow(i)); |
|
2510 } |
|
2511 for (i = 0; ticks[i] < u; i++) {} // strip small values |
|
2512 for (j = ticks.length; ticks[j - 1] > v; j--) {} // strip big values |
|
2513 ticks = ticks.slice(i, j); |
|
2514 } |
|
2515 return ticks; |
|
2516 }; |
|
2517 |
|
2518 scale.tickFormat = function(n, format) { |
|
2519 if (arguments.length < 2) format = d3_scale_logFormat; |
|
2520 if (arguments.length < 1) return format; |
|
2521 var k = n / scale.ticks().length, |
|
2522 f = log === d3_scale_logn ? (e = -1e-15, Math.floor) : (e = 1e-15, Math.ceil), |
|
2523 e; |
|
2524 return function(d) { |
|
2525 return d / pow(f(log(d) + e)) < k ? format(d) : ""; |
|
2526 }; |
|
2527 }; |
|
2528 |
|
2529 scale.copy = function() { |
|
2530 return d3_scale_log(linear.copy(), log); |
|
2531 }; |
|
2532 |
|
2533 return d3_scale_linearRebind(scale, linear); |
|
2534 }; |
|
2535 |
|
2536 var d3_scale_logFormat = d3.format("e"); |
|
2537 |
|
2538 function d3_scale_logp(x) { |
|
2539 return Math.log(x) / Math.LN10; |
|
2540 } |
|
2541 |
|
2542 function d3_scale_logn(x) { |
|
2543 return -Math.log(-x) / Math.LN10; |
|
2544 } |
|
2545 |
|
2546 d3_scale_logp.pow = function(x) { |
|
2547 return Math.pow(10, x); |
|
2548 }; |
|
2549 |
|
2550 d3_scale_logn.pow = function(x) { |
|
2551 return -Math.pow(10, -x); |
|
2552 }; |
|
2553 d3.scale.pow = function() { |
|
2554 return d3_scale_pow(d3.scale.linear(), 1); |
|
2555 }; |
|
2556 |
|
2557 function d3_scale_pow(linear, exponent) { |
|
2558 var powp = d3_scale_powPow(exponent), |
|
2559 powb = d3_scale_powPow(1 / exponent); |
|
2560 |
|
2561 function scale(x) { |
|
2562 return linear(powp(x)); |
|
2563 } |
|
2564 |
|
2565 scale.invert = function(x) { |
|
2566 return powb(linear.invert(x)); |
|
2567 }; |
|
2568 |
|
2569 scale.domain = function(x) { |
|
2570 if (!arguments.length) return linear.domain().map(powb); |
|
2571 linear.domain(x.map(powp)); |
|
2572 return scale; |
|
2573 }; |
|
2574 |
|
2575 scale.ticks = function(m) { |
|
2576 return d3_scale_linearTicks(scale.domain(), m); |
|
2577 }; |
|
2578 |
|
2579 scale.tickFormat = function(m) { |
|
2580 return d3_scale_linearTickFormat(scale.domain(), m); |
|
2581 }; |
|
2582 |
|
2583 scale.nice = function() { |
|
2584 return scale.domain(d3_scale_nice(scale.domain(), d3_scale_linearNice)); |
|
2585 }; |
|
2586 |
|
2587 scale.exponent = function(x) { |
|
2588 if (!arguments.length) return exponent; |
|
2589 var domain = scale.domain(); |
|
2590 powp = d3_scale_powPow(exponent = x); |
|
2591 powb = d3_scale_powPow(1 / exponent); |
|
2592 return scale.domain(domain); |
|
2593 }; |
|
2594 |
|
2595 scale.copy = function() { |
|
2596 return d3_scale_pow(linear.copy(), exponent); |
|
2597 }; |
|
2598 |
|
2599 return d3_scale_linearRebind(scale, linear); |
|
2600 }; |
|
2601 |
|
2602 function d3_scale_powPow(e) { |
|
2603 return function(x) { |
|
2604 return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e); |
|
2605 }; |
|
2606 } |
|
2607 d3.scale.sqrt = function() { |
|
2608 return d3.scale.pow().exponent(.5); |
|
2609 }; |
|
2610 d3.scale.ordinal = function() { |
|
2611 return d3_scale_ordinal([], {t: "range", x: []}); |
|
2612 }; |
|
2613 |
|
2614 function d3_scale_ordinal(domain, ranger) { |
|
2615 var index, |
|
2616 range, |
|
2617 rangeBand; |
|
2618 |
|
2619 function scale(x) { |
|
2620 return range[((index[x] || (index[x] = domain.push(x))) - 1) % range.length]; |
|
2621 } |
|
2622 |
|
2623 function steps(start, step) { |
|
2624 return d3.range(domain.length).map(function(i) { return start + step * i; }); |
|
2625 } |
|
2626 |
|
2627 scale.domain = function(x) { |
|
2628 if (!arguments.length) return domain; |
|
2629 domain = []; |
|
2630 index = {}; |
|
2631 var i = -1, n = x.length, xi; |
|
2632 while (++i < n) if (!index[xi = x[i]]) index[xi] = domain.push(xi); |
|
2633 return scale[ranger.t](ranger.x, ranger.p); |
|
2634 }; |
|
2635 |
|
2636 scale.range = function(x) { |
|
2637 if (!arguments.length) return range; |
|
2638 range = x; |
|
2639 rangeBand = 0; |
|
2640 ranger = {t: "range", x: x}; |
|
2641 return scale; |
|
2642 }; |
|
2643 |
|
2644 scale.rangePoints = function(x, padding) { |
|
2645 if (arguments.length < 2) padding = 0; |
|
2646 var start = x[0], |
|
2647 stop = x[1], |
|
2648 step = (stop - start) / (domain.length - 1 + padding); |
|
2649 range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step); |
|
2650 rangeBand = 0; |
|
2651 ranger = {t: "rangePoints", x: x, p: padding}; |
|
2652 return scale; |
|
2653 }; |
|
2654 |
|
2655 scale.rangeBands = function(x, padding) { |
|
2656 if (arguments.length < 2) padding = 0; |
|
2657 var start = x[0], |
|
2658 stop = x[1], |
|
2659 step = (stop - start) / (domain.length + padding); |
|
2660 range = steps(start + step * padding, step); |
|
2661 rangeBand = step * (1 - padding); |
|
2662 ranger = {t: "rangeBands", x: x, p: padding}; |
|
2663 return scale; |
|
2664 }; |
|
2665 |
|
2666 scale.rangeRoundBands = function(x, padding) { |
|
2667 if (arguments.length < 2) padding = 0; |
|
2668 var start = x[0], |
|
2669 stop = x[1], |
|
2670 step = Math.floor((stop - start) / (domain.length + padding)); |
|
2671 range = steps(start + Math.round((stop - start - (domain.length - padding) * step) / 2), step); |
|
2672 rangeBand = Math.round(step * (1 - padding)); |
|
2673 ranger = {t: "rangeRoundBands", x: x, p: padding}; |
|
2674 return scale; |
|
2675 }; |
|
2676 |
|
2677 scale.rangeBand = function() { |
|
2678 return rangeBand; |
|
2679 }; |
|
2680 |
|
2681 scale.copy = function() { |
|
2682 return d3_scale_ordinal(domain, ranger); |
|
2683 }; |
|
2684 |
|
2685 return scale.domain(domain); |
|
2686 }; |
|
2687 /* |
|
2688 * This product includes color specifications and designs developed by Cynthia |
|
2689 * Brewer (http://colorbrewer.org/). See lib/colorbrewer for more information. |
|
2690 */ |
|
2691 |
|
2692 d3.scale.category10 = function() { |
|
2693 return d3.scale.ordinal().range(d3_category10); |
|
2694 }; |
|
2695 |
|
2696 d3.scale.category20 = function() { |
|
2697 return d3.scale.ordinal().range(d3_category20); |
|
2698 }; |
|
2699 |
|
2700 d3.scale.category20b = function() { |
|
2701 return d3.scale.ordinal().range(d3_category20b); |
|
2702 }; |
|
2703 |
|
2704 d3.scale.category20c = function() { |
|
2705 return d3.scale.ordinal().range(d3_category20c); |
|
2706 }; |
|
2707 |
|
2708 var d3_category10 = [ |
|
2709 "#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", |
|
2710 "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf" |
|
2711 ]; |
|
2712 |
|
2713 var d3_category20 = [ |
|
2714 "#1f77b4", "#aec7e8", |
|
2715 "#ff7f0e", "#ffbb78", |
|
2716 "#2ca02c", "#98df8a", |
|
2717 "#d62728", "#ff9896", |
|
2718 "#9467bd", "#c5b0d5", |
|
2719 "#8c564b", "#c49c94", |
|
2720 "#e377c2", "#f7b6d2", |
|
2721 "#7f7f7f", "#c7c7c7", |
|
2722 "#bcbd22", "#dbdb8d", |
|
2723 "#17becf", "#9edae5" |
|
2724 ]; |
|
2725 |
|
2726 var d3_category20b = [ |
|
2727 "#393b79", "#5254a3", "#6b6ecf", "#9c9ede", |
|
2728 "#637939", "#8ca252", "#b5cf6b", "#cedb9c", |
|
2729 "#8c6d31", "#bd9e39", "#e7ba52", "#e7cb94", |
|
2730 "#843c39", "#ad494a", "#d6616b", "#e7969c", |
|
2731 "#7b4173", "#a55194", "#ce6dbd", "#de9ed6" |
|
2732 ]; |
|
2733 |
|
2734 var d3_category20c = [ |
|
2735 "#3182bd", "#6baed6", "#9ecae1", "#c6dbef", |
|
2736 "#e6550d", "#fd8d3c", "#fdae6b", "#fdd0a2", |
|
2737 "#31a354", "#74c476", "#a1d99b", "#c7e9c0", |
|
2738 "#756bb1", "#9e9ac8", "#bcbddc", "#dadaeb", |
|
2739 "#636363", "#969696", "#bdbdbd", "#d9d9d9" |
|
2740 ]; |
|
2741 d3.scale.quantile = function() { |
|
2742 return d3_scale_quantile([], []); |
|
2743 }; |
|
2744 |
|
2745 function d3_scale_quantile(domain, range) { |
|
2746 var thresholds; |
|
2747 |
|
2748 function rescale() { |
|
2749 var k = 0, |
|
2750 n = domain.length, |
|
2751 q = range.length; |
|
2752 thresholds = []; |
|
2753 while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q); |
|
2754 return scale; |
|
2755 } |
|
2756 |
|
2757 function scale(x) { |
|
2758 if (isNaN(x = +x)) return NaN; |
|
2759 return range[d3.bisect(thresholds, x)]; |
|
2760 } |
|
2761 |
|
2762 scale.domain = function(x) { |
|
2763 if (!arguments.length) return domain; |
|
2764 domain = x.filter(function(d) { return !isNaN(d); }).sort(d3.ascending); |
|
2765 return rescale(); |
|
2766 }; |
|
2767 |
|
2768 scale.range = function(x) { |
|
2769 if (!arguments.length) return range; |
|
2770 range = x; |
|
2771 return rescale(); |
|
2772 }; |
|
2773 |
|
2774 scale.quantiles = function() { |
|
2775 return thresholds; |
|
2776 }; |
|
2777 |
|
2778 scale.copy = function() { |
|
2779 return d3_scale_quantile(domain, range); // copy on write! |
|
2780 }; |
|
2781 |
|
2782 return rescale(); |
|
2783 }; |
|
2784 d3.scale.quantize = function() { |
|
2785 return d3_scale_quantize(0, 1, [0, 1]); |
|
2786 }; |
|
2787 |
|
2788 function d3_scale_quantize(x0, x1, range) { |
|
2789 var kx, i; |
|
2790 |
|
2791 function scale(x) { |
|
2792 return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))]; |
|
2793 } |
|
2794 |
|
2795 function rescale() { |
|
2796 kx = range.length / (x1 - x0); |
|
2797 i = range.length - 1; |
|
2798 return scale; |
|
2799 } |
|
2800 |
|
2801 scale.domain = function(x) { |
|
2802 if (!arguments.length) return [x0, x1]; |
|
2803 x0 = +x[0]; |
|
2804 x1 = +x[x.length - 1]; |
|
2805 return rescale(); |
|
2806 }; |
|
2807 |
|
2808 scale.range = function(x) { |
|
2809 if (!arguments.length) return range; |
|
2810 range = x; |
|
2811 return rescale(); |
|
2812 }; |
|
2813 |
|
2814 scale.copy = function() { |
|
2815 return d3_scale_quantize(x0, x1, range); // copy on write |
|
2816 }; |
|
2817 |
|
2818 return rescale(); |
|
2819 }; |
|
2820 d3.svg = {}; |
|
2821 d3.svg.arc = function() { |
|
2822 var innerRadius = d3_svg_arcInnerRadius, |
|
2823 outerRadius = d3_svg_arcOuterRadius, |
|
2824 startAngle = d3_svg_arcStartAngle, |
|
2825 endAngle = d3_svg_arcEndAngle; |
|
2826 |
|
2827 function arc() { |
|
2828 var r0 = innerRadius.apply(this, arguments), |
|
2829 r1 = outerRadius.apply(this, arguments), |
|
2830 a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, |
|
2831 a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset, |
|
2832 da = (a1 < a0 && (da = a0, a0 = a1, a1 = da), a1 - a0), |
|
2833 df = da < Math.PI ? "0" : "1", |
|
2834 c0 = Math.cos(a0), |
|
2835 s0 = Math.sin(a0), |
|
2836 c1 = Math.cos(a1), |
|
2837 s1 = Math.sin(a1); |
|
2838 return da >= d3_svg_arcMax |
|
2839 ? (r0 |
|
2840 ? "M0," + r1 |
|
2841 + "A" + r1 + "," + r1 + " 0 1,1 0," + (-r1) |
|
2842 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 |
|
2843 + "M0," + r0 |
|
2844 + "A" + r0 + "," + r0 + " 0 1,0 0," + (-r0) |
|
2845 + "A" + r0 + "," + r0 + " 0 1,0 0," + r0 |
|
2846 + "Z" |
|
2847 : "M0," + r1 |
|
2848 + "A" + r1 + "," + r1 + " 0 1,1 0," + (-r1) |
|
2849 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 |
|
2850 + "Z") |
|
2851 : (r0 |
|
2852 ? "M" + r1 * c0 + "," + r1 * s0 |
|
2853 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 |
|
2854 + "L" + r0 * c1 + "," + r0 * s1 |
|
2855 + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0 |
|
2856 + "Z" |
|
2857 : "M" + r1 * c0 + "," + r1 * s0 |
|
2858 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 |
|
2859 + "L0,0" |
|
2860 + "Z"); |
|
2861 } |
|
2862 |
|
2863 arc.innerRadius = function(v) { |
|
2864 if (!arguments.length) return innerRadius; |
|
2865 innerRadius = d3.functor(v); |
|
2866 return arc; |
|
2867 }; |
|
2868 |
|
2869 arc.outerRadius = function(v) { |
|
2870 if (!arguments.length) return outerRadius; |
|
2871 outerRadius = d3.functor(v); |
|
2872 return arc; |
|
2873 }; |
|
2874 |
|
2875 arc.startAngle = function(v) { |
|
2876 if (!arguments.length) return startAngle; |
|
2877 startAngle = d3.functor(v); |
|
2878 return arc; |
|
2879 }; |
|
2880 |
|
2881 arc.endAngle = function(v) { |
|
2882 if (!arguments.length) return endAngle; |
|
2883 endAngle = d3.functor(v); |
|
2884 return arc; |
|
2885 }; |
|
2886 |
|
2887 arc.centroid = function() { |
|
2888 var r = (innerRadius.apply(this, arguments) |
|
2889 + outerRadius.apply(this, arguments)) / 2, |
|
2890 a = (startAngle.apply(this, arguments) |
|
2891 + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset; |
|
2892 return [Math.cos(a) * r, Math.sin(a) * r]; |
|
2893 }; |
|
2894 |
|
2895 return arc; |
|
2896 }; |
|
2897 |
|
2898 var d3_svg_arcOffset = -Math.PI / 2, |
|
2899 d3_svg_arcMax = 2 * Math.PI - 1e-6; |
|
2900 |
|
2901 function d3_svg_arcInnerRadius(d) { |
|
2902 return d.innerRadius; |
|
2903 } |
|
2904 |
|
2905 function d3_svg_arcOuterRadius(d) { |
|
2906 return d.outerRadius; |
|
2907 } |
|
2908 |
|
2909 function d3_svg_arcStartAngle(d) { |
|
2910 return d.startAngle; |
|
2911 } |
|
2912 |
|
2913 function d3_svg_arcEndAngle(d) { |
|
2914 return d.endAngle; |
|
2915 } |
|
2916 function d3_svg_line(projection) { |
|
2917 var x = d3_svg_lineX, |
|
2918 y = d3_svg_lineY, |
|
2919 interpolate = "linear", |
|
2920 interpolator = d3_svg_lineInterpolators[interpolate], |
|
2921 tension = .7; |
|
2922 |
|
2923 function line(d) { |
|
2924 return d.length < 1 ? null : "M" + interpolator(projection(d3_svg_linePoints(this, d, x, y)), tension); |
|
2925 } |
|
2926 |
|
2927 line.x = function(v) { |
|
2928 if (!arguments.length) return x; |
|
2929 x = v; |
|
2930 return line; |
|
2931 }; |
|
2932 |
|
2933 line.y = function(v) { |
|
2934 if (!arguments.length) return y; |
|
2935 y = v; |
|
2936 return line; |
|
2937 }; |
|
2938 |
|
2939 line.interpolate = function(v) { |
|
2940 if (!arguments.length) return interpolate; |
|
2941 interpolator = d3_svg_lineInterpolators[interpolate = v]; |
|
2942 return line; |
|
2943 }; |
|
2944 |
|
2945 line.tension = function(v) { |
|
2946 if (!arguments.length) return tension; |
|
2947 tension = v; |
|
2948 return line; |
|
2949 }; |
|
2950 |
|
2951 return line; |
|
2952 } |
|
2953 |
|
2954 d3.svg.line = function() { |
|
2955 return d3_svg_line(Object); |
|
2956 }; |
|
2957 |
|
2958 // Converts the specified array of data into an array of points |
|
2959 // (x-y tuples), by evaluating the specified `x` and `y` functions on each |
|
2960 // data point. The `this` context of the evaluated functions is the specified |
|
2961 // "self" object; each function is passed the current datum and index. |
|
2962 function d3_svg_linePoints(self, d, x, y) { |
|
2963 var points = [], |
|
2964 i = -1, |
|
2965 n = d.length, |
|
2966 fx = typeof x === "function", |
|
2967 fy = typeof y === "function", |
|
2968 value; |
|
2969 if (fx && fy) { |
|
2970 while (++i < n) points.push([ |
|
2971 x.call(self, value = d[i], i), |
|
2972 y.call(self, value, i) |
|
2973 ]); |
|
2974 } else if (fx) { |
|
2975 while (++i < n) points.push([x.call(self, d[i], i), y]); |
|
2976 } else if (fy) { |
|
2977 while (++i < n) points.push([x, y.call(self, d[i], i)]); |
|
2978 } else { |
|
2979 while (++i < n) points.push([x, y]); |
|
2980 } |
|
2981 return points; |
|
2982 } |
|
2983 |
|
2984 // The default `x` property, which references d[0]. |
|
2985 function d3_svg_lineX(d) { |
|
2986 return d[0]; |
|
2987 } |
|
2988 |
|
2989 // The default `y` property, which references d[1]. |
|
2990 function d3_svg_lineY(d) { |
|
2991 return d[1]; |
|
2992 } |
|
2993 |
|
2994 // The various interpolators supported by the `line` class. |
|
2995 var d3_svg_lineInterpolators = { |
|
2996 "linear": d3_svg_lineLinear, |
|
2997 "step-before": d3_svg_lineStepBefore, |
|
2998 "step-after": d3_svg_lineStepAfter, |
|
2999 "basis": d3_svg_lineBasis, |
|
3000 "basis-open": d3_svg_lineBasisOpen, |
|
3001 "basis-closed": d3_svg_lineBasisClosed, |
|
3002 "bundle": d3_svg_lineBundle, |
|
3003 "cardinal": d3_svg_lineCardinal, |
|
3004 "cardinal-open": d3_svg_lineCardinalOpen, |
|
3005 "cardinal-closed": d3_svg_lineCardinalClosed, |
|
3006 "monotone": d3_svg_lineMonotone |
|
3007 }; |
|
3008 |
|
3009 // Linear interpolation; generates "L" commands. |
|
3010 function d3_svg_lineLinear(points) { |
|
3011 var i = 0, |
|
3012 n = points.length, |
|
3013 p = points[0], |
|
3014 path = [p[0], ",", p[1]]; |
|
3015 while (++i < n) path.push("L", (p = points[i])[0], ",", p[1]); |
|
3016 return path.join(""); |
|
3017 } |
|
3018 |
|
3019 // Step interpolation; generates "H" and "V" commands. |
|
3020 function d3_svg_lineStepBefore(points) { |
|
3021 var i = 0, |
|
3022 n = points.length, |
|
3023 p = points[0], |
|
3024 path = [p[0], ",", p[1]]; |
|
3025 while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]); |
|
3026 return path.join(""); |
|
3027 } |
|
3028 |
|
3029 // Step interpolation; generates "H" and "V" commands. |
|
3030 function d3_svg_lineStepAfter(points) { |
|
3031 var i = 0, |
|
3032 n = points.length, |
|
3033 p = points[0], |
|
3034 path = [p[0], ",", p[1]]; |
|
3035 while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]); |
|
3036 return path.join(""); |
|
3037 } |
|
3038 |
|
3039 // Open cardinal spline interpolation; generates "C" commands. |
|
3040 function d3_svg_lineCardinalOpen(points, tension) { |
|
3041 return points.length < 4 |
|
3042 ? d3_svg_lineLinear(points) |
|
3043 : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1), |
|
3044 d3_svg_lineCardinalTangents(points, tension)); |
|
3045 } |
|
3046 |
|
3047 // Closed cardinal spline interpolation; generates "C" commands. |
|
3048 function d3_svg_lineCardinalClosed(points, tension) { |
|
3049 return points.length < 3 |
|
3050 ? d3_svg_lineLinear(points) |
|
3051 : points[0] + d3_svg_lineHermite((points.push(points[0]), points), |
|
3052 d3_svg_lineCardinalTangents([points[points.length - 2]] |
|
3053 .concat(points, [points[1]]), tension)); |
|
3054 } |
|
3055 |
|
3056 // Cardinal spline interpolation; generates "C" commands. |
|
3057 function d3_svg_lineCardinal(points, tension, closed) { |
|
3058 return points.length < 3 |
|
3059 ? d3_svg_lineLinear(points) |
|
3060 : points[0] + d3_svg_lineHermite(points, |
|
3061 d3_svg_lineCardinalTangents(points, tension)); |
|
3062 } |
|
3063 |
|
3064 // Hermite spline construction; generates "C" commands. |
|
3065 function d3_svg_lineHermite(points, tangents) { |
|
3066 if (tangents.length < 1 |
|
3067 || (points.length != tangents.length |
|
3068 && points.length != tangents.length + 2)) { |
|
3069 return d3_svg_lineLinear(points); |
|
3070 } |
|
3071 |
|
3072 var quad = points.length != tangents.length, |
|
3073 path = "", |
|
3074 p0 = points[0], |
|
3075 p = points[1], |
|
3076 t0 = tangents[0], |
|
3077 t = t0, |
|
3078 pi = 1; |
|
3079 |
|
3080 if (quad) { |
|
3081 path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) |
|
3082 + "," + p[0] + "," + p[1]; |
|
3083 p0 = points[1]; |
|
3084 pi = 2; |
|
3085 } |
|
3086 |
|
3087 if (tangents.length > 1) { |
|
3088 t = tangents[1]; |
|
3089 p = points[pi]; |
|
3090 pi++; |
|
3091 path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) |
|
3092 + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) |
|
3093 + "," + p[0] + "," + p[1]; |
|
3094 for (var i = 2; i < tangents.length; i++, pi++) { |
|
3095 p = points[pi]; |
|
3096 t = tangents[i]; |
|
3097 path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) |
|
3098 + "," + p[0] + "," + p[1]; |
|
3099 } |
|
3100 } |
|
3101 |
|
3102 if (quad) { |
|
3103 var lp = points[pi]; |
|
3104 path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) |
|
3105 + "," + lp[0] + "," + lp[1]; |
|
3106 } |
|
3107 |
|
3108 return path; |
|
3109 } |
|
3110 |
|
3111 // Generates tangents for a cardinal spline. |
|
3112 function d3_svg_lineCardinalTangents(points, tension) { |
|
3113 var tangents = [], |
|
3114 a = (1 - tension) / 2, |
|
3115 p0, |
|
3116 p1 = points[0], |
|
3117 p2 = points[1], |
|
3118 i = 1, |
|
3119 n = points.length; |
|
3120 while (++i < n) { |
|
3121 p0 = p1; |
|
3122 p1 = p2; |
|
3123 p2 = points[i]; |
|
3124 tangents.push([a * (p2[0] - p0[0]), a * (p2[1] - p0[1])]); |
|
3125 } |
|
3126 return tangents; |
|
3127 } |
|
3128 |
|
3129 // B-spline interpolation; generates "C" commands. |
|
3130 function d3_svg_lineBasis(points) { |
|
3131 if (points.length < 3) return d3_svg_lineLinear(points); |
|
3132 var i = 1, |
|
3133 n = points.length, |
|
3134 pi = points[0], |
|
3135 x0 = pi[0], |
|
3136 y0 = pi[1], |
|
3137 px = [x0, x0, x0, (pi = points[1])[0]], |
|
3138 py = [y0, y0, y0, pi[1]], |
|
3139 path = [x0, ",", y0]; |
|
3140 d3_svg_lineBasisBezier(path, px, py); |
|
3141 while (++i < n) { |
|
3142 pi = points[i]; |
|
3143 px.shift(); px.push(pi[0]); |
|
3144 py.shift(); py.push(pi[1]); |
|
3145 d3_svg_lineBasisBezier(path, px, py); |
|
3146 } |
|
3147 i = -1; |
|
3148 while (++i < 2) { |
|
3149 px.shift(); px.push(pi[0]); |
|
3150 py.shift(); py.push(pi[1]); |
|
3151 d3_svg_lineBasisBezier(path, px, py); |
|
3152 } |
|
3153 return path.join(""); |
|
3154 } |
|
3155 |
|
3156 // Open B-spline interpolation; generates "C" commands. |
|
3157 function d3_svg_lineBasisOpen(points) { |
|
3158 if (points.length < 4) return d3_svg_lineLinear(points); |
|
3159 var path = [], |
|
3160 i = -1, |
|
3161 n = points.length, |
|
3162 pi, |
|
3163 px = [0], |
|
3164 py = [0]; |
|
3165 while (++i < 3) { |
|
3166 pi = points[i]; |
|
3167 px.push(pi[0]); |
|
3168 py.push(pi[1]); |
|
3169 } |
|
3170 path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) |
|
3171 + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py)); |
|
3172 --i; while (++i < n) { |
|
3173 pi = points[i]; |
|
3174 px.shift(); px.push(pi[0]); |
|
3175 py.shift(); py.push(pi[1]); |
|
3176 d3_svg_lineBasisBezier(path, px, py); |
|
3177 } |
|
3178 return path.join(""); |
|
3179 } |
|
3180 |
|
3181 // Closed B-spline interpolation; generates "C" commands. |
|
3182 function d3_svg_lineBasisClosed(points) { |
|
3183 var path, |
|
3184 i = -1, |
|
3185 n = points.length, |
|
3186 m = n + 4, |
|
3187 pi, |
|
3188 px = [], |
|
3189 py = []; |
|
3190 while (++i < 4) { |
|
3191 pi = points[i % n]; |
|
3192 px.push(pi[0]); |
|
3193 py.push(pi[1]); |
|
3194 } |
|
3195 path = [ |
|
3196 d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", |
|
3197 d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) |
|
3198 ]; |
|
3199 --i; while (++i < m) { |
|
3200 pi = points[i % n]; |
|
3201 px.shift(); px.push(pi[0]); |
|
3202 py.shift(); py.push(pi[1]); |
|
3203 d3_svg_lineBasisBezier(path, px, py); |
|
3204 } |
|
3205 return path.join(""); |
|
3206 } |
|
3207 |
|
3208 function d3_svg_lineBundle(points, tension) { |
|
3209 var n = points.length - 1, |
|
3210 x0 = points[0][0], |
|
3211 y0 = points[0][1], |
|
3212 dx = points[n][0] - x0, |
|
3213 dy = points[n][1] - y0, |
|
3214 i = -1, |
|
3215 p, |
|
3216 t; |
|
3217 while (++i <= n) { |
|
3218 p = points[i]; |
|
3219 t = i / n; |
|
3220 p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx); |
|
3221 p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy); |
|
3222 } |
|
3223 return d3_svg_lineBasis(points); |
|
3224 } |
|
3225 |
|
3226 // Returns the dot product of the given four-element vectors. |
|
3227 function d3_svg_lineDot4(a, b) { |
|
3228 return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; |
|
3229 } |
|
3230 |
|
3231 // Matrix to transform basis (b-spline) control points to bezier |
|
3232 // control points. Derived from FvD 11.2.8. |
|
3233 var d3_svg_lineBasisBezier1 = [0, 2/3, 1/3, 0], |
|
3234 d3_svg_lineBasisBezier2 = [0, 1/3, 2/3, 0], |
|
3235 d3_svg_lineBasisBezier3 = [0, 1/6, 2/3, 1/6]; |
|
3236 |
|
3237 // Pushes a "C" Bézier curve onto the specified path array, given the |
|
3238 // two specified four-element arrays which define the control points. |
|
3239 function d3_svg_lineBasisBezier(path, x, y) { |
|
3240 path.push( |
|
3241 "C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), |
|
3242 ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), |
|
3243 ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), |
|
3244 ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), |
|
3245 ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), |
|
3246 ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y)); |
|
3247 } |
|
3248 |
|
3249 // Computes the slope from points p0 to p1. |
|
3250 function d3_svg_lineSlope(p0, p1) { |
|
3251 return (p1[1] - p0[1]) / (p1[0] - p0[0]); |
|
3252 } |
|
3253 |
|
3254 // Compute three-point differences for the given points. |
|
3255 // http://en.wikipedia.org/wiki/Cubic_Hermite_spline#Finite_difference |
|
3256 function d3_svg_lineFiniteDifferences(points) { |
|
3257 var i = 0, |
|
3258 j = points.length - 1, |
|
3259 m = [], |
|
3260 p0 = points[0], |
|
3261 p1 = points[1], |
|
3262 d = m[0] = d3_svg_lineSlope(p0, p1); |
|
3263 while (++i < j) { |
|
3264 m[i] = d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1])); |
|
3265 } |
|
3266 m[i] = d; |
|
3267 return m; |
|
3268 } |
|
3269 |
|
3270 // Interpolates the given points using Fritsch-Carlson Monotone cubic Hermite |
|
3271 // interpolation. Returns an array of tangent vectors. For details, see |
|
3272 // http://en.wikipedia.org/wiki/Monotone_cubic_interpolation |
|
3273 function d3_svg_lineMonotoneTangents(points) { |
|
3274 var tangents = [], |
|
3275 d, |
|
3276 a, |
|
3277 b, |
|
3278 s, |
|
3279 m = d3_svg_lineFiniteDifferences(points), |
|
3280 i = -1, |
|
3281 j = points.length - 1; |
|
3282 |
|
3283 // The first two steps are done by computing finite-differences: |
|
3284 // 1. Compute the slopes of the secant lines between successive points. |
|
3285 // 2. Initialize the tangents at every point as the average of the secants. |
|
3286 |
|
3287 // Then, for each segment… |
|
3288 while (++i < j) { |
|
3289 d = d3_svg_lineSlope(points[i], points[i + 1]); |
|
3290 |
|
3291 // 3. If two successive yk = y{k + 1} are equal (i.e., d is zero), then set |
|
3292 // mk = m{k + 1} = 0 as the spline connecting these points must be flat to |
|
3293 // preserve monotonicity. Ignore step 4 and 5 for those k. |
|
3294 |
|
3295 if (Math.abs(d) < 1e-6) { |
|
3296 m[i] = m[i + 1] = 0; |
|
3297 } else { |
|
3298 // 4. Let ak = mk / dk and bk = m{k + 1} / dk. |
|
3299 a = m[i] / d; |
|
3300 b = m[i + 1] / d; |
|
3301 |
|
3302 // 5. Prevent overshoot and ensure monotonicity by restricting the |
|
3303 // magnitude of vector <ak, bk> to a circle of radius 3. |
|
3304 s = a * a + b * b; |
|
3305 if (s > 9) { |
|
3306 s = d * 3 / Math.sqrt(s); |
|
3307 m[i] = s * a; |
|
3308 m[i + 1] = s * b; |
|
3309 } |
|
3310 } |
|
3311 } |
|
3312 |
|
3313 // Compute the normalized tangent vector from the slopes. Note that if x is |
|
3314 // not monotonic, it's possible that the slope will be infinite, so we protect |
|
3315 // against NaN by setting the coordinate to zero. |
|
3316 i = -1; while (++i <= j) { |
|
3317 s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) |
|
3318 / (6 * (1 + m[i] * m[i])); |
|
3319 tangents.push([s || 0, m[i] * s || 0]); |
|
3320 } |
|
3321 |
|
3322 return tangents; |
|
3323 } |
|
3324 |
|
3325 function d3_svg_lineMonotone(points) { |
|
3326 return points.length < 3 |
|
3327 ? d3_svg_lineLinear(points) |
|
3328 : points[0] + |
|
3329 d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points)); |
|
3330 } |
|
3331 d3.svg.line.radial = function() { |
|
3332 var line = d3_svg_line(d3_svg_lineRadial); |
|
3333 line.radius = line.x, delete line.x; |
|
3334 line.angle = line.y, delete line.y; |
|
3335 return line; |
|
3336 }; |
|
3337 |
|
3338 function d3_svg_lineRadial(points) { |
|
3339 var point, |
|
3340 i = -1, |
|
3341 n = points.length, |
|
3342 r, |
|
3343 a; |
|
3344 while (++i < n) { |
|
3345 point = points[i]; |
|
3346 r = point[0]; |
|
3347 a = point[1] + d3_svg_arcOffset; |
|
3348 point[0] = r * Math.cos(a); |
|
3349 point[1] = r * Math.sin(a); |
|
3350 } |
|
3351 return points; |
|
3352 } |
|
3353 function d3_svg_area(projection) { |
|
3354 var x0 = d3_svg_lineX, |
|
3355 x1 = d3_svg_lineX, |
|
3356 y0 = 0, |
|
3357 y1 = d3_svg_lineY, |
|
3358 interpolate, |
|
3359 i0, |
|
3360 i1, |
|
3361 tension = .7; |
|
3362 |
|
3363 function area(d) { |
|
3364 if (d.length < 1) return null; |
|
3365 var points0 = d3_svg_linePoints(this, d, x0, y0), |
|
3366 points1 = d3_svg_linePoints(this, d, x0 === x1 ? d3_svg_areaX(points0) : x1, y0 === y1 ? d3_svg_areaY(points0) : y1); |
|
3367 return "M" + i0(projection(points1), tension) |
|
3368 + "L" + i1(projection(points0.reverse()), tension) |
|
3369 + "Z"; |
|
3370 } |
|
3371 |
|
3372 area.x = function(x) { |
|
3373 if (!arguments.length) return x1; |
|
3374 x0 = x1 = x; |
|
3375 return area; |
|
3376 }; |
|
3377 |
|
3378 area.x0 = function(x) { |
|
3379 if (!arguments.length) return x0; |
|
3380 x0 = x; |
|
3381 return area; |
|
3382 }; |
|
3383 |
|
3384 area.x1 = function(x) { |
|
3385 if (!arguments.length) return x1; |
|
3386 x1 = x; |
|
3387 return area; |
|
3388 }; |
|
3389 |
|
3390 area.y = function(y) { |
|
3391 if (!arguments.length) return y1; |
|
3392 y0 = y1 = y; |
|
3393 return area; |
|
3394 }; |
|
3395 |
|
3396 area.y0 = function(y) { |
|
3397 if (!arguments.length) return y0; |
|
3398 y0 = y; |
|
3399 return area; |
|
3400 }; |
|
3401 |
|
3402 area.y1 = function(y) { |
|
3403 if (!arguments.length) return y1; |
|
3404 y1 = y; |
|
3405 return area; |
|
3406 }; |
|
3407 |
|
3408 area.interpolate = function(x) { |
|
3409 if (!arguments.length) return interpolate; |
|
3410 i0 = d3_svg_lineInterpolators[interpolate = x]; |
|
3411 i1 = i0.reverse || i0; |
|
3412 return area; |
|
3413 }; |
|
3414 |
|
3415 area.tension = function(x) { |
|
3416 if (!arguments.length) return tension; |
|
3417 tension = x; |
|
3418 return area; |
|
3419 }; |
|
3420 |
|
3421 return area.interpolate("linear"); |
|
3422 } |
|
3423 |
|
3424 d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter; |
|
3425 d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore; |
|
3426 |
|
3427 d3.svg.area = function() { |
|
3428 return d3_svg_area(Object); |
|
3429 }; |
|
3430 |
|
3431 function d3_svg_areaX(points) { |
|
3432 return function(d, i) { |
|
3433 return points[i][0]; |
|
3434 }; |
|
3435 } |
|
3436 |
|
3437 function d3_svg_areaY(points) { |
|
3438 return function(d, i) { |
|
3439 return points[i][1]; |
|
3440 }; |
|
3441 } |
|
3442 d3.svg.area.radial = function() { |
|
3443 var area = d3_svg_area(d3_svg_lineRadial); |
|
3444 area.radius = area.x, delete area.x; |
|
3445 area.innerRadius = area.x0, delete area.x0; |
|
3446 area.outerRadius = area.x1, delete area.x1; |
|
3447 area.angle = area.y, delete area.y; |
|
3448 area.startAngle = area.y0, delete area.y0; |
|
3449 area.endAngle = area.y1, delete area.y1; |
|
3450 return area; |
|
3451 }; |
|
3452 d3.svg.chord = function() { |
|
3453 var source = d3_svg_chordSource, |
|
3454 target = d3_svg_chordTarget, |
|
3455 radius = d3_svg_chordRadius, |
|
3456 startAngle = d3_svg_arcStartAngle, |
|
3457 endAngle = d3_svg_arcEndAngle; |
|
3458 |
|
3459 // TODO Allow control point to be customized. |
|
3460 |
|
3461 function chord(d, i) { |
|
3462 var s = subgroup(this, source, d, i), |
|
3463 t = subgroup(this, target, d, i); |
|
3464 return "M" + s.p0 |
|
3465 + arc(s.r, s.p1) + (equals(s, t) |
|
3466 ? curve(s.r, s.p1, s.r, s.p0) |
|
3467 : curve(s.r, s.p1, t.r, t.p0) |
|
3468 + arc(t.r, t.p1) |
|
3469 + curve(t.r, t.p1, s.r, s.p0)) |
|
3470 + "Z"; |
|
3471 } |
|
3472 |
|
3473 function subgroup(self, f, d, i) { |
|
3474 var subgroup = f.call(self, d, i), |
|
3475 r = radius.call(self, subgroup, i), |
|
3476 a0 = startAngle.call(self, subgroup, i) + d3_svg_arcOffset, |
|
3477 a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset; |
|
3478 return { |
|
3479 r: r, |
|
3480 a0: a0, |
|
3481 a1: a1, |
|
3482 p0: [r * Math.cos(a0), r * Math.sin(a0)], |
|
3483 p1: [r * Math.cos(a1), r * Math.sin(a1)] |
|
3484 }; |
|
3485 } |
|
3486 |
|
3487 function equals(a, b) { |
|
3488 return a.a0 == b.a0 && a.a1 == b.a1; |
|
3489 } |
|
3490 |
|
3491 function arc(r, p) { |
|
3492 return "A" + r + "," + r + " 0 0,1 " + p; |
|
3493 } |
|
3494 |
|
3495 function curve(r0, p0, r1, p1) { |
|
3496 return "Q 0,0 " + p1; |
|
3497 } |
|
3498 |
|
3499 chord.radius = function(v) { |
|
3500 if (!arguments.length) return radius; |
|
3501 radius = d3.functor(v); |
|
3502 return chord; |
|
3503 }; |
|
3504 |
|
3505 chord.source = function(v) { |
|
3506 if (!arguments.length) return source; |
|
3507 source = d3.functor(v); |
|
3508 return chord; |
|
3509 }; |
|
3510 |
|
3511 chord.target = function(v) { |
|
3512 if (!arguments.length) return target; |
|
3513 target = d3.functor(v); |
|
3514 return chord; |
|
3515 }; |
|
3516 |
|
3517 chord.startAngle = function(v) { |
|
3518 if (!arguments.length) return startAngle; |
|
3519 startAngle = d3.functor(v); |
|
3520 return chord; |
|
3521 }; |
|
3522 |
|
3523 chord.endAngle = function(v) { |
|
3524 if (!arguments.length) return endAngle; |
|
3525 endAngle = d3.functor(v); |
|
3526 return chord; |
|
3527 }; |
|
3528 |
|
3529 return chord; |
|
3530 }; |
|
3531 |
|
3532 function d3_svg_chordSource(d) { |
|
3533 return d.source; |
|
3534 } |
|
3535 |
|
3536 function d3_svg_chordTarget(d) { |
|
3537 return d.target; |
|
3538 } |
|
3539 |
|
3540 function d3_svg_chordRadius(d) { |
|
3541 return d.radius; |
|
3542 } |
|
3543 |
|
3544 function d3_svg_chordStartAngle(d) { |
|
3545 return d.startAngle; |
|
3546 } |
|
3547 |
|
3548 function d3_svg_chordEndAngle(d) { |
|
3549 return d.endAngle; |
|
3550 } |
|
3551 d3.svg.diagonal = function() { |
|
3552 var source = d3_svg_chordSource, |
|
3553 target = d3_svg_chordTarget, |
|
3554 projection = d3_svg_diagonalProjection; |
|
3555 |
|
3556 function diagonal(d, i) { |
|
3557 var p0 = source.call(this, d, i), |
|
3558 p3 = target.call(this, d, i), |
|
3559 m = (p0.y + p3.y) / 2, |
|
3560 p = [p0, {x: p0.x, y: m}, {x: p3.x, y: m}, p3]; |
|
3561 p = p.map(projection); |
|
3562 return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3]; |
|
3563 } |
|
3564 |
|
3565 diagonal.source = function(x) { |
|
3566 if (!arguments.length) return source; |
|
3567 source = d3.functor(x); |
|
3568 return diagonal; |
|
3569 }; |
|
3570 |
|
3571 diagonal.target = function(x) { |
|
3572 if (!arguments.length) return target; |
|
3573 target = d3.functor(x); |
|
3574 return diagonal; |
|
3575 }; |
|
3576 |
|
3577 diagonal.projection = function(x) { |
|
3578 if (!arguments.length) return projection; |
|
3579 projection = x; |
|
3580 return diagonal; |
|
3581 }; |
|
3582 |
|
3583 return diagonal; |
|
3584 }; |
|
3585 |
|
3586 function d3_svg_diagonalProjection(d) { |
|
3587 return [d.x, d.y]; |
|
3588 } |
|
3589 d3.svg.diagonal.radial = function() { |
|
3590 var diagonal = d3.svg.diagonal(), |
|
3591 projection = d3_svg_diagonalProjection, |
|
3592 projection_ = diagonal.projection; |
|
3593 |
|
3594 diagonal.projection = function(x) { |
|
3595 return arguments.length |
|
3596 ? projection_(d3_svg_diagonalRadialProjection(projection = x)) |
|
3597 : projection; |
|
3598 }; |
|
3599 |
|
3600 return diagonal; |
|
3601 }; |
|
3602 |
|
3603 function d3_svg_diagonalRadialProjection(projection) { |
|
3604 return function() { |
|
3605 var d = projection.apply(this, arguments), |
|
3606 r = d[0], |
|
3607 a = d[1] + d3_svg_arcOffset; |
|
3608 return [r * Math.cos(a), r * Math.sin(a)]; |
|
3609 }; |
|
3610 } |
|
3611 d3.svg.mouse = function(container) { |
|
3612 return d3_svg_mousePoint(container, d3.event); |
|
3613 }; |
|
3614 |
|
3615 // https://bugs.webkit.org/show_bug.cgi?id=44083 |
|
3616 var d3_mouse_bug44083 = /WebKit/.test(navigator.userAgent) ? -1 : 0; |
|
3617 |
|
3618 function d3_svg_mousePoint(container, e) { |
|
3619 var point = (container.ownerSVGElement || container).createSVGPoint(); |
|
3620 if ((d3_mouse_bug44083 < 0) && (window.scrollX || window.scrollY)) { |
|
3621 var svg = d3.select(document.body) |
|
3622 .append("svg:svg") |
|
3623 .style("position", "absolute") |
|
3624 .style("top", 0) |
|
3625 .style("left", 0); |
|
3626 var ctm = svg[0][0].getScreenCTM(); |
|
3627 d3_mouse_bug44083 = !(ctm.f || ctm.e); |
|
3628 svg.remove(); |
|
3629 } |
|
3630 if (d3_mouse_bug44083) { |
|
3631 point.x = e.pageX; |
|
3632 point.y = e.pageY; |
|
3633 } else { |
|
3634 point.x = e.clientX; |
|
3635 point.y = e.clientY; |
|
3636 } |
|
3637 point = point.matrixTransform(container.getScreenCTM().inverse()); |
|
3638 return [point.x, point.y]; |
|
3639 }; |
|
3640 d3.svg.touches = function(container, touches) { |
|
3641 if (arguments.length < 2) touches = d3.event.touches; |
|
3642 |
|
3643 return touches ? d3_array(touches).map(function(touch) { |
|
3644 var point = d3_svg_mousePoint(container, touch); |
|
3645 point.identifier = touch.identifier; |
|
3646 return point; |
|
3647 }) : []; |
|
3648 }; |
|
3649 d3.svg.symbol = function() { |
|
3650 var type = d3_svg_symbolType, |
|
3651 size = d3_svg_symbolSize; |
|
3652 |
|
3653 function symbol(d, i) { |
|
3654 return (d3_svg_symbols[type.call(this, d, i)] |
|
3655 || d3_svg_symbols.circle) |
|
3656 (size.call(this, d, i)); |
|
3657 } |
|
3658 |
|
3659 symbol.type = function(x) { |
|
3660 if (!arguments.length) return type; |
|
3661 type = d3.functor(x); |
|
3662 return symbol; |
|
3663 }; |
|
3664 |
|
3665 // size of symbol in square pixels |
|
3666 symbol.size = function(x) { |
|
3667 if (!arguments.length) return size; |
|
3668 size = d3.functor(x); |
|
3669 return symbol; |
|
3670 }; |
|
3671 |
|
3672 return symbol; |
|
3673 }; |
|
3674 |
|
3675 function d3_svg_symbolSize() { |
|
3676 return 64; |
|
3677 } |
|
3678 |
|
3679 function d3_svg_symbolType() { |
|
3680 return "circle"; |
|
3681 } |
|
3682 |
|
3683 // TODO cross-diagonal? |
|
3684 var d3_svg_symbols = { |
|
3685 "circle": function(size) { |
|
3686 var r = Math.sqrt(size / Math.PI); |
|
3687 return "M0," + r |
|
3688 + "A" + r + "," + r + " 0 1,1 0," + (-r) |
|
3689 + "A" + r + "," + r + " 0 1,1 0," + r |
|
3690 + "Z"; |
|
3691 }, |
|
3692 "cross": function(size) { |
|
3693 var r = Math.sqrt(size / 5) / 2; |
|
3694 return "M" + -3 * r + "," + -r |
|
3695 + "H" + -r |
|
3696 + "V" + -3 * r |
|
3697 + "H" + r |
|
3698 + "V" + -r |
|
3699 + "H" + 3 * r |
|
3700 + "V" + r |
|
3701 + "H" + r |
|
3702 + "V" + 3 * r |
|
3703 + "H" + -r |
|
3704 + "V" + r |
|
3705 + "H" + -3 * r |
|
3706 + "Z"; |
|
3707 }, |
|
3708 "diamond": function(size) { |
|
3709 var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), |
|
3710 rx = ry * d3_svg_symbolTan30; |
|
3711 return "M0," + -ry |
|
3712 + "L" + rx + ",0" |
|
3713 + " 0," + ry |
|
3714 + " " + -rx + ",0" |
|
3715 + "Z"; |
|
3716 }, |
|
3717 "square": function(size) { |
|
3718 var r = Math.sqrt(size) / 2; |
|
3719 return "M" + -r + "," + -r |
|
3720 + "L" + r + "," + -r |
|
3721 + " " + r + "," + r |
|
3722 + " " + -r + "," + r |
|
3723 + "Z"; |
|
3724 }, |
|
3725 "triangle-down": function(size) { |
|
3726 var rx = Math.sqrt(size / d3_svg_symbolSqrt3), |
|
3727 ry = rx * d3_svg_symbolSqrt3 / 2; |
|
3728 return "M0," + ry |
|
3729 + "L" + rx +"," + -ry |
|
3730 + " " + -rx + "," + -ry |
|
3731 + "Z"; |
|
3732 }, |
|
3733 "triangle-up": function(size) { |
|
3734 var rx = Math.sqrt(size / d3_svg_symbolSqrt3), |
|
3735 ry = rx * d3_svg_symbolSqrt3 / 2; |
|
3736 return "M0," + -ry |
|
3737 + "L" + rx +"," + ry |
|
3738 + " " + -rx + "," + ry |
|
3739 + "Z"; |
|
3740 } |
|
3741 }; |
|
3742 |
|
3743 d3.svg.symbolTypes = d3.keys(d3_svg_symbols); |
|
3744 |
|
3745 var d3_svg_symbolSqrt3 = Math.sqrt(3), |
|
3746 d3_svg_symbolTan30 = Math.tan(30 * Math.PI / 180); |
|
3747 d3.svg.axis = function() { |
|
3748 var scale = d3.scale.linear(), |
|
3749 orient = "bottom", |
|
3750 tickMajorSize = 6, |
|
3751 tickMinorSize = 6, |
|
3752 tickEndSize = 6, |
|
3753 tickPadding = 3, |
|
3754 tickArguments_ = [10], |
|
3755 tickFormat_, |
|
3756 tickSubdivide = 0; |
|
3757 |
|
3758 function axis(selection) { |
|
3759 selection.each(function(d, i, j) { |
|
3760 var g = d3.select(this); |
|
3761 |
|
3762 // If selection is a transition, create subtransitions. |
|
3763 var transition = selection.delay ? function(o) { |
|
3764 var id = d3_transitionInheritId; |
|
3765 try { |
|
3766 d3_transitionInheritId = selection.id; |
|
3767 return o.transition() |
|
3768 .delay(selection[j][i].delay) |
|
3769 .duration(selection[j][i].duration) |
|
3770 .ease(selection.ease()); |
|
3771 } finally { |
|
3772 d3_transitionInheritId = id; |
|
3773 } |
|
3774 } : Object; |
|
3775 |
|
3776 // Ticks. |
|
3777 var ticks = scale.ticks.apply(scale, tickArguments_), |
|
3778 tickFormat = tickFormat_ == null ? scale.tickFormat.apply(scale, tickArguments_) : tickFormat_; |
|
3779 |
|
3780 // Minor ticks. |
|
3781 var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide), |
|
3782 subtick = g.selectAll(".minor").data(subticks, String), |
|
3783 subtickEnter = subtick.enter().insert("svg:line", "g").attr("class", "tick minor").style("opacity", 1e-6), |
|
3784 subtickExit = transition(subtick.exit()).style("opacity", 1e-6).remove(), |
|
3785 subtickUpdate = transition(subtick).style("opacity", 1); |
|
3786 |
|
3787 // Major ticks. |
|
3788 var tick = g.selectAll("g").data(ticks, String), |
|
3789 tickEnter = tick.enter().insert("svg:g", "path").style("opacity", 1e-6), |
|
3790 tickExit = transition(tick.exit()).style("opacity", 1e-6).remove(), |
|
3791 tickUpdate = transition(tick).style("opacity", 1), |
|
3792 tickTransform; |
|
3793 |
|
3794 // Domain. |
|
3795 var range = d3_scaleExtent(scale.range()), |
|
3796 path = g.selectAll(".domain").data([0]), |
|
3797 pathEnter = path.enter().append("svg:path").attr("class", "domain"), |
|
3798 pathUpdate = transition(path); |
|
3799 |
|
3800 // Stash the new scale and grab the old scale. |
|
3801 var scale0 = this.__chart__ || scale; |
|
3802 this.__chart__ = scale.copy(); |
|
3803 |
|
3804 tickEnter.append("svg:line").attr("class", "tick"); |
|
3805 tickEnter.append("svg:text"); |
|
3806 tickUpdate.select("text").text(tickFormat); |
|
3807 |
|
3808 switch (orient) { |
|
3809 case "bottom": { |
|
3810 tickTransform = d3_svg_axisX; |
|
3811 subtickUpdate.attr("x2", 0).attr("y2", tickMinorSize); |
|
3812 tickUpdate.select("line").attr("x2", 0).attr("y2", tickMajorSize); |
|
3813 tickUpdate.select("text").attr("x", 0).attr("y", Math.max(tickMajorSize, 0) + tickPadding).attr("dy", ".71em").attr("text-anchor", "middle"); |
|
3814 pathUpdate.attr("d", "M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize); |
|
3815 break; |
|
3816 } |
|
3817 case "top": { |
|
3818 tickTransform = d3_svg_axisX; |
|
3819 subtickUpdate.attr("x2", 0).attr("y2", -tickMinorSize); |
|
3820 tickUpdate.select("line").attr("x2", 0).attr("y2", -tickMajorSize); |
|
3821 tickUpdate.select("text").attr("x", 0).attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("dy", "0em").attr("text-anchor", "middle"); |
|
3822 pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize); |
|
3823 break; |
|
3824 } |
|
3825 case "left": { |
|
3826 tickTransform = d3_svg_axisY; |
|
3827 subtickUpdate.attr("x2", -tickMinorSize).attr("y2", 0); |
|
3828 tickUpdate.select("line").attr("x2", -tickMajorSize).attr("y2", 0); |
|
3829 tickUpdate.select("text").attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", 0).attr("dy", ".32em").attr("text-anchor", "end"); |
|
3830 pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize); |
|
3831 break; |
|
3832 } |
|
3833 case "right": { |
|
3834 tickTransform = d3_svg_axisY; |
|
3835 subtickUpdate.attr("x2", tickMinorSize).attr("y2", 0); |
|
3836 tickUpdate.select("line").attr("x2", tickMajorSize).attr("y2", 0); |
|
3837 tickUpdate.select("text").attr("x", Math.max(tickMajorSize, 0) + tickPadding).attr("y", 0).attr("dy", ".32em").attr("text-anchor", "start"); |
|
3838 pathUpdate.attr("d", "M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize); |
|
3839 break; |
|
3840 } |
|
3841 } |
|
3842 |
|
3843 tickEnter.call(tickTransform, scale0); |
|
3844 tickUpdate.call(tickTransform, scale); |
|
3845 tickExit.call(tickTransform, scale); |
|
3846 |
|
3847 subtickEnter.call(tickTransform, scale0); |
|
3848 subtickUpdate.call(tickTransform, scale); |
|
3849 subtickExit.call(tickTransform, scale); |
|
3850 }); |
|
3851 } |
|
3852 |
|
3853 axis.scale = function(x) { |
|
3854 if (!arguments.length) return scale; |
|
3855 scale = x; |
|
3856 return axis; |
|
3857 }; |
|
3858 |
|
3859 axis.orient = function(x) { |
|
3860 if (!arguments.length) return orient; |
|
3861 orient = x; |
|
3862 return axis; |
|
3863 }; |
|
3864 |
|
3865 axis.ticks = function() { |
|
3866 if (!arguments.length) return tickArguments_; |
|
3867 tickArguments_ = arguments; |
|
3868 return axis; |
|
3869 }; |
|
3870 |
|
3871 axis.tickFormat = function(x) { |
|
3872 if (!arguments.length) return tickFormat_; |
|
3873 tickFormat_ = x; |
|
3874 return axis; |
|
3875 }; |
|
3876 |
|
3877 axis.tickSize = function(x, y, z) { |
|
3878 if (!arguments.length) return tickMajorSize; |
|
3879 var n = arguments.length - 1; |
|
3880 tickMajorSize = +x; |
|
3881 tickMinorSize = n > 1 ? +y : tickMajorSize; |
|
3882 tickEndSize = n > 0 ? +arguments[n] : tickMajorSize; |
|
3883 return axis; |
|
3884 }; |
|
3885 |
|
3886 axis.tickPadding = function(x) { |
|
3887 if (!arguments.length) return tickPadding; |
|
3888 tickPadding = +x; |
|
3889 return axis; |
|
3890 }; |
|
3891 |
|
3892 axis.tickSubdivide = function(x) { |
|
3893 if (!arguments.length) return tickSubdivide; |
|
3894 tickSubdivide = +x; |
|
3895 return axis; |
|
3896 }; |
|
3897 |
|
3898 return axis; |
|
3899 }; |
|
3900 |
|
3901 function d3_svg_axisX(selection, x) { |
|
3902 selection.attr("transform", function(d) { return "translate(" + x(d) + ",0)"; }); |
|
3903 } |
|
3904 |
|
3905 function d3_svg_axisY(selection, y) { |
|
3906 selection.attr("transform", function(d) { return "translate(0," + y(d) + ")"; }); |
|
3907 } |
|
3908 |
|
3909 function d3_svg_axisSubdivide(scale, ticks, m) { |
|
3910 subticks = []; |
|
3911 if (m && ticks.length > 1) { |
|
3912 var extent = d3_scaleExtent(scale.domain()), |
|
3913 subticks, |
|
3914 i = -1, |
|
3915 n = ticks.length, |
|
3916 d = (ticks[1] - ticks[0]) / ++m, |
|
3917 j, |
|
3918 v; |
|
3919 while (++i < n) { |
|
3920 for (j = m; --j > 0;) { |
|
3921 if ((v = +ticks[i] - j * d) >= extent[0]) { |
|
3922 subticks.push(v); |
|
3923 } |
|
3924 } |
|
3925 } |
|
3926 for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1];) { |
|
3927 subticks.push(v); |
|
3928 } |
|
3929 } |
|
3930 return subticks; |
|
3931 } |
|
3932 d3.svg.brush = function() { |
|
3933 var event = d3.dispatch("brushstart", "brush", "brushend"), |
|
3934 x, // x-scale, optional |
|
3935 y, // y-scale, optional |
|
3936 extent = [[0, 0], [0, 0]]; // [x0, y0], [x1, y1] |
|
3937 |
|
3938 function brush(g) { |
|
3939 var resizes = x && y ? ["n", "e", "s", "w", "nw", "ne", "se", "sw"] |
|
3940 : x ? ["e", "w"] |
|
3941 : y ? ["n", "s"] |
|
3942 : []; |
|
3943 |
|
3944 g.each(function() { |
|
3945 var g = d3.select(this).on("mousedown.brush", down), |
|
3946 bg = g.selectAll(".background").data([,]), |
|
3947 fg = g.selectAll(".extent").data([,]), |
|
3948 tz = g.selectAll(".resize").data(resizes, String), |
|
3949 e; |
|
3950 |
|
3951 // An invisible, mouseable area for starting a new brush. |
|
3952 bg.enter().append("svg:rect") |
|
3953 .attr("class", "background") |
|
3954 .style("visibility", "hidden") |
|
3955 .style("pointer-events", "all") |
|
3956 .style("cursor", "crosshair"); |
|
3957 |
|
3958 // The visible brush extent; style this as you like! |
|
3959 fg.enter().append("svg:rect") |
|
3960 .attr("class", "extent") |
|
3961 .style("cursor", "move"); |
|
3962 |
|
3963 // More invisible rects for resizing the extent. |
|
3964 tz.enter().append("svg:rect") |
|
3965 .attr("class", function(d) { return "resize " + d; }) |
|
3966 .attr("width", 6) |
|
3967 .attr("height", 6) |
|
3968 .style("visibility", "hidden") |
|
3969 .style("pointer-events", brush.empty() ? "none" : "all") |
|
3970 .style("cursor", function(d) { return d3_svg_brushCursor[d]; }); |
|
3971 |
|
3972 // Remove any superfluous resizers. |
|
3973 tz.exit().remove(); |
|
3974 |
|
3975 // Initialize the background to fill the defined range. |
|
3976 // If the range isn't defined, you can post-process. |
|
3977 if (x) { |
|
3978 e = d3_scaleExtent(x.range()); |
|
3979 bg.attr("x", e[0]).attr("width", e[1] - e[0]); |
|
3980 d3_svg_brushRedrawX(g, extent); |
|
3981 } |
|
3982 if (y) { |
|
3983 e = d3_scaleExtent(y.range()); |
|
3984 bg.attr("y", e[0]).attr("height", e[1] - e[0]); |
|
3985 d3_svg_brushRedrawY(g, extent); |
|
3986 } |
|
3987 }); |
|
3988 } |
|
3989 |
|
3990 function down() { |
|
3991 var target = d3.select(d3.event.target); |
|
3992 |
|
3993 // Store some global state for the duration of the brush gesture. |
|
3994 d3_svg_brush = brush; |
|
3995 d3_svg_brushTarget = this; |
|
3996 d3_svg_brushExtent = extent; |
|
3997 d3_svg_brushOffset = d3.svg.mouse(d3_svg_brushTarget); |
|
3998 |
|
3999 // If the extent was clicked on, drag rather than brush; |
|
4000 // store the offset between the mouse and extent origin instead. |
|
4001 if (d3_svg_brushDrag = target.classed("extent")) { |
|
4002 d3_svg_brushOffset[0] = extent[0][0] - d3_svg_brushOffset[0]; |
|
4003 d3_svg_brushOffset[1] = extent[0][1] - d3_svg_brushOffset[1]; |
|
4004 } |
|
4005 |
|
4006 // If a resizer was clicked on, record which side is to be resized. |
|
4007 // Also, set the offset to the opposite side. |
|
4008 else if (target.classed("resize")) { |
|
4009 d3_svg_brushResize = d3.event.target.__data__; |
|
4010 d3_svg_brushOffset[0] = extent[+/w$/.test(d3_svg_brushResize)][0]; |
|
4011 d3_svg_brushOffset[1] = extent[+/^n/.test(d3_svg_brushResize)][1]; |
|
4012 } |
|
4013 |
|
4014 // If the ALT key is down when starting a brush, the center is at the mouse. |
|
4015 else if (d3.event.altKey) { |
|
4016 d3_svg_brushCenter = d3_svg_brushOffset.slice(); |
|
4017 } |
|
4018 |
|
4019 // Restrict which dimensions are resized. |
|
4020 d3_svg_brushX = !/^(n|s)$/.test(d3_svg_brushResize) && x; |
|
4021 d3_svg_brushY = !/^(e|w)$/.test(d3_svg_brushResize) && y; |
|
4022 |
|
4023 // Notify listeners. |
|
4024 d3_svg_brushDispatch = dispatcher(this, arguments); |
|
4025 d3_svg_brushDispatch("brushstart"); |
|
4026 d3_svg_brushMove(); |
|
4027 d3_eventCancel(); |
|
4028 } |
|
4029 |
|
4030 function dispatcher(that, argumentz) { |
|
4031 return function(type) { |
|
4032 var e = d3.event; |
|
4033 try { |
|
4034 d3.event = {type: type, target: brush}; |
|
4035 event[type].apply(that, argumentz); |
|
4036 } finally { |
|
4037 d3.event = e; |
|
4038 } |
|
4039 }; |
|
4040 } |
|
4041 |
|
4042 brush.x = function(z) { |
|
4043 if (!arguments.length) return x; |
|
4044 x = z; |
|
4045 return brush; |
|
4046 }; |
|
4047 |
|
4048 brush.y = function(z) { |
|
4049 if (!arguments.length) return y; |
|
4050 y = z; |
|
4051 return brush; |
|
4052 }; |
|
4053 |
|
4054 brush.extent = function(z) { |
|
4055 var x0, x1, y0, y1, t; |
|
4056 |
|
4057 // Invert the pixel extent to data-space. |
|
4058 if (!arguments.length) { |
|
4059 if (x) { |
|
4060 x0 = x.invert(extent[0][0]), x1 = x.invert(extent[1][0]); |
|
4061 if (x1 < x0) t = x0, x0 = x1, x1 = t; |
|
4062 } |
|
4063 if (y) { |
|
4064 y0 = y.invert(extent[0][1]), y1 = y.invert(extent[1][1]); |
|
4065 if (y1 < y0) t = y0, y0 = y1, y1 = t; |
|
4066 } |
|
4067 return x && y ? [[x0, y0], [x1, y1]] : x ? [x0, x1] : y && [y0, y1]; |
|
4068 } |
|
4069 |
|
4070 // Scale the data-space extent to pixels. |
|
4071 if (x) { |
|
4072 x0 = z[0], x1 = z[1]; |
|
4073 if (y) x0 = x0[0], x1 = x1[0]; |
|
4074 x0 = x(x0), x1 = x(x1); |
|
4075 if (x1 < x0) t = x0, x0 = x1, x1 = t; |
|
4076 extent[0][0] = x0, extent[1][0] = x1; |
|
4077 } |
|
4078 if (y) { |
|
4079 y0 = z[0], y1 = z[1]; |
|
4080 if (x) y0 = y0[1], y1 = y1[1]; |
|
4081 y0 = y(y0), y1 = y(y1); |
|
4082 if (y1 < y0) t = y0, y0 = y1, y1 = t; |
|
4083 extent[0][1] = y0, extent[1][1] = y1; |
|
4084 } |
|
4085 |
|
4086 return brush; |
|
4087 }; |
|
4088 |
|
4089 brush.clear = function() { |
|
4090 extent[0][0] = |
|
4091 extent[0][1] = |
|
4092 extent[1][0] = |
|
4093 extent[1][1] = 0; |
|
4094 return brush; |
|
4095 }; |
|
4096 |
|
4097 brush.empty = function() { |
|
4098 return (x && extent[0][0] === extent[1][0]) |
|
4099 || (y && extent[0][1] === extent[1][1]); |
|
4100 }; |
|
4101 |
|
4102 brush.on = function(type, listener) { |
|
4103 event.on(type, listener); |
|
4104 return brush; |
|
4105 }; |
|
4106 |
|
4107 d3.select(window) |
|
4108 .on("mousemove.brush", d3_svg_brushMove) |
|
4109 .on("mouseup.brush", d3_svg_brushUp) |
|
4110 .on("keydown.brush", d3_svg_brushKeydown) |
|
4111 .on("keyup.brush", d3_svg_brushKeyup); |
|
4112 |
|
4113 return brush; |
|
4114 }; |
|
4115 |
|
4116 var d3_svg_brush, |
|
4117 d3_svg_brushDispatch, |
|
4118 d3_svg_brushTarget, |
|
4119 d3_svg_brushX, |
|
4120 d3_svg_brushY, |
|
4121 d3_svg_brushExtent, |
|
4122 d3_svg_brushDrag, |
|
4123 d3_svg_brushResize, |
|
4124 d3_svg_brushCenter, |
|
4125 d3_svg_brushOffset; |
|
4126 |
|
4127 function d3_svg_brushRedrawX(g, extent) { |
|
4128 g.select(".extent").attr("x", extent[0][0]); |
|
4129 g.selectAll(".n,.s,.w,.nw,.sw").attr("x", extent[0][0] - 2); |
|
4130 g.selectAll(".e,.ne,.se").attr("x", extent[1][0] - 3); |
|
4131 g.selectAll(".extent,.n,.s").attr("width", extent[1][0] - extent[0][0]); |
|
4132 } |
|
4133 |
|
4134 function d3_svg_brushRedrawY(g, extent) { |
|
4135 g.select(".extent").attr("y", extent[0][1]); |
|
4136 g.selectAll(".n,.e,.w,.nw,.ne").attr("y", extent[0][1] - 3); |
|
4137 g.selectAll(".s,.se,.sw").attr("y", extent[1][1] - 4); |
|
4138 g.selectAll(".extent,.e,.w").attr("height", extent[1][1] - extent[0][1]); |
|
4139 } |
|
4140 |
|
4141 function d3_svg_brushKeydown() { |
|
4142 if (d3.event.keyCode == 32 && d3_svg_brushTarget && !d3_svg_brushDrag) { |
|
4143 d3_svg_brushCenter = null; |
|
4144 d3_svg_brushOffset[0] -= d3_svg_brushExtent[1][0]; |
|
4145 d3_svg_brushOffset[1] -= d3_svg_brushExtent[1][1]; |
|
4146 d3_svg_brushDrag = 2; |
|
4147 d3_eventCancel(); |
|
4148 } |
|
4149 } |
|
4150 |
|
4151 function d3_svg_brushKeyup() { |
|
4152 if (d3.event.keyCode == 32 && d3_svg_brushDrag == 2) { |
|
4153 d3_svg_brushOffset[0] += d3_svg_brushExtent[1][0]; |
|
4154 d3_svg_brushOffset[1] += d3_svg_brushExtent[1][1]; |
|
4155 d3_svg_brushDrag = 0; |
|
4156 d3_eventCancel(); |
|
4157 } |
|
4158 } |
|
4159 |
|
4160 function d3_svg_brushMove() { |
|
4161 if (d3_svg_brushOffset) { |
|
4162 var mouse = d3.svg.mouse(d3_svg_brushTarget), |
|
4163 g = d3.select(d3_svg_brushTarget); |
|
4164 |
|
4165 if (!d3_svg_brushDrag) { |
|
4166 |
|
4167 // If needed, determine the center from the current extent. |
|
4168 if (d3.event.altKey) { |
|
4169 if (!d3_svg_brushCenter) { |
|
4170 d3_svg_brushCenter = [ |
|
4171 (d3_svg_brushExtent[0][0] + d3_svg_brushExtent[1][0]) / 2, |
|
4172 (d3_svg_brushExtent[0][1] + d3_svg_brushExtent[1][1]) / 2 |
|
4173 ]; |
|
4174 } |
|
4175 |
|
4176 // Update the offset, for when the ALT key is released. |
|
4177 d3_svg_brushOffset[0] = d3_svg_brushExtent[+(mouse[0] < d3_svg_brushCenter[0])][0]; |
|
4178 d3_svg_brushOffset[1] = d3_svg_brushExtent[+(mouse[1] < d3_svg_brushCenter[1])][1]; |
|
4179 } |
|
4180 |
|
4181 // When the ALT key is released, we clear the center. |
|
4182 else d3_svg_brushCenter = null; |
|
4183 } |
|
4184 |
|
4185 // Update the brush extent for each dimension. |
|
4186 if (d3_svg_brushX) { |
|
4187 d3_svg_brushMove1(mouse, d3_svg_brushX, 0); |
|
4188 d3_svg_brushRedrawX(g, d3_svg_brushExtent); |
|
4189 } |
|
4190 if (d3_svg_brushY) { |
|
4191 d3_svg_brushMove1(mouse, d3_svg_brushY, 1); |
|
4192 d3_svg_brushRedrawY(g, d3_svg_brushExtent); |
|
4193 } |
|
4194 |
|
4195 // Notify listeners. |
|
4196 d3_svg_brushDispatch("brush"); |
|
4197 } |
|
4198 } |
|
4199 |
|
4200 function d3_svg_brushMove1(mouse, scale, i) { |
|
4201 var range = d3_scaleExtent(scale.range()), |
|
4202 offset = d3_svg_brushOffset[i], |
|
4203 size = d3_svg_brushExtent[1][i] - d3_svg_brushExtent[0][i], |
|
4204 min, |
|
4205 max; |
|
4206 |
|
4207 // When dragging, reduce the range by the extent size and offset. |
|
4208 if (d3_svg_brushDrag) { |
|
4209 range[0] -= offset; |
|
4210 range[1] -= size + offset; |
|
4211 } |
|
4212 |
|
4213 // Clamp the mouse so that the extent fits within the range extent. |
|
4214 min = Math.max(range[0], Math.min(range[1], mouse[i])); |
|
4215 |
|
4216 // Compute the new extent bounds. |
|
4217 if (d3_svg_brushDrag) { |
|
4218 max = (min += offset) + size; |
|
4219 } else { |
|
4220 |
|
4221 // If the ALT key is pressed, then preserve the center of the extent. |
|
4222 if (d3_svg_brushCenter) offset = Math.max(range[0], Math.min(range[1], 2 * d3_svg_brushCenter[i] - min)); |
|
4223 |
|
4224 // Compute the min and max of the offset and mouse. |
|
4225 if (offset < min) { |
|
4226 max = min; |
|
4227 min = offset; |
|
4228 } else { |
|
4229 max = offset; |
|
4230 } |
|
4231 } |
|
4232 |
|
4233 // Update the stored bounds. |
|
4234 d3_svg_brushExtent[0][i] = min; |
|
4235 d3_svg_brushExtent[1][i] = max; |
|
4236 } |
|
4237 |
|
4238 function d3_svg_brushUp() { |
|
4239 if (d3_svg_brushOffset) { |
|
4240 d3_svg_brushMove(); |
|
4241 d3.select(d3_svg_brushTarget).selectAll(".resize").style("pointer-events", d3_svg_brush.empty() ? "none" : "all"); |
|
4242 d3_svg_brushDispatch("brushend"); |
|
4243 d3_svg_brush = |
|
4244 d3_svg_brushDispatch = |
|
4245 d3_svg_brushTarget = |
|
4246 d3_svg_brushX = |
|
4247 d3_svg_brushY = |
|
4248 d3_svg_brushExtent = |
|
4249 d3_svg_brushDrag = |
|
4250 d3_svg_brushResize = |
|
4251 d3_svg_brushCenter = |
|
4252 d3_svg_brushOffset = null; |
|
4253 d3_eventCancel(); |
|
4254 } |
|
4255 } |
|
4256 |
|
4257 var d3_svg_brushCursor = { |
|
4258 n: "ns-resize", |
|
4259 e: "ew-resize", |
|
4260 s: "ns-resize", |
|
4261 w: "ew-resize", |
|
4262 nw: "nwse-resize", |
|
4263 ne: "nesw-resize", |
|
4264 se: "nwse-resize", |
|
4265 sw: "nesw-resize" |
|
4266 }; |
|
4267 d3.behavior = {}; |
|
4268 d3.behavior.drag = function() { |
|
4269 var event = d3.dispatch("drag", "dragstart", "dragend"); |
|
4270 |
|
4271 function drag() { |
|
4272 this |
|
4273 .on("mousedown.drag", mousedown) |
|
4274 .on("touchstart.drag", mousedown); |
|
4275 |
|
4276 d3.select(window) |
|
4277 .on("mousemove.drag", d3_behavior_dragMove) |
|
4278 .on("touchmove.drag", d3_behavior_dragMove) |
|
4279 .on("mouseup.drag", d3_behavior_dragUp, true) |
|
4280 .on("touchend.drag", d3_behavior_dragUp, true) |
|
4281 .on("click.drag", d3_behavior_dragClick, true); |
|
4282 } |
|
4283 |
|
4284 // snapshot the local context for subsequent dispatch |
|
4285 function start() { |
|
4286 d3_behavior_dragEvent = event; |
|
4287 d3_behavior_dragEventTarget = d3.event.target; |
|
4288 d3_behavior_dragOffset = d3_behavior_dragPoint((d3_behavior_dragTarget = this).parentNode); |
|
4289 d3_behavior_dragMoved = 0; |
|
4290 d3_behavior_dragArguments = arguments; |
|
4291 } |
|
4292 |
|
4293 function mousedown() { |
|
4294 start.apply(this, arguments); |
|
4295 d3_behavior_dragDispatch("dragstart"); |
|
4296 } |
|
4297 |
|
4298 drag.on = function(type, listener) { |
|
4299 event.on(type, listener); |
|
4300 return drag; |
|
4301 }; |
|
4302 |
|
4303 return drag; |
|
4304 }; |
|
4305 |
|
4306 var d3_behavior_dragEvent, |
|
4307 d3_behavior_dragEventTarget, |
|
4308 d3_behavior_dragTarget, |
|
4309 d3_behavior_dragArguments, |
|
4310 d3_behavior_dragOffset, |
|
4311 d3_behavior_dragMoved, |
|
4312 d3_behavior_dragStopClick; |
|
4313 |
|
4314 function d3_behavior_dragDispatch(type) { |
|
4315 var o = d3.event, p = d3_behavior_dragTarget.parentNode, dx = 0, dy = 0; |
|
4316 |
|
4317 if (p) { |
|
4318 p = d3_behavior_dragPoint(p); |
|
4319 dx = p[0] - d3_behavior_dragOffset[0]; |
|
4320 dy = p[1] - d3_behavior_dragOffset[1]; |
|
4321 d3_behavior_dragOffset = p; |
|
4322 d3_behavior_dragMoved |= dx | dy; |
|
4323 } |
|
4324 |
|
4325 try { |
|
4326 d3.event = {dx: dx, dy: dy}; |
|
4327 d3_behavior_dragEvent[type].apply(d3_behavior_dragTarget, d3_behavior_dragArguments); |
|
4328 } finally { |
|
4329 d3.event = o; |
|
4330 } |
|
4331 |
|
4332 o.preventDefault(); |
|
4333 } |
|
4334 |
|
4335 function d3_behavior_dragPoint(container, type) { |
|
4336 // TODO Track touch points by identifier. |
|
4337 var t = d3.event.changedTouches; |
|
4338 return t ? d3.svg.touches(container, t)[0] : d3.svg.mouse(container); |
|
4339 } |
|
4340 |
|
4341 function d3_behavior_dragMove() { |
|
4342 if (!d3_behavior_dragTarget) return; |
|
4343 var parent = d3_behavior_dragTarget.parentNode; |
|
4344 |
|
4345 // O NOES! The drag element was removed from the DOM. |
|
4346 if (!parent) return d3_behavior_dragUp(); |
|
4347 |
|
4348 d3_behavior_dragDispatch("drag"); |
|
4349 d3_eventCancel(); |
|
4350 } |
|
4351 |
|
4352 function d3_behavior_dragUp() { |
|
4353 if (!d3_behavior_dragTarget) return; |
|
4354 d3_behavior_dragDispatch("dragend"); |
|
4355 d3_behavior_dragTarget = null; |
|
4356 |
|
4357 // If the node was moved, prevent the mouseup from propagating. |
|
4358 // Also prevent the subsequent click from propagating (e.g., for anchors). |
|
4359 if (d3_behavior_dragMoved && d3_behavior_dragEventTarget === d3.event.target) { |
|
4360 d3_behavior_dragStopClick = true; |
|
4361 d3_eventCancel(); |
|
4362 } |
|
4363 } |
|
4364 |
|
4365 function d3_behavior_dragClick() { |
|
4366 if (d3_behavior_dragStopClick && d3_behavior_dragEventTarget === d3.event.target) { |
|
4367 d3_eventCancel(); |
|
4368 d3_behavior_dragStopClick = false; |
|
4369 d3_behavior_dragEventTarget = null; |
|
4370 } |
|
4371 } |
|
4372 // TODO unbind zoom behavior? |
|
4373 d3.behavior.zoom = function() { |
|
4374 var xyz = [0, 0, 0], |
|
4375 event = d3.dispatch("zoom"), |
|
4376 extent = d3_behavior_zoomInfiniteExtent; |
|
4377 |
|
4378 function zoom() { |
|
4379 this |
|
4380 .on("mousedown.zoom", mousedown) |
|
4381 .on("mousewheel.zoom", mousewheel) |
|
4382 .on("DOMMouseScroll.zoom", mousewheel) |
|
4383 .on("dblclick.zoom", dblclick) |
|
4384 .on("touchstart.zoom", touchstart); |
|
4385 |
|
4386 d3.select(window) |
|
4387 .on("mousemove.zoom", d3_behavior_zoomMousemove) |
|
4388 .on("mouseup.zoom", d3_behavior_zoomMouseup) |
|
4389 .on("touchmove.zoom", d3_behavior_zoomTouchmove) |
|
4390 .on("touchend.zoom", d3_behavior_zoomTouchup) |
|
4391 .on("click.zoom", d3_behavior_zoomClick, true); |
|
4392 } |
|
4393 |
|
4394 // snapshot the local context for subsequent dispatch |
|
4395 function start() { |
|
4396 d3_behavior_zoomXyz = xyz; |
|
4397 d3_behavior_zoomExtent = extent; |
|
4398 d3_behavior_zoomDispatch = event.zoom; |
|
4399 d3_behavior_zoomEventTarget = d3.event.target; |
|
4400 d3_behavior_zoomTarget = this; |
|
4401 d3_behavior_zoomArguments = arguments; |
|
4402 } |
|
4403 |
|
4404 function mousedown() { |
|
4405 start.apply(this, arguments); |
|
4406 d3_behavior_zoomPanning = d3_behavior_zoomLocation(d3.svg.mouse(d3_behavior_zoomTarget)); |
|
4407 d3_behavior_zoomMoved = false; |
|
4408 d3.event.preventDefault(); |
|
4409 window.focus(); |
|
4410 } |
|
4411 |
|
4412 // store starting mouse location |
|
4413 function mousewheel() { |
|
4414 start.apply(this, arguments); |
|
4415 if (!d3_behavior_zoomZooming) d3_behavior_zoomZooming = d3_behavior_zoomLocation(d3.svg.mouse(d3_behavior_zoomTarget)); |
|
4416 d3_behavior_zoomTo(d3_behavior_zoomDelta() + xyz[2], d3.svg.mouse(d3_behavior_zoomTarget), d3_behavior_zoomZooming); |
|
4417 } |
|
4418 |
|
4419 function dblclick() { |
|
4420 start.apply(this, arguments); |
|
4421 var mouse = d3.svg.mouse(d3_behavior_zoomTarget); |
|
4422 d3_behavior_zoomTo(d3.event.shiftKey ? Math.ceil(xyz[2] - 1) : Math.floor(xyz[2] + 1), mouse, d3_behavior_zoomLocation(mouse)); |
|
4423 } |
|
4424 |
|
4425 // doubletap detection |
|
4426 function touchstart() { |
|
4427 start.apply(this, arguments); |
|
4428 var touches = d3_behavior_zoomTouchup(), |
|
4429 touch, |
|
4430 now = Date.now(); |
|
4431 if ((touches.length === 1) && (now - d3_behavior_zoomLast < 300)) { |
|
4432 d3_behavior_zoomTo(1 + Math.floor(xyz[2]), touch = touches[0], d3_behavior_zoomLocations[touch.identifier]); |
|
4433 } |
|
4434 d3_behavior_zoomLast = now; |
|
4435 } |
|
4436 |
|
4437 zoom.extent = function(x) { |
|
4438 if (!arguments.length) return extent; |
|
4439 extent = x == null ? d3_behavior_zoomInfiniteExtent : x; |
|
4440 return zoom; |
|
4441 }; |
|
4442 |
|
4443 zoom.on = function(type, listener) { |
|
4444 event.on(type, listener); |
|
4445 return zoom; |
|
4446 }; |
|
4447 |
|
4448 return zoom; |
|
4449 }; |
|
4450 |
|
4451 var d3_behavior_zoomDiv, |
|
4452 d3_behavior_zoomPanning, |
|
4453 d3_behavior_zoomZooming, |
|
4454 d3_behavior_zoomLocations = {}, // identifier -> location |
|
4455 d3_behavior_zoomLast = 0, |
|
4456 d3_behavior_zoomXyz, |
|
4457 d3_behavior_zoomExtent, |
|
4458 d3_behavior_zoomDispatch, |
|
4459 d3_behavior_zoomEventTarget, |
|
4460 d3_behavior_zoomTarget, |
|
4461 d3_behavior_zoomArguments, |
|
4462 d3_behavior_zoomMoved, |
|
4463 d3_behavior_zoomStopClick; |
|
4464 |
|
4465 function d3_behavior_zoomLocation(point) { |
|
4466 return [ |
|
4467 point[0] - d3_behavior_zoomXyz[0], |
|
4468 point[1] - d3_behavior_zoomXyz[1], |
|
4469 d3_behavior_zoomXyz[2] |
|
4470 ]; |
|
4471 } |
|
4472 |
|
4473 // detect the pixels that would be scrolled by this wheel event |
|
4474 function d3_behavior_zoomDelta() { |
|
4475 |
|
4476 // mousewheel events are totally broken! |
|
4477 // https://bugs.webkit.org/show_bug.cgi?id=40441 |
|
4478 // not only that, but Chrome and Safari differ in re. to acceleration! |
|
4479 if (!d3_behavior_zoomDiv) { |
|
4480 d3_behavior_zoomDiv = d3.select("body").append("div") |
|
4481 .style("visibility", "hidden") |
|
4482 .style("top", 0) |
|
4483 .style("height", 0) |
|
4484 .style("width", 0) |
|
4485 .style("overflow-y", "scroll") |
|
4486 .append("div") |
|
4487 .style("height", "2000px") |
|
4488 .node().parentNode; |
|
4489 } |
|
4490 |
|
4491 var e = d3.event, delta; |
|
4492 try { |
|
4493 d3_behavior_zoomDiv.scrollTop = 1000; |
|
4494 d3_behavior_zoomDiv.dispatchEvent(e); |
|
4495 delta = 1000 - d3_behavior_zoomDiv.scrollTop; |
|
4496 } catch (error) { |
|
4497 delta = e.wheelDelta || (-e.detail * 5); |
|
4498 } |
|
4499 |
|
4500 return delta * .005; |
|
4501 } |
|
4502 |
|
4503 // Note: Since we don't rotate, it's possible for the touches to become |
|
4504 // slightly detached from their original positions. Thus, we recompute the |
|
4505 // touch points on touchend as well as touchstart! |
|
4506 function d3_behavior_zoomTouchup() { |
|
4507 var touches = d3.svg.touches(d3_behavior_zoomTarget), |
|
4508 i = -1, |
|
4509 n = touches.length, |
|
4510 touch; |
|
4511 while (++i < n) d3_behavior_zoomLocations[(touch = touches[i]).identifier] = d3_behavior_zoomLocation(touch); |
|
4512 return touches; |
|
4513 } |
|
4514 |
|
4515 function d3_behavior_zoomTouchmove() { |
|
4516 var touches = d3.svg.touches(d3_behavior_zoomTarget); |
|
4517 switch (touches.length) { |
|
4518 |
|
4519 // single-touch pan |
|
4520 case 1: { |
|
4521 var touch = touches[0]; |
|
4522 d3_behavior_zoomTo(d3_behavior_zoomXyz[2], touch, d3_behavior_zoomLocations[touch.identifier]); |
|
4523 break; |
|
4524 } |
|
4525 |
|
4526 // double-touch pan + zoom |
|
4527 case 2: { |
|
4528 var p0 = touches[0], |
|
4529 p1 = touches[1], |
|
4530 p2 = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2], |
|
4531 l0 = d3_behavior_zoomLocations[p0.identifier], |
|
4532 l1 = d3_behavior_zoomLocations[p1.identifier], |
|
4533 l2 = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2, l0[2]]; |
|
4534 d3_behavior_zoomTo(Math.log(d3.event.scale) / Math.LN2 + l0[2], p2, l2); |
|
4535 break; |
|
4536 } |
|
4537 } |
|
4538 } |
|
4539 |
|
4540 function d3_behavior_zoomMousemove() { |
|
4541 d3_behavior_zoomZooming = null; |
|
4542 if (d3_behavior_zoomPanning) { |
|
4543 d3_behavior_zoomMoved = true; |
|
4544 d3_behavior_zoomTo(d3_behavior_zoomXyz[2], d3.svg.mouse(d3_behavior_zoomTarget), d3_behavior_zoomPanning); |
|
4545 } |
|
4546 } |
|
4547 |
|
4548 function d3_behavior_zoomMouseup() { |
|
4549 if (d3_behavior_zoomPanning) { |
|
4550 if (d3_behavior_zoomMoved && d3_behavior_zoomEventTarget === d3.event.target) { |
|
4551 d3_behavior_zoomStopClick = true; |
|
4552 } |
|
4553 d3_behavior_zoomMousemove(); |
|
4554 d3_behavior_zoomPanning = null; |
|
4555 } |
|
4556 } |
|
4557 |
|
4558 function d3_behavior_zoomClick() { |
|
4559 if (d3_behavior_zoomStopClick && d3_behavior_zoomEventTarget === d3.event.target) { |
|
4560 d3.event.stopPropagation(); |
|
4561 d3.event.preventDefault(); |
|
4562 d3_behavior_zoomStopClick = false; |
|
4563 d3_behavior_zoomEventTarget = null; |
|
4564 } |
|
4565 } |
|
4566 |
|
4567 function d3_behavior_zoomTo(z, x0, x1) { |
|
4568 z = d3_behavior_zoomExtentClamp(z, 2); |
|
4569 var j = Math.pow(2, d3_behavior_zoomXyz[2]), |
|
4570 k = Math.pow(2, z), |
|
4571 K = Math.pow(2, (d3_behavior_zoomXyz[2] = z) - x1[2]), |
|
4572 x_ = d3_behavior_zoomXyz[0], |
|
4573 y_ = d3_behavior_zoomXyz[1], |
|
4574 x = d3_behavior_zoomXyz[0] = d3_behavior_zoomExtentClamp((x0[0] - x1[0] * K), 0, k), |
|
4575 y = d3_behavior_zoomXyz[1] = d3_behavior_zoomExtentClamp((x0[1] - x1[1] * K), 1, k), |
|
4576 o = d3.event; // Events can be reentrant (e.g., focus). |
|
4577 |
|
4578 d3.event = { |
|
4579 scale: k, |
|
4580 translate: [x, y], |
|
4581 transform: function(sx, sy) { |
|
4582 if (sx) transform(sx, x_, x); |
|
4583 if (sy) transform(sy, y_, y); |
|
4584 } |
|
4585 }; |
|
4586 |
|
4587 function transform(scale, a, b) { |
|
4588 scale.domain(scale.range().map(function(v) { return scale.invert(((v - b) * j) / k + a); })); |
|
4589 } |
|
4590 |
|
4591 try { |
|
4592 d3_behavior_zoomDispatch.apply(d3_behavior_zoomTarget, d3_behavior_zoomArguments); |
|
4593 } finally { |
|
4594 d3.event = o; |
|
4595 } |
|
4596 |
|
4597 o.preventDefault(); |
|
4598 } |
|
4599 |
|
4600 var d3_behavior_zoomInfiniteExtent = [ |
|
4601 [-Infinity, Infinity], |
|
4602 [-Infinity, Infinity], |
|
4603 [-Infinity, Infinity] |
|
4604 ]; |
|
4605 |
|
4606 function d3_behavior_zoomExtentClamp(x, i, k) { |
|
4607 var range = d3_behavior_zoomExtent[i], |
|
4608 r0 = range[0], |
|
4609 r1 = range[1]; |
|
4610 return arguments.length === 3 |
|
4611 ? Math.max(r1 * (r1 === Infinity ? -Infinity : 1 / k - 1), |
|
4612 Math.min(r0 === -Infinity ? Infinity : r0, x / k)) * k |
|
4613 : Math.max(r0, Math.min(r1, x)); |
|
4614 } |
|
4615 })(); |