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