comparison extract_display_features/dashboard/html_js.py @ 0:89592faa2875 draft

Uploaded
author chrisb
date Wed, 23 Mar 2016 14:35:56 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:89592faa2875
1 __license__ = "MIT"
2
3 # test if local js dashboard will work
4
5 if __name__ == "__main__":
6 import sys
7
8 try:
9 inone = file(sys.argv[1],"read").readlines()
10 out = file(sys.argv[2],"w")
11 output="""
12 <!DOCTYPE html>
13 <html lang="en">
14 <head>
15 <title>dc.js - Number Display Example</title>
16 <meta charset="UTF-8">
17 </head>
18 <style>
19 div.dc-chart {
20 float: left;
21 }
22
23 .dc-chart rect.bar {
24 stroke: none;
25 cursor: pointer;
26 }
27
28 .dc-chart rect.bar:hover {
29 fill-opacity: .5;
30 }
31
32 .dc-chart rect.stack1 {
33 stroke: none;
34 fill: red;
35 }
36
37 .dc-chart rect.stack2 {
38 stroke: none;
39 fill: green;
40 }
41
42 .dc-chart rect.deselected {
43 stroke: none;
44 fill: #ccc;
45 }
46
47 .dc-chart .empty-chart .pie-slice path {
48 fill: #FFEEEE;
49 cursor: default;
50 }
51
52 .dc-chart .empty-chart .pie-slice {
53 cursor: default;
54 }
55
56 .dc-chart .pie-slice {
57 fill: white;
58 font-size: 12px;
59 cursor: pointer;
60 }
61
62 .dc-chart .pie-slice.external{
63 fill: black;
64 }
65
66 .dc-chart .pie-slice :hover {
67 fill-opacity: .8;
68 }
69
70 .dc-chart .pie-slice.highlight {
71 fill-opacity: .8;
72 }
73
74 .dc-chart .selected path {
75 stroke-width: 3;
76 stroke: #ccc;
77 fill-opacity: 1;
78 }
79
80 .dc-chart .deselected path {
81 stroke: none;
82 fill-opacity: .5;
83 fill: #ccc;
84 }
85
86 .dc-chart .axis path, .axis line {
87 fill: none;
88 stroke: #000;
89 shape-rendering: crispEdges;
90 }
91
92 .dc-chart .axis text {
93 font: 10px sans-serif;
94 }
95
96 .dc-chart .grid-line {
97 fill: none;
98 stroke: #ccc;
99 opacity: .5;
100 shape-rendering: crispEdges;
101 }
102
103 .dc-chart .grid-line line {
104 fill: none;
105 stroke: #ccc;
106 opacity: .5;
107 shape-rendering: crispEdges;
108 }
109
110 .dc-chart .brush rect.background {
111 z-index: -999;
112 }
113
114 .dc-chart .brush rect.extent {
115 fill: steelblue;
116 fill-opacity: .125;
117 }
118
119 .dc-chart .brush .resize path {
120 fill: #eee;
121 stroke: #666;
122 }
123
124 .dc-chart path.line {
125 fill: none;
126 stroke-width: 1.5px;
127 }
128
129 .dc-chart circle.dot {
130 stroke: none;
131 }
132
133 .dc-chart g.dc-tooltip path {
134 fill: none;
135 stroke: grey;
136 stroke-opacity: .8;
137 }
138
139 .dc-chart path.area {
140 fill-opacity: .3;
141 stroke: none;
142 }
143
144 .dc-chart .node {
145 font-size: 0.7em;
146 cursor: pointer;
147 }
148
149 .dc-chart .node :hover {
150 fill-opacity: .8;
151 }
152
153 .dc-chart .selected circle {
154 stroke-width: 3;
155 stroke: #ccc;
156 fill-opacity: 1;
157 }
158
159 .dc-chart .deselected circle {
160 stroke: none;
161 fill-opacity: .5;
162 fill: #ccc;
163 }
164
165 .dc-chart .bubble {
166 stroke: none;
167 fill-opacity: 0.6;
168 }
169
170 .dc-data-count {
171 float: right;
172 margin-top: 15px;
173 margin-right: 15px;
174 }
175
176 .dc-data-count .filter-count {
177 color: #3182bd;
178 font-weight: bold;
179 }
180
181 .dc-data-count .total-count {
182 color: #3182bd;
183 font-weight: bold;
184 }
185
186 .dc-data-table {
187 }
188
189 .dc-chart g.state {
190 cursor: pointer;
191 }
192
193 .dc-chart g.state :hover {
194 fill-opacity: .8;
195 }
196
197 .dc-chart g.state path {
198 stroke: white;
199 }
200
201 .dc-chart g.selected path {
202 }
203
204 .dc-chart g.deselected path {
205 fill: grey;
206 }
207
208 .dc-chart g.selected text {
209 }
210
211 .dc-chart g.deselected text {
212 display: none;
213 }
214
215 .dc-chart g.county path {
216 stroke: white;
217 fill: none;
218 }
219
220 .dc-chart g.debug rect {
221 fill: blue;
222 fill-opacity: .2;
223 }
224
225 .dc-chart g.row rect {
226 fill-opacity: 0.8;
227 cursor: pointer;
228 }
229
230 .dc-chart g.row rect:hover {
231 fill-opacity: 0.6;
232 }
233
234 .dc-chart g.row text {
235 fill: white;
236 font-size: 12px;
237 cursor: pointer;
238 }
239
240 .dc-legend {
241 font-size: 11px;
242 }
243
244 .dc-legend-item {
245 cursor: pointer;
246 }
247
248 .dc-chart g.axis text {
249 /* Makes it so the user can't accidentally click and select text that is meant as a label only */
250 -webkit-user-select: none; /* Chrome/Safari */
251 -moz-user-select: none; /* Firefox */
252 -ms-user-select: none; /* IE10 */
253 -o-user-select: none;
254 user-select: none;
255 pointer-events: none;
256 }
257
258 .dc-chart path.highlight {
259 stroke-width: 3;
260 fill-opacity: 1;
261 stroke-opacity: 1;
262 }
263
264 .dc-chart .highlight {
265 fill-opacity: 1;
266 stroke-opacity: 1;
267 }
268
269 .dc-chart .fadeout {
270 fill-opacity: 0.2;
271 stroke-opacity: 0.2;
272 }
273
274 .dc-chart path.dc-symbol, g.dc-legend-item.fadeout {
275 fill-opacity: 0.5;
276 stroke-opacity: 0.5;
277 }
278
279 .dc-hard .number-display {
280 float: none;
281 }
282
283 .dc-chart .box text {
284 font: 10px sans-serif;
285 -webkit-user-select: none; /* Chrome/Safari */
286 -moz-user-select: none; /* Firefox */
287 -ms-user-select: none; /* IE10 */
288 -o-user-select: none;
289 user-select: none;
290 pointer-events: none;
291 }
292
293 .dc-chart .box line,
294 .dc-chart .box circle {
295 fill: #fff;
296 stroke: #000;
297 stroke-width: 1.5px;
298 }
299
300 .dc-chart .box rect {
301 stroke: #000;
302 stroke-width: 1.5px;
303 }
304
305 .dc-chart .box .center {
306 stroke-dasharray: 3,3;
307 }
308
309 .dc-chart .box .outlier {
310 fill: none;
311 stroke: #ccc;
312 }
313
314 .dc-chart .box.deselected .box {
315 fill: #ccc;
316 }
317
318 .dc-chart .box.deselected {
319 opacity: .5;
320 }
321
322 .dc-chart .symbol{
323 stroke: none;
324 }
325
326 .dc-chart .heatmap .box-group.deselected rect {
327 stroke: none;
328 fill-opacity: .5;
329 fill: #ccc;
330 }
331
332 .dc-chart .heatmap g.axis text {
333 pointer-events: all;
334 cursor: pointer;
335 }
336
337 </style>
338 <body>
339
340 <div id="chart-bar-ring"></div>
341 <div id="chart-row-pdb"></div>
342
343
344 <script>
345 !function() {
346 var d3 = {
347 version: "3.5.2"
348 };
349 if (!Date.now) Date.now = function() {
350 return +new Date();
351 };
352 var d3_arraySlice = [].slice, d3_array = function(list) {
353 return d3_arraySlice.call(list);
354 };
355 var d3_document = document, d3_documentElement = d3_document.documentElement, d3_window = window;
356 try {
357 d3_array(d3_documentElement.childNodes)[0].nodeType;
358 } catch (e) {
359 d3_array = function(list) {
360 var i = list.length, array = new Array(i);
361 while (i--) array[i] = list[i];
362 return array;
363 };
364 }
365 try {
366 d3_document.createElement("div").style.setProperty("opacity", 0, "");
367 } catch (error) {
368 var d3_element_prototype = d3_window.Element.prototype, d3_element_setAttribute = d3_element_prototype.setAttribute, d3_element_setAttributeNS = d3_element_prototype.setAttributeNS, d3_style_prototype = d3_window.CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty;
369 d3_element_prototype.setAttribute = function(name, value) {
370 d3_element_setAttribute.call(this, name, value + "");
371 };
372 d3_element_prototype.setAttributeNS = function(space, local, value) {
373 d3_element_setAttributeNS.call(this, space, local, value + "");
374 };
375 d3_style_prototype.setProperty = function(name, value, priority) {
376 d3_style_setProperty.call(this, name, value + "", priority);
377 };
378 }
379 d3.ascending = d3_ascending;
380 function d3_ascending(a, b) {
381 return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
382 }
383 d3.descending = function(a, b) {
384 return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
385 };
386 d3.min = function(array, f) {
387 var i = -1, n = array.length, a, b;
388 if (arguments.length === 1) {
389 while (++i < n) if ((b = array[i]) != null && b >= b) {
390 a = b;
391 break;
392 }
393 while (++i < n) if ((b = array[i]) != null && a > b) a = b;
394 } else {
395 while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) {
396 a = b;
397 break;
398 }
399 while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b;
400 }
401 return a;
402 };
403 d3.max = function(array, f) {
404 var i = -1, n = array.length, a, b;
405 if (arguments.length === 1) {
406 while (++i < n) if ((b = array[i]) != null && b >= b) {
407 a = b;
408 break;
409 }
410 while (++i < n) if ((b = array[i]) != null && b > a) a = b;
411 } else {
412 while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) {
413 a = b;
414 break;
415 }
416 while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b;
417 }
418 return a;
419 };
420 d3.extent = function(array, f) {
421 var i = -1, n = array.length, a, b, c;
422 if (arguments.length === 1) {
423 while (++i < n) if ((b = array[i]) != null && b >= b) {
424 a = c = b;
425 break;
426 }
427 while (++i < n) if ((b = array[i]) != null) {
428 if (a > b) a = b;
429 if (c < b) c = b;
430 }
431 } else {
432 while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) {
433 a = c = b;
434 break;
435 }
436 while (++i < n) if ((b = f.call(array, array[i], i)) != null) {
437 if (a > b) a = b;
438 if (c < b) c = b;
439 }
440 }
441 return [ a, c ];
442 };
443 function d3_number(x) {
444 return x === null ? NaN : +x;
445 }
446 function d3_numeric(x) {
447 return !isNaN(x);
448 }
449 d3.sum = function(array, f) {
450 var s = 0, n = array.length, a, i = -1;
451 if (arguments.length === 1) {
452 while (++i < n) if (d3_numeric(a = +array[i])) s += a;
453 } else {
454 while (++i < n) if (d3_numeric(a = +f.call(array, array[i], i))) s += a;
455 }
456 return s;
457 };
458 d3.mean = function(array, f) {
459 var s = 0, n = array.length, a, i = -1, j = n;
460 if (arguments.length === 1) {
461 while (++i < n) if (d3_numeric(a = d3_number(array[i]))) s += a; else --j;
462 } else {
463 while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) s += a; else --j;
464 }
465 if (j) return s / j;
466 };
467 d3.quantile = function(values, p) {
468 var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h;
469 return e ? v + e * (values[h] - v) : v;
470 };
471 d3.median = function(array, f) {
472 var numbers = [], n = array.length, a, i = -1;
473 if (arguments.length === 1) {
474 while (++i < n) if (d3_numeric(a = d3_number(array[i]))) numbers.push(a);
475 } else {
476 while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) numbers.push(a);
477 }
478 if (numbers.length) return d3.quantile(numbers.sort(d3_ascending), .5);
479 };
480 d3.variance = function(array, f) {
481 var n = array.length, m = 0, a, d, s = 0, i = -1, j = 0;
482 if (arguments.length === 1) {
483 while (++i < n) {
484 if (d3_numeric(a = d3_number(array[i]))) {
485 d = a - m;
486 m += d / ++j;
487 s += d * (a - m);
488 }
489 }
490 } else {
491 while (++i < n) {
492 if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) {
493 d = a - m;
494 m += d / ++j;
495 s += d * (a - m);
496 }
497 }
498 }
499 if (j > 1) return s / (j - 1);
500 };
501 d3.deviation = function() {
502 var v = d3.variance.apply(this, arguments);
503 return v ? Math.sqrt(v) : v;
504 };
505 function d3_bisector(compare) {
506 return {
507 left: function(a, x, lo, hi) {
508 if (arguments.length < 3) lo = 0;
509 if (arguments.length < 4) hi = a.length;
510 while (lo < hi) {
511 var mid = lo + hi >>> 1;
512 if (compare(a[mid], x) < 0) lo = mid + 1; else hi = mid;
513 }
514 return lo;
515 },
516 right: function(a, x, lo, hi) {
517 if (arguments.length < 3) lo = 0;
518 if (arguments.length < 4) hi = a.length;
519 while (lo < hi) {
520 var mid = lo + hi >>> 1;
521 if (compare(a[mid], x) > 0) hi = mid; else lo = mid + 1;
522 }
523 return lo;
524 }
525 };
526 }
527 var d3_bisect = d3_bisector(d3_ascending);
528 d3.bisectLeft = d3_bisect.left;
529 d3.bisect = d3.bisectRight = d3_bisect.right;
530 d3.bisector = function(f) {
531 return d3_bisector(f.length === 1 ? function(d, x) {
532 return d3_ascending(f(d), x);
533 } : f);
534 };
535 d3.shuffle = function(array, i0, i1) {
536 if ((m = arguments.length) < 3) {
537 i1 = array.length;
538 if (m < 2) i0 = 0;
539 }
540 var m = i1 - i0, t, i;
541 while (m) {
542 i = Math.random() * m-- | 0;
543 t = array[m + i0], array[m + i0] = array[i + i0], array[i + i0] = t;
544 }
545 return array;
546 };
547 d3.permute = function(array, indexes) {
548 var i = indexes.length, permutes = new Array(i);
549 while (i--) permutes[i] = array[indexes[i]];
550 return permutes;
551 };
552 d3.pairs = function(array) {
553 var i = 0, n = array.length - 1, p0, p1 = array[0], pairs = new Array(n < 0 ? 0 : n);
554 while (i < n) pairs[i] = [ p0 = p1, p1 = array[++i] ];
555 return pairs;
556 };
557 d3.zip = function() {
558 if (!(n = arguments.length)) return [];
559 for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) {
560 for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) {
561 zip[j] = arguments[j][i];
562 }
563 }
564 return zips;
565 };
566 function d3_zipLength(d) {
567 return d.length;
568 }
569 d3.transpose = function(matrix) {
570 return d3.zip.apply(d3, matrix);
571 };
572 d3.keys = function(map) {
573 var keys = [];
574 for (var key in map) keys.push(key);
575 return keys;
576 };
577 d3.values = function(map) {
578 var values = [];
579 for (var key in map) values.push(map[key]);
580 return values;
581 };
582 d3.entries = function(map) {
583 var entries = [];
584 for (var key in map) entries.push({
585 key: key,
586 value: map[key]
587 });
588 return entries;
589 };
590 d3.merge = function(arrays) {
591 var n = arrays.length, m, i = -1, j = 0, merged, array;
592 while (++i < n) j += arrays[i].length;
593 merged = new Array(j);
594 while (--n >= 0) {
595 array = arrays[n];
596 m = array.length;
597 while (--m >= 0) {
598 merged[--j] = array[m];
599 }
600 }
601 return merged;
602 };
603 var abs = Math.abs;
604 d3.range = function(start, stop, step) {
605 if (arguments.length < 3) {
606 step = 1;
607 if (arguments.length < 2) {
608 stop = start;
609 start = 0;
610 }
611 }
612 if ((stop - start) / step === Infinity) throw new Error("infinite range");
613 var range = [], k = d3_range_integerScale(abs(step)), i = -1, j;
614 start *= k, stop *= k, step *= k;
615 if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k);
616 return range;
617 };
618 function d3_range_integerScale(x) {
619 var k = 1;
620 while (x * k % 1) k *= 10;
621 return k;
622 }
623 function d3_class(ctor, properties) {
624 for (var key in properties) {
625 Object.defineProperty(ctor.prototype, key, {
626 value: properties[key],
627 enumerable: false
628 });
629 }
630 }
631 d3.map = function(object, f) {
632 var map = new d3_Map();
633 if (object instanceof d3_Map) {
634 object.forEach(function(key, value) {
635 map.set(key, value);
636 });
637 } else if (Array.isArray(object)) {
638 var i = -1, n = object.length, o;
639 if (arguments.length === 1) while (++i < n) map.set(i, object[i]); else while (++i < n) map.set(f.call(object, o = object[i], i), o);
640 } else {
641 for (var key in object) map.set(key, object[key]);
642 }
643 return map;
644 };
645 function d3_Map() {
646 this._ = Object.create(null);
647 }
648 var d3_map_proto = "__proto__", d3_map_zero = "\x00";
649 d3_class(d3_Map, {
650 has: d3_map_has,
651 get: function(key) {
652 return this._[d3_map_escape(key)];
653 },
654 set: function(key, value) {
655 return this._[d3_map_escape(key)] = value;
656 },
657 remove: d3_map_remove,
658 keys: d3_map_keys,
659 values: function() {
660 var values = [];
661 for (var key in this._) values.push(this._[key]);
662 return values;
663 },
664 entries: function() {
665 var entries = [];
666 for (var key in this._) entries.push({
667 key: d3_map_unescape(key),
668 value: this._[key]
669 });
670 return entries;
671 },
672 size: d3_map_size,
673 empty: d3_map_empty,
674 forEach: function(f) {
675 for (var key in this._) f.call(this, d3_map_unescape(key), this._[key]);
676 }
677 });
678 function d3_map_escape(key) {
679 return (key += "") === d3_map_proto || key[0] === d3_map_zero ? d3_map_zero + key : key;
680 }
681 function d3_map_unescape(key) {
682 return (key += "")[0] === d3_map_zero ? key.slice(1) : key;
683 }
684 function d3_map_has(key) {
685 return d3_map_escape(key) in this._;
686 }
687 function d3_map_remove(key) {
688 return (key = d3_map_escape(key)) in this._ && delete this._[key];
689 }
690 function d3_map_keys() {
691 var keys = [];
692 for (var key in this._) keys.push(d3_map_unescape(key));
693 return keys;
694 }
695 function d3_map_size() {
696 var size = 0;
697 for (var key in this._) ++size;
698 return size;
699 }
700 function d3_map_empty() {
701 for (var key in this._) return false;
702 return true;
703 }
704 d3.nest = function() {
705 var nest = {}, keys = [], sortKeys = [], sortValues, rollup;
706 function map(mapType, array, depth) {
707 if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array;
708 var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter, valuesByKey = new d3_Map(), values;
709 while (++i < n) {
710 if (values = valuesByKey.get(keyValue = key(object = array[i]))) {
711 values.push(object);
712 } else {
713 valuesByKey.set(keyValue, [ object ]);
714 }
715 }
716 if (mapType) {
717 object = mapType();
718 setter = function(keyValue, values) {
719 object.set(keyValue, map(mapType, values, depth));
720 };
721 } else {
722 object = {};
723 setter = function(keyValue, values) {
724 object[keyValue] = map(mapType, values, depth);
725 };
726 }
727 valuesByKey.forEach(setter);
728 return object;
729 }
730 function entries(map, depth) {
731 if (depth >= keys.length) return map;
732 var array = [], sortKey = sortKeys[depth++];
733 map.forEach(function(key, keyMap) {
734 array.push({
735 key: key,
736 values: entries(keyMap, depth)
737 });
738 });
739 return sortKey ? array.sort(function(a, b) {
740 return sortKey(a.key, b.key);
741 }) : array;
742 }
743 nest.map = function(array, mapType) {
744 return map(mapType, array, 0);
745 };
746 nest.entries = function(array) {
747 return entries(map(d3.map, array, 0), 0);
748 };
749 nest.key = function(d) {
750 keys.push(d);
751 return nest;
752 };
753 nest.sortKeys = function(order) {
754 sortKeys[keys.length - 1] = order;
755 return nest;
756 };
757 nest.sortValues = function(order) {
758 sortValues = order;
759 return nest;
760 };
761 nest.rollup = function(f) {
762 rollup = f;
763 return nest;
764 };
765 return nest;
766 };
767 d3.set = function(array) {
768 var set = new d3_Set();
769 if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]);
770 return set;
771 };
772 function d3_Set() {
773 this._ = Object.create(null);
774 }
775 d3_class(d3_Set, {
776 has: d3_map_has,
777 add: function(key) {
778 this._[d3_map_escape(key += "")] = true;
779 return key;
780 },
781 remove: d3_map_remove,
782 values: d3_map_keys,
783 size: d3_map_size,
784 empty: d3_map_empty,
785 forEach: function(f) {
786 for (var key in this._) f.call(this, d3_map_unescape(key));
787 }
788 });
789 d3.behavior = {};
790 d3.rebind = function(target, source) {
791 var i = 1, n = arguments.length, method;
792 while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]);
793 return target;
794 };
795 function d3_rebind(target, source, method) {
796 return function() {
797 var value = method.apply(source, arguments);
798 return value === source ? target : value;
799 };
800 }
801 function d3_vendorSymbol(object, name) {
802 if (name in object) return name;
803 name = name.charAt(0).toUpperCase() + name.slice(1);
804 for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) {
805 var prefixName = d3_vendorPrefixes[i] + name;
806 if (prefixName in object) return prefixName;
807 }
808 }
809 var d3_vendorPrefixes = [ "webkit", "ms", "moz", "Moz", "o", "O" ];
810 function d3_noop() {}
811 d3.dispatch = function() {
812 var dispatch = new d3_dispatch(), i = -1, n = arguments.length;
813 while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
814 return dispatch;
815 };
816 function d3_dispatch() {}
817 d3_dispatch.prototype.on = function(type, listener) {
818 var i = type.indexOf("."), name = "";
819 if (i >= 0) {
820 name = type.slice(i + 1);
821 type = type.slice(0, i);
822 }
823 if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener);
824 if (arguments.length === 2) {
825 if (listener == null) for (type in this) {
826 if (this.hasOwnProperty(type)) this[type].on(name, null);
827 }
828 return this;
829 }
830 };
831 function d3_dispatch_event(dispatch) {
832 var listeners = [], listenerByName = new d3_Map();
833 function event() {
834 var z = listeners, i = -1, n = z.length, l;
835 while (++i < n) if (l = z[i].on) l.apply(this, arguments);
836 return dispatch;
837 }
838 event.on = function(name, listener) {
839 var l = listenerByName.get(name), i;
840 if (arguments.length < 2) return l && l.on;
841 if (l) {
842 l.on = null;
843 listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1));
844 listenerByName.remove(name);
845 }
846 if (listener) listeners.push(listenerByName.set(name, {
847 on: listener
848 }));
849 return dispatch;
850 };
851 return event;
852 }
853 d3.event = null;
854 function d3_eventPreventDefault() {
855 d3.event.preventDefault();
856 }
857 function d3_eventSource() {
858 var e = d3.event, s;
859 while (s = e.sourceEvent) e = s;
860 return e;
861 }
862 function d3_eventDispatch(target) {
863 var dispatch = new d3_dispatch(), i = 0, n = arguments.length;
864 while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
865 dispatch.of = function(thiz, argumentz) {
866 return function(e1) {
867 try {
868 var e0 = e1.sourceEvent = d3.event;
869 e1.target = target;
870 d3.event = e1;
871 dispatch[e1.type].apply(thiz, argumentz);
872 } finally {
873 d3.event = e0;
874 }
875 };
876 };
877 return dispatch;
878 }
879 d3.requote = function(s) {
880 return s.replace(d3_requote_re, "\\$&");
881 };
882 var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
883 var d3_subclass = {}.__proto__ ? function(object, prototype) {
884 object.__proto__ = prototype;
885 } : function(object, prototype) {
886 for (var property in prototype) object[property] = prototype[property];
887 };
888 function d3_selection(groups) {
889 d3_subclass(groups, d3_selectionPrototype);
890 return groups;
891 }
892 var d3_select = function(s, n) {
893 return n.querySelector(s);
894 }, d3_selectAll = function(s, n) {
895 return n.querySelectorAll(s);
896 }, d3_selectMatcher = d3_documentElement.matches || d3_documentElement[d3_vendorSymbol(d3_documentElement, "matchesSelector")], d3_selectMatches = function(n, s) {
897 return d3_selectMatcher.call(n, s);
898 };
899 if (typeof Sizzle === "function") {
900 d3_select = function(s, n) {
901 return Sizzle(s, n)[0] || null;
902 };
903 d3_selectAll = Sizzle;
904 d3_selectMatches = Sizzle.matchesSelector;
905 }
906 d3.selection = function() {
907 return d3_selectionRoot;
908 };
909 var d3_selectionPrototype = d3.selection.prototype = [];
910 d3_selectionPrototype.select = function(selector) {
911 var subgroups = [], subgroup, subnode, group, node;
912 selector = d3_selection_selector(selector);
913 for (var j = -1, m = this.length; ++j < m; ) {
914 subgroups.push(subgroup = []);
915 subgroup.parentNode = (group = this[j]).parentNode;
916 for (var i = -1, n = group.length; ++i < n; ) {
917 if (node = group[i]) {
918 subgroup.push(subnode = selector.call(node, node.__data__, i, j));
919 if (subnode && "__data__" in node) subnode.__data__ = node.__data__;
920 } else {
921 subgroup.push(null);
922 }
923 }
924 }
925 return d3_selection(subgroups);
926 };
927 function d3_selection_selector(selector) {
928 return typeof selector === "function" ? selector : function() {
929 return d3_select(selector, this);
930 };
931 }
932 d3_selectionPrototype.selectAll = function(selector) {
933 var subgroups = [], subgroup, node;
934 selector = d3_selection_selectorAll(selector);
935 for (var j = -1, m = this.length; ++j < m; ) {
936 for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
937 if (node = group[i]) {
938 subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j)));
939 subgroup.parentNode = node;
940 }
941 }
942 }
943 return d3_selection(subgroups);
944 };
945 function d3_selection_selectorAll(selector) {
946 return typeof selector === "function" ? selector : function() {
947 return d3_selectAll(selector, this);
948 };
949 }
950 var d3_nsPrefix = {
951 svg: "http://www.w3.org/2000/svg",
952 xhtml: "http://www.w3.org/1999/xhtml",
953 xlink: "http://www.w3.org/1999/xlink",
954 xml: "http://www.w3.org/XML/1998/namespace",
955 xmlns: "http://www.w3.org/2000/xmlns/"
956 };
957 d3.ns = {
958 prefix: d3_nsPrefix,
959 qualify: function(name) {
960 var i = name.indexOf(":"), prefix = name;
961 if (i >= 0) {
962 prefix = name.slice(0, i);
963 name = name.slice(i + 1);
964 }
965 return d3_nsPrefix.hasOwnProperty(prefix) ? {
966 space: d3_nsPrefix[prefix],
967 local: name
968 } : name;
969 }
970 };
971 d3_selectionPrototype.attr = function(name, value) {
972 if (arguments.length < 2) {
973 if (typeof name === "string") {
974 var node = this.node();
975 name = d3.ns.qualify(name);
976 return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name);
977 }
978 for (value in name) this.each(d3_selection_attr(value, name[value]));
979 return this;
980 }
981 return this.each(d3_selection_attr(name, value));
982 };
983 function d3_selection_attr(name, value) {
984 name = d3.ns.qualify(name);
985 function attrNull() {
986 this.removeAttribute(name);
987 }
988 function attrNullNS() {
989 this.removeAttributeNS(name.space, name.local);
990 }
991 function attrConstant() {
992 this.setAttribute(name, value);
993 }
994 function attrConstantNS() {
995 this.setAttributeNS(name.space, name.local, value);
996 }
997 function attrFunction() {
998 var x = value.apply(this, arguments);
999 if (x == null) this.removeAttribute(name); else this.setAttribute(name, x);
1000 }
1001 function attrFunctionNS() {
1002 var x = value.apply(this, arguments);
1003 if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x);
1004 }
1005 return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant;
1006 }
1007 function d3_collapse(s) {
1008 return s.trim().replace(/\s+/g, " ");
1009 }
1010 d3_selectionPrototype.classed = function(name, value) {
1011 if (arguments.length < 2) {
1012 if (typeof name === "string") {
1013 var node = this.node(), n = (name = d3_selection_classes(name)).length, i = -1;
1014 if (value = node.classList) {
1015 while (++i < n) if (!value.contains(name[i])) return false;
1016 } else {
1017 value = node.getAttribute("class");
1018 while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false;
1019 }
1020 return true;
1021 }
1022 for (value in name) this.each(d3_selection_classed(value, name[value]));
1023 return this;
1024 }
1025 return this.each(d3_selection_classed(name, value));
1026 };
1027 function d3_selection_classedRe(name) {
1028 return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g");
1029 }
1030 function d3_selection_classes(name) {
1031 return (name + "").trim().split(/^|\s+/);
1032 }
1033 function d3_selection_classed(name, value) {
1034 name = d3_selection_classes(name).map(d3_selection_classedName);
1035 var n = name.length;
1036 function classedConstant() {
1037 var i = -1;
1038 while (++i < n) name[i](this, value);
1039 }
1040 function classedFunction() {
1041 var i = -1, x = value.apply(this, arguments);
1042 while (++i < n) name[i](this, x);
1043 }
1044 return typeof value === "function" ? classedFunction : classedConstant;
1045 }
1046 function d3_selection_classedName(name) {
1047 var re = d3_selection_classedRe(name);
1048 return function(node, value) {
1049 if (c = node.classList) return value ? c.add(name) : c.remove(name);
1050 var c = node.getAttribute("class") || "";
1051 if (value) {
1052 re.lastIndex = 0;
1053 if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name));
1054 } else {
1055 node.setAttribute("class", d3_collapse(c.replace(re, " ")));
1056 }
1057 };
1058 }
1059 d3_selectionPrototype.style = function(name, value, priority) {
1060 var n = arguments.length;
1061 if (n < 3) {
1062 if (typeof name !== "string") {
1063 if (n < 2) value = "";
1064 for (priority in name) this.each(d3_selection_style(priority, name[priority], value));
1065 return this;
1066 }
1067 if (n < 2) return d3_window.getComputedStyle(this.node(), null).getPropertyValue(name);
1068 priority = "";
1069 }
1070 return this.each(d3_selection_style(name, value, priority));
1071 };
1072 function d3_selection_style(name, value, priority) {
1073 function styleNull() {
1074 this.style.removeProperty(name);
1075 }
1076 function styleConstant() {
1077 this.style.setProperty(name, value, priority);
1078 }
1079 function styleFunction() {
1080 var x = value.apply(this, arguments);
1081 if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority);
1082 }
1083 return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant;
1084 }
1085 d3_selectionPrototype.property = function(name, value) {
1086 if (arguments.length < 2) {
1087 if (typeof name === "string") return this.node()[name];
1088 for (value in name) this.each(d3_selection_property(value, name[value]));
1089 return this;
1090 }
1091 return this.each(d3_selection_property(name, value));
1092 };
1093 function d3_selection_property(name, value) {
1094 function propertyNull() {
1095 delete this[name];
1096 }
1097 function propertyConstant() {
1098 this[name] = value;
1099 }
1100 function propertyFunction() {
1101 var x = value.apply(this, arguments);
1102 if (x == null) delete this[name]; else this[name] = x;
1103 }
1104 return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant;
1105 }
1106 d3_selectionPrototype.text = function(value) {
1107 return arguments.length ? this.each(typeof value === "function" ? function() {
1108 var v = value.apply(this, arguments);
1109 this.textContent = v == null ? "" : v;
1110 } : value == null ? function() {
1111 this.textContent = "";
1112 } : function() {
1113 this.textContent = value;
1114 }) : this.node().textContent;
1115 };
1116 d3_selectionPrototype.html = function(value) {
1117 return arguments.length ? this.each(typeof value === "function" ? function() {
1118 var v = value.apply(this, arguments);
1119 this.innerHTML = v == null ? "" : v;
1120 } : value == null ? function() {
1121 this.innerHTML = "";
1122 } : function() {
1123 this.innerHTML = value;
1124 }) : this.node().innerHTML;
1125 };
1126 d3_selectionPrototype.append = function(name) {
1127 name = d3_selection_creator(name);
1128 return this.select(function() {
1129 return this.appendChild(name.apply(this, arguments));
1130 });
1131 };
1132 function d3_selection_creator(name) {
1133 return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? function() {
1134 return this.ownerDocument.createElementNS(name.space, name.local);
1135 } : function() {
1136 return this.ownerDocument.createElementNS(this.namespaceURI, name);
1137 };
1138 }
1139 d3_selectionPrototype.insert = function(name, before) {
1140 name = d3_selection_creator(name);
1141 before = d3_selection_selector(before);
1142 return this.select(function() {
1143 return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments) || null);
1144 });
1145 };
1146 d3_selectionPrototype.remove = function() {
1147 return this.each(d3_selectionRemove);
1148 };
1149 function d3_selectionRemove() {
1150 var parent = this.parentNode;
1151 if (parent) parent.removeChild(this);
1152 }
1153 d3_selectionPrototype.data = function(value, key) {
1154 var i = -1, n = this.length, group, node;
1155 if (!arguments.length) {
1156 value = new Array(n = (group = this[0]).length);
1157 while (++i < n) {
1158 if (node = group[i]) {
1159 value[i] = node.__data__;
1160 }
1161 }
1162 return value;
1163 }
1164 function bind(group, groupData) {
1165 var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes = new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData;
1166 if (key) {
1167 var nodeByKeyValue = new d3_Map(), keyValues = new Array(n), keyValue;
1168 for (i = -1; ++i < n; ) {
1169 if (nodeByKeyValue.has(keyValue = key.call(node = group[i], node.__data__, i))) {
1170 exitNodes[i] = node;
1171 } else {
1172 nodeByKeyValue.set(keyValue, node);
1173 }
1174 keyValues[i] = keyValue;
1175 }
1176 for (i = -1; ++i < m; ) {
1177 if (!(node = nodeByKeyValue.get(keyValue = key.call(groupData, nodeData = groupData[i], i)))) {
1178 enterNodes[i] = d3_selection_dataNode(nodeData);
1179 } else if (node !== true) {
1180 updateNodes[i] = node;
1181 node.__data__ = nodeData;
1182 }
1183 nodeByKeyValue.set(keyValue, true);
1184 }
1185 for (i = -1; ++i < n; ) {
1186 if (nodeByKeyValue.get(keyValues[i]) !== true) {
1187 exitNodes[i] = group[i];
1188 }
1189 }
1190 } else {
1191 for (i = -1; ++i < n0; ) {
1192 node = group[i];
1193 nodeData = groupData[i];
1194 if (node) {
1195 node.__data__ = nodeData;
1196 updateNodes[i] = node;
1197 } else {
1198 enterNodes[i] = d3_selection_dataNode(nodeData);
1199 }
1200 }
1201 for (;i < m; ++i) {
1202 enterNodes[i] = d3_selection_dataNode(groupData[i]);
1203 }
1204 for (;i < n; ++i) {
1205 exitNodes[i] = group[i];
1206 }
1207 }
1208 enterNodes.update = updateNodes;
1209 enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode;
1210 enter.push(enterNodes);
1211 update.push(updateNodes);
1212 exit.push(exitNodes);
1213 }
1214 var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]);
1215 if (typeof value === "function") {
1216 while (++i < n) {
1217 bind(group = this[i], value.call(group, group.parentNode.__data__, i));
1218 }
1219 } else {
1220 while (++i < n) {
1221 bind(group = this[i], value);
1222 }
1223 }
1224 update.enter = function() {
1225 return enter;
1226 };
1227 update.exit = function() {
1228 return exit;
1229 };
1230 return update;
1231 };
1232 function d3_selection_dataNode(data) {
1233 return {
1234 __data__: data
1235 };
1236 }
1237 d3_selectionPrototype.datum = function(value) {
1238 return arguments.length ? this.property("__data__", value) : this.property("__data__");
1239 };
1240 d3_selectionPrototype.filter = function(filter) {
1241 var subgroups = [], subgroup, group, node;
1242 if (typeof filter !== "function") filter = d3_selection_filter(filter);
1243 for (var j = 0, m = this.length; j < m; j++) {
1244 subgroups.push(subgroup = []);
1245 subgroup.parentNode = (group = this[j]).parentNode;
1246 for (var i = 0, n = group.length; i < n; i++) {
1247 if ((node = group[i]) && filter.call(node, node.__data__, i, j)) {
1248 subgroup.push(node);
1249 }
1250 }
1251 }
1252 return d3_selection(subgroups);
1253 };
1254 function d3_selection_filter(selector) {
1255 return function() {
1256 return d3_selectMatches(this, selector);
1257 };
1258 }
1259 d3_selectionPrototype.order = function() {
1260 for (var j = -1, m = this.length; ++j < m; ) {
1261 for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) {
1262 if (node = group[i]) {
1263 if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
1264 next = node;
1265 }
1266 }
1267 }
1268 return this;
1269 };
1270 d3_selectionPrototype.sort = function(comparator) {
1271 comparator = d3_selection_sortComparator.apply(this, arguments);
1272 for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator);
1273 return this.order();
1274 };
1275 function d3_selection_sortComparator(comparator) {
1276 if (!arguments.length) comparator = d3_ascending;
1277 return function(a, b) {
1278 return a && b ? comparator(a.__data__, b.__data__) : !a - !b;
1279 };
1280 }
1281 d3_selectionPrototype.each = function(callback) {
1282 return d3_selection_each(this, function(node, i, j) {
1283 callback.call(node, node.__data__, i, j);
1284 });
1285 };
1286 function d3_selection_each(groups, callback) {
1287 for (var j = 0, m = groups.length; j < m; j++) {
1288 for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) {
1289 if (node = group[i]) callback(node, i, j);
1290 }
1291 }
1292 return groups;
1293 }
1294 d3_selectionPrototype.call = function(callback) {
1295 var args = d3_array(arguments);
1296 callback.apply(args[0] = this, args);
1297 return this;
1298 };
1299 d3_selectionPrototype.empty = function() {
1300 return !this.node();
1301 };
1302 d3_selectionPrototype.node = function() {
1303 for (var j = 0, m = this.length; j < m; j++) {
1304 for (var group = this[j], i = 0, n = group.length; i < n; i++) {
1305 var node = group[i];
1306 if (node) return node;
1307 }
1308 }
1309 return null;
1310 };
1311 d3_selectionPrototype.size = function() {
1312 var n = 0;
1313 d3_selection_each(this, function() {
1314 ++n;
1315 });
1316 return n;
1317 };
1318 function d3_selection_enter(selection) {
1319 d3_subclass(selection, d3_selection_enterPrototype);
1320 return selection;
1321 }
1322 var d3_selection_enterPrototype = [];
1323 d3.selection.enter = d3_selection_enter;
1324 d3.selection.enter.prototype = d3_selection_enterPrototype;
1325 d3_selection_enterPrototype.append = d3_selectionPrototype.append;
1326 d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;
1327 d3_selection_enterPrototype.node = d3_selectionPrototype.node;
1328 d3_selection_enterPrototype.call = d3_selectionPrototype.call;
1329 d3_selection_enterPrototype.size = d3_selectionPrototype.size;
1330 d3_selection_enterPrototype.select = function(selector) {
1331 var subgroups = [], subgroup, subnode, upgroup, group, node;
1332 for (var j = -1, m = this.length; ++j < m; ) {
1333 upgroup = (group = this[j]).update;
1334 subgroups.push(subgroup = []);
1335 subgroup.parentNode = group.parentNode;
1336 for (var i = -1, n = group.length; ++i < n; ) {
1337 if (node = group[i]) {
1338 subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j));
1339 subnode.__data__ = node.__data__;
1340 } else {
1341 subgroup.push(null);
1342 }
1343 }
1344 }
1345 return d3_selection(subgroups);
1346 };
1347 d3_selection_enterPrototype.insert = function(name, before) {
1348 if (arguments.length < 2) before = d3_selection_enterInsertBefore(this);
1349 return d3_selectionPrototype.insert.call(this, name, before);
1350 };
1351 function d3_selection_enterInsertBefore(enter) {
1352 var i0, j0;
1353 return function(d, i, j) {
1354 var group = enter[j].update, n = group.length, node;
1355 if (j != j0) j0 = j, i0 = 0;
1356 if (i >= i0) i0 = i + 1;
1357 while (!(node = group[i0]) && ++i0 < n) ;
1358 return node;
1359 };
1360 }
1361 d3.select = function(node) {
1362 var group = [ typeof node === "string" ? d3_select(node, d3_document) : node ];
1363 group.parentNode = d3_documentElement;
1364 return d3_selection([ group ]);
1365 };
1366 d3.selectAll = function(nodes) {
1367 var group = d3_array(typeof nodes === "string" ? d3_selectAll(nodes, d3_document) : nodes);
1368 group.parentNode = d3_documentElement;
1369 return d3_selection([ group ]);
1370 };
1371 var d3_selectionRoot = d3.select(d3_documentElement);
1372 d3_selectionPrototype.on = function(type, listener, capture) {
1373 var n = arguments.length;
1374 if (n < 3) {
1375 if (typeof type !== "string") {
1376 if (n < 2) listener = false;
1377 for (capture in type) this.each(d3_selection_on(capture, type[capture], listener));
1378 return this;
1379 }
1380 if (n < 2) return (n = this.node()["__on" + type]) && n._;
1381 capture = false;
1382 }
1383 return this.each(d3_selection_on(type, listener, capture));
1384 };
1385 function d3_selection_on(type, listener, capture) {
1386 var name = "__on" + type, i = type.indexOf("."), wrap = d3_selection_onListener;
1387 if (i > 0) type = type.slice(0, i);
1388 var filter = d3_selection_onFilters.get(type);
1389 if (filter) type = filter, wrap = d3_selection_onFilter;
1390 function onRemove() {
1391 var l = this[name];
1392 if (l) {
1393 this.removeEventListener(type, l, l.$);
1394 delete this[name];
1395 }
1396 }
1397 function onAdd() {
1398 var l = wrap(listener, d3_array(arguments));
1399 onRemove.call(this);
1400 this.addEventListener(type, this[name] = l, l.$ = capture);
1401 l._ = listener;
1402 }
1403 function removeAll() {
1404 var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"), match;
1405 for (var name in this) {
1406 if (match = name.match(re)) {
1407 var l = this[name];
1408 this.removeEventListener(match[1], l, l.$);
1409 delete this[name];
1410 }
1411 }
1412 }
1413 return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll;
1414 }
1415 var d3_selection_onFilters = d3.map({
1416 mouseenter: "mouseover",
1417 mouseleave: "mouseout"
1418 });
1419 d3_selection_onFilters.forEach(function(k) {
1420 if ("on" + k in d3_document) d3_selection_onFilters.remove(k);
1421 });
1422 function d3_selection_onListener(listener, argumentz) {
1423 return function(e) {
1424 var o = d3.event;
1425 d3.event = e;
1426 argumentz[0] = this.__data__;
1427 try {
1428 listener.apply(this, argumentz);
1429 } finally {
1430 d3.event = o;
1431 }
1432 };
1433 }
1434 function d3_selection_onFilter(listener, argumentz) {
1435 var l = d3_selection_onListener(listener, argumentz);
1436 return function(e) {
1437 var target = this, related = e.relatedTarget;
1438 if (!related || related !== target && !(related.compareDocumentPosition(target) & 8)) {
1439 l.call(target, e);
1440 }
1441 };
1442 }
1443 var d3_event_dragSelect = "onselectstart" in d3_document ? null : d3_vendorSymbol(d3_documentElement.style, "userSelect"), d3_event_dragId = 0;
1444 function d3_event_dragSuppress() {
1445 var name = ".dragsuppress-" + ++d3_event_dragId, click = "click" + name, w = d3.select(d3_window).on("touchmove" + name, d3_eventPreventDefault).on("dragstart" + name, d3_eventPreventDefault).on("selectstart" + name, d3_eventPreventDefault);
1446 if (d3_event_dragSelect) {
1447 var style = d3_documentElement.style, select = style[d3_event_dragSelect];
1448 style[d3_event_dragSelect] = "none";
1449 }
1450 return function(suppressClick) {
1451 w.on(name, null);
1452 if (d3_event_dragSelect) style[d3_event_dragSelect] = select;
1453 if (suppressClick) {
1454 var off = function() {
1455 w.on(click, null);
1456 };
1457 w.on(click, function() {
1458 d3_eventPreventDefault();
1459 off();
1460 }, true);
1461 setTimeout(off, 0);
1462 }
1463 };
1464 }
1465 d3.mouse = function(container) {
1466 return d3_mousePoint(container, d3_eventSource());
1467 };
1468 var d3_mouse_bug44083 = /WebKit/.test(d3_window.navigator.userAgent) ? -1 : 0;
1469 function d3_mousePoint(container, e) {
1470 if (e.changedTouches) e = e.changedTouches[0];
1471 var svg = container.ownerSVGElement || container;
1472 if (svg.createSVGPoint) {
1473 var point = svg.createSVGPoint();
1474 if (d3_mouse_bug44083 < 0 && (d3_window.scrollX || d3_window.scrollY)) {
1475 svg = d3.select("body").append("svg").style({
1476 position: "absolute",
1477 top: 0,
1478 left: 0,
1479 margin: 0,
1480 padding: 0,
1481 border: "none"
1482 }, "important");
1483 var ctm = svg[0][0].getScreenCTM();
1484 d3_mouse_bug44083 = !(ctm.f || ctm.e);
1485 svg.remove();
1486 }
1487 if (d3_mouse_bug44083) point.x = e.pageX, point.y = e.pageY; else point.x = e.clientX,
1488 point.y = e.clientY;
1489 point = point.matrixTransform(container.getScreenCTM().inverse());
1490 return [ point.x, point.y ];
1491 }
1492 var rect = container.getBoundingClientRect();
1493 return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ];
1494 }
1495 d3.touch = function(container, touches, identifier) {
1496 if (arguments.length < 3) identifier = touches, touches = d3_eventSource().changedTouches;
1497 if (touches) for (var i = 0, n = touches.length, touch; i < n; ++i) {
1498 if ((touch = touches[i]).identifier === identifier) {
1499 return d3_mousePoint(container, touch);
1500 }
1501 }
1502 };
1503 d3.behavior.drag = function() {
1504 var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null, mousedown = dragstart(d3_noop, d3.mouse, d3_behavior_dragMouseSubject, "mousemove", "mouseup"), touchstart = dragstart(d3_behavior_dragTouchId, d3.touch, d3_behavior_dragTouchSubject, "touchmove", "touchend");
1505 function drag() {
1506 this.on("mousedown.drag", mousedown).on("touchstart.drag", touchstart);
1507 }
1508 function dragstart(id, position, subject, move, end) {
1509 return function() {
1510 var that = this, target = d3.event.target, parent = that.parentNode, dispatch = event.of(that, arguments), dragged = 0, dragId = id(), dragName = ".drag" + (dragId == null ? "" : "-" + dragId), dragOffset, dragSubject = d3.select(subject()).on(move + dragName, moved).on(end + dragName, ended), dragRestore = d3_event_dragSuppress(), position0 = position(parent, dragId);
1511 if (origin) {
1512 dragOffset = origin.apply(that, arguments);
1513 dragOffset = [ dragOffset.x - position0[0], dragOffset.y - position0[1] ];
1514 } else {
1515 dragOffset = [ 0, 0 ];
1516 }
1517 dispatch({
1518 type: "dragstart"
1519 });
1520 function moved() {
1521 var position1 = position(parent, dragId), dx, dy;
1522 if (!position1) return;
1523 dx = position1[0] - position0[0];
1524 dy = position1[1] - position0[1];
1525 dragged |= dx | dy;
1526 position0 = position1;
1527 dispatch({
1528 type: "drag",
1529 x: position1[0] + dragOffset[0],
1530 y: position1[1] + dragOffset[1],
1531 dx: dx,
1532 dy: dy
1533 });
1534 }
1535 function ended() {
1536 if (!position(parent, dragId)) return;
1537 dragSubject.on(move + dragName, null).on(end + dragName, null);
1538 dragRestore(dragged && d3.event.target === target);
1539 dispatch({
1540 type: "dragend"
1541 });
1542 }
1543 };
1544 }
1545 drag.origin = function(x) {
1546 if (!arguments.length) return origin;
1547 origin = x;
1548 return drag;
1549 };
1550 return d3.rebind(drag, event, "on");
1551 };
1552 function d3_behavior_dragTouchId() {
1553 return d3.event.changedTouches[0].identifier;
1554 }
1555 function d3_behavior_dragTouchSubject() {
1556 return d3.event.target;
1557 }
1558 function d3_behavior_dragMouseSubject() {
1559 return d3_window;
1560 }
1561 d3.touches = function(container, touches) {
1562 if (arguments.length < 2) touches = d3_eventSource().touches;
1563 return touches ? d3_array(touches).map(function(touch) {
1564 var point = d3_mousePoint(container, touch);
1565 point.identifier = touch.identifier;
1566 return point;
1567 }) : [];
1568 };
1569 var ε = 1e-6, ε2 = ε * ε, π = Math.PI, τ = 2 * π, τε = τ - ε, halfπ = π / 2, d3_radians = π / 180, d3_degrees = 180 / π;
1570 function d3_sgn(x) {
1571 return x > 0 ? 1 : x < 0 ? -1 : 0;
1572 }
1573 function d3_cross2d(a, b, c) {
1574 return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
1575 }
1576 function d3_acos(x) {
1577 return x > 1 ? 0 : x < -1 ? π : Math.acos(x);
1578 }
1579 function d3_asin(x) {
1580 return x > 1 ? halfπ : x < -1 ? -halfπ : Math.asin(x);
1581 }
1582 function d3_sinh(x) {
1583 return ((x = Math.exp(x)) - 1 / x) / 2;
1584 }
1585 function d3_cosh(x) {
1586 return ((x = Math.exp(x)) + 1 / x) / 2;
1587 }
1588 function d3_tanh(x) {
1589 return ((x = Math.exp(2 * x)) - 1) / (x + 1);
1590 }
1591 function d3_haversin(x) {
1592 return (x = Math.sin(x / 2)) * x;
1593 }
1594 var ρ = Math.SQRT2, ρ2 = 2, ρ4 = 4;
1595 d3.interpolateZoom = function(p0, p1) {
1596 var ux0 = p0[0], uy0 = p0[1], w0 = p0[2], ux1 = p1[0], uy1 = p1[1], w1 = p1[2];
1597 var dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, d1 = Math.sqrt(d2), b0 = (w1 * w1 - w0 * w0 + ρ4 * d2) / (2 * w0 * ρ2 * d1), b1 = (w1 * w1 - w0 * w0 - ρ4 * d2) / (2 * w1 * ρ2 * d1), r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1), dr = r1 - r0, S = (dr || Math.log(w1 / w0)) / ρ;
1598 function interpolate(t) {
1599 var s = t * S;
1600 if (dr) {
1601 var coshr0 = d3_cosh(r0), u = w0 / (ρ2 * d1) * (coshr0 * d3_tanh(ρ * s + r0) - d3_sinh(r0));
1602 return [ ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / d3_cosh(ρ * s + r0) ];
1603 }
1604 return [ ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(ρ * s) ];
1605 }
1606 interpolate.duration = S * 1e3;
1607 return interpolate;
1608 };
1609 d3.behavior.zoom = function() {
1610 var view = {
1611 x: 0,
1612 y: 0,
1613 k: 1
1614 }, translate0, center0, center, size = [ 960, 500 ], scaleExtent = d3_behavior_zoomInfinity, duration = 250, zooming = 0, mousedown = "mousedown.zoom", mousemove = "mousemove.zoom", mouseup = "mouseup.zoom", mousewheelTimer, touchstart = "touchstart.zoom", touchtime, event = d3_eventDispatch(zoom, "zoomstart", "zoom", "zoomend"), x0, x1, y0, y1;
1615 function zoom(g) {
1616 g.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + ".zoom", mousewheeled).on("dblclick.zoom", dblclicked).on(touchstart, touchstarted);
1617 }
1618 zoom.event = function(g) {
1619 g.each(function() {
1620 var dispatch = event.of(this, arguments), view1 = view;
1621 if (d3_transitionInheritId) {
1622 d3.select(this).transition().each("start.zoom", function() {
1623 view = this.__chart__ || {
1624 x: 0,
1625 y: 0,
1626 k: 1
1627 };
1628 zoomstarted(dispatch);
1629 }).tween("zoom:zoom", function() {
1630 var dx = size[0], dy = size[1], cx = center0 ? center0[0] : dx / 2, cy = center0 ? center0[1] : dy / 2, i = d3.interpolateZoom([ (cx - view.x) / view.k, (cy - view.y) / view.k, dx / view.k ], [ (cx - view1.x) / view1.k, (cy - view1.y) / view1.k, dx / view1.k ]);
1631 return function(t) {
1632 var l = i(t), k = dx / l[2];
1633 this.__chart__ = view = {
1634 x: cx - l[0] * k,
1635 y: cy - l[1] * k,
1636 k: k
1637 };
1638 zoomed(dispatch);
1639 };
1640 }).each("interrupt.zoom", function() {
1641 zoomended(dispatch);
1642 }).each("end.zoom", function() {
1643 zoomended(dispatch);
1644 });
1645 } else {
1646 this.__chart__ = view;
1647 zoomstarted(dispatch);
1648 zoomed(dispatch);
1649 zoomended(dispatch);
1650 }
1651 });
1652 };
1653 zoom.translate = function(_) {
1654 if (!arguments.length) return [ view.x, view.y ];
1655 view = {
1656 x: +_[0],
1657 y: +_[1],
1658 k: view.k
1659 };
1660 rescale();
1661 return zoom;
1662 };
1663 zoom.scale = function(_) {
1664 if (!arguments.length) return view.k;
1665 view = {
1666 x: view.x,
1667 y: view.y,
1668 k: +_
1669 };
1670 rescale();
1671 return zoom;
1672 };
1673 zoom.scaleExtent = function(_) {
1674 if (!arguments.length) return scaleExtent;
1675 scaleExtent = _ == null ? d3_behavior_zoomInfinity : [ +_[0], +_[1] ];
1676 return zoom;
1677 };
1678 zoom.center = function(_) {
1679 if (!arguments.length) return center;
1680 center = _ && [ +_[0], +_[1] ];
1681 return zoom;
1682 };
1683 zoom.size = function(_) {
1684 if (!arguments.length) return size;
1685 size = _ && [ +_[0], +_[1] ];
1686 return zoom;
1687 };
1688 zoom.duration = function(_) {
1689 if (!arguments.length) return duration;
1690 duration = +_;
1691 return zoom;
1692 };
1693 zoom.x = function(z) {
1694 if (!arguments.length) return x1;
1695 x1 = z;
1696 x0 = z.copy();
1697 view = {
1698 x: 0,
1699 y: 0,
1700 k: 1
1701 };
1702 return zoom;
1703 };
1704 zoom.y = function(z) {
1705 if (!arguments.length) return y1;
1706 y1 = z;
1707 y0 = z.copy();
1708 view = {
1709 x: 0,
1710 y: 0,
1711 k: 1
1712 };
1713 return zoom;
1714 };
1715 function location(p) {
1716 return [ (p[0] - view.x) / view.k, (p[1] - view.y) / view.k ];
1717 }
1718 function point(l) {
1719 return [ l[0] * view.k + view.x, l[1] * view.k + view.y ];
1720 }
1721 function scaleTo(s) {
1722 view.k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s));
1723 }
1724 function translateTo(p, l) {
1725 l = point(l);
1726 view.x += p[0] - l[0];
1727 view.y += p[1] - l[1];
1728 }
1729 function zoomTo(that, p, l, k) {
1730 that.__chart__ = {
1731 x: view.x,
1732 y: view.y,
1733 k: view.k
1734 };
1735 scaleTo(Math.pow(2, k));
1736 translateTo(center0 = p, l);
1737 that = d3.select(that);
1738 if (duration > 0) that = that.transition().duration(duration);
1739 that.call(zoom.event);
1740 }
1741 function rescale() {
1742 if (x1) x1.domain(x0.range().map(function(x) {
1743 return (x - view.x) / view.k;
1744 }).map(x0.invert));
1745 if (y1) y1.domain(y0.range().map(function(y) {
1746 return (y - view.y) / view.k;
1747 }).map(y0.invert));
1748 }
1749 function zoomstarted(dispatch) {
1750 if (!zooming++) dispatch({
1751 type: "zoomstart"
1752 });
1753 }
1754 function zoomed(dispatch) {
1755 rescale();
1756 dispatch({
1757 type: "zoom",
1758 scale: view.k,
1759 translate: [ view.x, view.y ]
1760 });
1761 }
1762 function zoomended(dispatch) {
1763 if (!--zooming) dispatch({
1764 type: "zoomend"
1765 });
1766 center0 = null;
1767 }
1768 function mousedowned() {
1769 var that = this, target = d3.event.target, dispatch = event.of(that, arguments), dragged = 0, subject = d3.select(d3_window).on(mousemove, moved).on(mouseup, ended), location0 = location(d3.mouse(that)), dragRestore = d3_event_dragSuppress();
1770 d3_selection_interrupt.call(that);
1771 zoomstarted(dispatch);
1772 function moved() {
1773 dragged = 1;
1774 translateTo(d3.mouse(that), location0);
1775 zoomed(dispatch);
1776 }
1777 function ended() {
1778 subject.on(mousemove, null).on(mouseup, null);
1779 dragRestore(dragged && d3.event.target === target);
1780 zoomended(dispatch);
1781 }
1782 }
1783 function touchstarted() {
1784 var that = this, dispatch = event.of(that, arguments), locations0 = {}, distance0 = 0, scale0, zoomName = ".zoom-" + d3.event.changedTouches[0].identifier, touchmove = "touchmove" + zoomName, touchend = "touchend" + zoomName, targets = [], subject = d3.select(that), dragRestore = d3_event_dragSuppress();
1785 started();
1786 zoomstarted(dispatch);
1787 subject.on(mousedown, null).on(touchstart, started);
1788 function relocate() {
1789 var touches = d3.touches(that);
1790 scale0 = view.k;
1791 touches.forEach(function(t) {
1792 if (t.identifier in locations0) locations0[t.identifier] = location(t);
1793 });
1794 return touches;
1795 }
1796 function started() {
1797 var target = d3.event.target;
1798 d3.select(target).on(touchmove, moved).on(touchend, ended);
1799 targets.push(target);
1800 var changed = d3.event.changedTouches;
1801 for (var i = 0, n = changed.length; i < n; ++i) {
1802 locations0[changed[i].identifier] = null;
1803 }
1804 var touches = relocate(), now = Date.now();
1805 if (touches.length === 1) {
1806 if (now - touchtime < 500) {
1807 var p = touches[0];
1808 zoomTo(that, p, locations0[p.identifier], Math.floor(Math.log(view.k) / Math.LN2) + 1);
1809 d3_eventPreventDefault();
1810 }
1811 touchtime = now;
1812 } else if (touches.length > 1) {
1813 var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1];
1814 distance0 = dx * dx + dy * dy;
1815 }
1816 }
1817 function moved() {
1818 var touches = d3.touches(that), p0, l0, p1, l1;
1819 d3_selection_interrupt.call(that);
1820 for (var i = 0, n = touches.length; i < n; ++i, l1 = null) {
1821 p1 = touches[i];
1822 if (l1 = locations0[p1.identifier]) {
1823 if (l0) break;
1824 p0 = p1, l0 = l1;
1825 }
1826 }
1827 if (l1) {
1828 var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1, scale1 = distance0 && Math.sqrt(distance1 / distance0);
1829 p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ];
1830 l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ];
1831 scaleTo(scale1 * scale0);
1832 }
1833 touchtime = null;
1834 translateTo(p0, l0);
1835 zoomed(dispatch);
1836 }
1837 function ended() {
1838 if (d3.event.touches.length) {
1839 var changed = d3.event.changedTouches;
1840 for (var i = 0, n = changed.length; i < n; ++i) {
1841 delete locations0[changed[i].identifier];
1842 }
1843 for (var identifier in locations0) {
1844 return void relocate();
1845 }
1846 }
1847 d3.selectAll(targets).on(zoomName, null);
1848 subject.on(mousedown, mousedowned).on(touchstart, touchstarted);
1849 dragRestore();
1850 zoomended(dispatch);
1851 }
1852 }
1853 function mousewheeled() {
1854 var dispatch = event.of(this, arguments);
1855 if (mousewheelTimer) clearTimeout(mousewheelTimer); else translate0 = location(center0 = center || d3.mouse(this)),
1856 d3_selection_interrupt.call(this), zoomstarted(dispatch);
1857 mousewheelTimer = setTimeout(function() {
1858 mousewheelTimer = null;
1859 zoomended(dispatch);
1860 }, 50);
1861 d3_eventPreventDefault();
1862 scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * view.k);
1863 translateTo(center0, translate0);
1864 zoomed(dispatch);
1865 }
1866 function dblclicked() {
1867 var p = d3.mouse(this), k = Math.log(view.k) / Math.LN2;
1868 zoomTo(this, p, location(p), d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1);
1869 }
1870 return d3.rebind(zoom, event, "on");
1871 };
1872 var d3_behavior_zoomInfinity = [ 0, Infinity ];
1873 var d3_behavior_zoomDelta, d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() {
1874 return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1);
1875 }, "wheel") : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() {
1876 return d3.event.wheelDelta;
1877 }, "mousewheel") : (d3_behavior_zoomDelta = function() {
1878 return -d3.event.detail;
1879 }, "MozMousePixelScroll");
1880 d3.color = d3_color;
1881 function d3_color() {}
1882 d3_color.prototype.toString = function() {
1883 return this.rgb() + "";
1884 };
1885 d3.hsl = d3_hsl;
1886 function d3_hsl(h, s, l) {
1887 return this instanceof d3_hsl ? void (this.h = +h, this.s = +s, this.l = +l) : arguments.length < 2 ? h instanceof d3_hsl ? new d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : new d3_hsl(h, s, l);
1888 }
1889 var d3_hslPrototype = d3_hsl.prototype = new d3_color();
1890 d3_hslPrototype.brighter = function(k) {
1891 k = Math.pow(.7, arguments.length ? k : 1);
1892 return new d3_hsl(this.h, this.s, this.l / k);
1893 };
1894 d3_hslPrototype.darker = function(k) {
1895 k = Math.pow(.7, arguments.length ? k : 1);
1896 return new d3_hsl(this.h, this.s, k * this.l);
1897 };
1898 d3_hslPrototype.rgb = function() {
1899 return d3_hsl_rgb(this.h, this.s, this.l);
1900 };
1901 function d3_hsl_rgb(h, s, l) {
1902 var m1, m2;
1903 h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h;
1904 s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s;
1905 l = l < 0 ? 0 : l > 1 ? 1 : l;
1906 m2 = l <= .5 ? l * (1 + s) : l + s - l * s;
1907 m1 = 2 * l - m2;
1908 function v(h) {
1909 if (h > 360) h -= 360; else if (h < 0) h += 360;
1910 if (h < 60) return m1 + (m2 - m1) * h / 60;
1911 if (h < 180) return m2;
1912 if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60;
1913 return m1;
1914 }
1915 function vv(h) {
1916 return Math.round(v(h) * 255);
1917 }
1918 return new d3_rgb(vv(h + 120), vv(h), vv(h - 120));
1919 }
1920 d3.hcl = d3_hcl;
1921 function d3_hcl(h, c, l) {
1922 return this instanceof d3_hcl ? void (this.h = +h, this.c = +c, this.l = +l) : arguments.length < 2 ? h instanceof d3_hcl ? new d3_hcl(h.h, h.c, h.l) : h instanceof d3_lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : new d3_hcl(h, c, l);
1923 }
1924 var d3_hclPrototype = d3_hcl.prototype = new d3_color();
1925 d3_hclPrototype.brighter = function(k) {
1926 return new d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)));
1927 };
1928 d3_hclPrototype.darker = function(k) {
1929 return new d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)));
1930 };
1931 d3_hclPrototype.rgb = function() {
1932 return d3_hcl_lab(this.h, this.c, this.l).rgb();
1933 };
1934 function d3_hcl_lab(h, c, l) {
1935 if (isNaN(h)) h = 0;
1936 if (isNaN(c)) c = 0;
1937 return new d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c);
1938 }
1939 d3.lab = d3_lab;
1940 function d3_lab(l, a, b) {
1941 return this instanceof d3_lab ? void (this.l = +l, this.a = +a, this.b = +b) : arguments.length < 2 ? l instanceof d3_lab ? new d3_lab(l.l, l.a, l.b) : l instanceof d3_hcl ? d3_hcl_lab(l.h, l.c, l.l) : d3_rgb_lab((l = d3_rgb(l)).r, l.g, l.b) : new d3_lab(l, a, b);
1942 }
1943 var d3_lab_K = 18;
1944 var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883;
1945 var d3_labPrototype = d3_lab.prototype = new d3_color();
1946 d3_labPrototype.brighter = function(k) {
1947 return new d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
1948 };
1949 d3_labPrototype.darker = function(k) {
1950 return new d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
1951 };
1952 d3_labPrototype.rgb = function() {
1953 return d3_lab_rgb(this.l, this.a, this.b);
1954 };
1955 function d3_lab_rgb(l, a, b) {
1956 var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200;
1957 x = d3_lab_xyz(x) * d3_lab_X;
1958 y = d3_lab_xyz(y) * d3_lab_Y;
1959 z = d3_lab_xyz(z) * d3_lab_Z;
1960 return new d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z));
1961 }
1962 function d3_lab_hcl(l, a, b) {
1963 return l > 0 ? new d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l) : new d3_hcl(NaN, NaN, l);
1964 }
1965 function d3_lab_xyz(x) {
1966 return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
1967 }
1968 function d3_xyz_lab(x) {
1969 return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
1970 }
1971 function d3_xyz_rgb(r) {
1972 return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055));
1973 }
1974 d3.rgb = d3_rgb;
1975 function d3_rgb(r, g, b) {
1976 return this instanceof d3_rgb ? void (this.r = ~~r, this.g = ~~g, this.b = ~~b) : arguments.length < 2 ? r instanceof d3_rgb ? new d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : new d3_rgb(r, g, b);
1977 }
1978 function d3_rgbNumber(value) {
1979 return new d3_rgb(value >> 16, value >> 8 & 255, value & 255);
1980 }
1981 function d3_rgbString(value) {
1982 return d3_rgbNumber(value) + "";
1983 }
1984 var d3_rgbPrototype = d3_rgb.prototype = new d3_color();
1985 d3_rgbPrototype.brighter = function(k) {
1986 k = Math.pow(.7, arguments.length ? k : 1);
1987 var r = this.r, g = this.g, b = this.b, i = 30;
1988 if (!r && !g && !b) return new d3_rgb(i, i, i);
1989 if (r && r < i) r = i;
1990 if (g && g < i) g = i;
1991 if (b && b < i) b = i;
1992 return new d3_rgb(Math.min(255, r / k), Math.min(255, g / k), Math.min(255, b / k));
1993 };
1994 d3_rgbPrototype.darker = function(k) {
1995 k = Math.pow(.7, arguments.length ? k : 1);
1996 return new d3_rgb(k * this.r, k * this.g, k * this.b);
1997 };
1998 d3_rgbPrototype.hsl = function() {
1999 return d3_rgb_hsl(this.r, this.g, this.b);
2000 };
2001 d3_rgbPrototype.toString = function() {
2002 return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b);
2003 };
2004 function d3_rgb_hex(v) {
2005 return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16);
2006 }
2007 function d3_rgb_parse(format, rgb, hsl) {
2008 var r = 0, g = 0, b = 0, m1, m2, color;
2009 m1 = /([a-z]+)\((.*)\)/i.exec(format);
2010 if (m1) {
2011 m2 = m1[2].split(",");
2012 switch (m1[1]) {
2013 case "hsl":
2014 {
2015 return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100);
2016 }
2017
2018 case "rgb":
2019 {
2020 return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2]));
2021 }
2022 }
2023 }
2024 if (color = d3_rgb_names.get(format)) return rgb(color.r, color.g, color.b);
2025 if (format != null && format.charAt(0) === "#" && !isNaN(color = parseInt(format.slice(1), 16))) {
2026 if (format.length === 4) {
2027 r = (color & 3840) >> 4;
2028 r = r >> 4 | r;
2029 g = color & 240;
2030 g = g >> 4 | g;
2031 b = color & 15;
2032 b = b << 4 | b;
2033 } else if (format.length === 7) {
2034 r = (color & 16711680) >> 16;
2035 g = (color & 65280) >> 8;
2036 b = color & 255;
2037 }
2038 }
2039 return rgb(r, g, b);
2040 }
2041 function d3_rgb_hsl(r, g, b) {
2042 var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2;
2043 if (d) {
2044 s = l < .5 ? d / (max + min) : d / (2 - max - min);
2045 if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4;
2046 h *= 60;
2047 } else {
2048 h = NaN;
2049 s = l > 0 && l < 1 ? 0 : h;
2050 }
2051 return new d3_hsl(h, s, l);
2052 }
2053 function d3_rgb_lab(r, g, b) {
2054 r = d3_rgb_xyz(r);
2055 g = d3_rgb_xyz(g);
2056 b = d3_rgb_xyz(b);
2057 var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z);
2058 return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z));
2059 }
2060 function d3_rgb_xyz(r) {
2061 return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4);
2062 }
2063 function d3_rgb_parseNumber(c) {
2064 var f = parseFloat(c);
2065 return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f;
2066 }
2067 var d3_rgb_names = d3.map({
2068 aliceblue: 15792383,
2069 antiquewhite: 16444375,
2070 aqua: 65535,
2071 aquamarine: 8388564,
2072 azure: 15794175,
2073 beige: 16119260,
2074 bisque: 16770244,
2075 black: 0,
2076 blanchedalmond: 16772045,
2077 blue: 255,
2078 blueviolet: 9055202,
2079 brown: 10824234,
2080 burlywood: 14596231,
2081 cadetblue: 6266528,
2082 chartreuse: 8388352,
2083 chocolate: 13789470,
2084 coral: 16744272,
2085 cornflowerblue: 6591981,
2086 cornsilk: 16775388,
2087 crimson: 14423100,
2088 cyan: 65535,
2089 darkblue: 139,
2090 darkcyan: 35723,
2091 darkgoldenrod: 12092939,
2092 darkgray: 11119017,
2093 darkgreen: 25600,
2094 darkgrey: 11119017,
2095 darkkhaki: 12433259,
2096 darkmagenta: 9109643,
2097 darkolivegreen: 5597999,
2098 darkorange: 16747520,
2099 darkorchid: 10040012,
2100 darkred: 9109504,
2101 darksalmon: 15308410,
2102 darkseagreen: 9419919,
2103 darkslateblue: 4734347,
2104 darkslategray: 3100495,
2105 darkslategrey: 3100495,
2106 darkturquoise: 52945,
2107 darkviolet: 9699539,
2108 deeppink: 16716947,
2109 deepskyblue: 49151,
2110 dimgray: 6908265,
2111 dimgrey: 6908265,
2112 dodgerblue: 2003199,
2113 firebrick: 11674146,
2114 floralwhite: 16775920,
2115 forestgreen: 2263842,
2116 fuchsia: 16711935,
2117 gainsboro: 14474460,
2118 ghostwhite: 16316671,
2119 gold: 16766720,
2120 goldenrod: 14329120,
2121 gray: 8421504,
2122 green: 32768,
2123 greenyellow: 11403055,
2124 grey: 8421504,
2125 honeydew: 15794160,
2126 hotpink: 16738740,
2127 indianred: 13458524,
2128 indigo: 4915330,
2129 ivory: 16777200,
2130 khaki: 15787660,
2131 lavender: 15132410,
2132 lavenderblush: 16773365,
2133 lawngreen: 8190976,
2134 lemonchiffon: 16775885,
2135 lightblue: 11393254,
2136 lightcoral: 15761536,
2137 lightcyan: 14745599,
2138 lightgoldenrodyellow: 16448210,
2139 lightgray: 13882323,
2140 lightgreen: 9498256,
2141 lightgrey: 13882323,
2142 lightpink: 16758465,
2143 lightsalmon: 16752762,
2144 lightseagreen: 2142890,
2145 lightskyblue: 8900346,
2146 lightslategray: 7833753,
2147 lightslategrey: 7833753,
2148 lightsteelblue: 11584734,
2149 lightyellow: 16777184,
2150 lime: 65280,
2151 limegreen: 3329330,
2152 linen: 16445670,
2153 magenta: 16711935,
2154 maroon: 8388608,
2155 mediumaquamarine: 6737322,
2156 mediumblue: 205,
2157 mediumorchid: 12211667,
2158 mediumpurple: 9662683,
2159 mediumseagreen: 3978097,
2160 mediumslateblue: 8087790,
2161 mediumspringgreen: 64154,
2162 mediumturquoise: 4772300,
2163 mediumvioletred: 13047173,
2164 midnightblue: 1644912,
2165 mintcream: 16121850,
2166 mistyrose: 16770273,
2167 moccasin: 16770229,
2168 navajowhite: 16768685,
2169 navy: 128,
2170 oldlace: 16643558,
2171 olive: 8421376,
2172 olivedrab: 7048739,
2173 orange: 16753920,
2174 orangered: 16729344,
2175 orchid: 14315734,
2176 palegoldenrod: 15657130,
2177 palegreen: 10025880,
2178 paleturquoise: 11529966,
2179 palevioletred: 14381203,
2180 papayawhip: 16773077,
2181 peachpuff: 16767673,
2182 peru: 13468991,
2183 pink: 16761035,
2184 plum: 14524637,
2185 powderblue: 11591910,
2186 purple: 8388736,
2187 red: 16711680,
2188 rosybrown: 12357519,
2189 royalblue: 4286945,
2190 saddlebrown: 9127187,
2191 salmon: 16416882,
2192 sandybrown: 16032864,
2193 seagreen: 3050327,
2194 seashell: 16774638,
2195 sienna: 10506797,
2196 silver: 12632256,
2197 skyblue: 8900331,
2198 slateblue: 6970061,
2199 slategray: 7372944,
2200 slategrey: 7372944,
2201 snow: 16775930,
2202 springgreen: 65407,
2203 steelblue: 4620980,
2204 tan: 13808780,
2205 teal: 32896,
2206 thistle: 14204888,
2207 tomato: 16737095,
2208 turquoise: 4251856,
2209 violet: 15631086,
2210 wheat: 16113331,
2211 white: 16777215,
2212 whitesmoke: 16119285,
2213 yellow: 16776960,
2214 yellowgreen: 10145074
2215 });
2216 d3_rgb_names.forEach(function(key, value) {
2217 d3_rgb_names.set(key, d3_rgbNumber(value));
2218 });
2219 function d3_functor(v) {
2220 return typeof v === "function" ? v : function() {
2221 return v;
2222 };
2223 }
2224 d3.functor = d3_functor;
2225 function d3_identity(d) {
2226 return d;
2227 }
2228 d3.xhr = d3_xhrType(d3_identity);
2229 function d3_xhrType(response) {
2230 return function(url, mimeType, callback) {
2231 if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType,
2232 mimeType = null;
2233 return d3_xhr(url, mimeType, response, callback);
2234 };
2235 }
2236 function d3_xhr(url, mimeType, response, callback) {
2237 var xhr = {}, dispatch = d3.dispatch("beforesend", "progress", "load", "error"), headers = {}, request = new XMLHttpRequest(), responseType = null;
2238 if (d3_window.XDomainRequest && !("withCredentials" in request) && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest();
2239 "onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() {
2240 request.readyState > 3 && respond();
2241 };
2242 function respond() {
2243 var status = request.status, result;
2244 if (!status && d3_xhrHasResponse(request) || status >= 200 && status < 300 || status === 304) {
2245 try {
2246 result = response.call(xhr, request);
2247 } catch (e) {
2248 dispatch.error.call(xhr, e);
2249 return;
2250 }
2251 dispatch.load.call(xhr, result);
2252 } else {
2253 dispatch.error.call(xhr, request);
2254 }
2255 }
2256 request.onprogress = function(event) {
2257 var o = d3.event;
2258 d3.event = event;
2259 try {
2260 dispatch.progress.call(xhr, request);
2261 } finally {
2262 d3.event = o;
2263 }
2264 };
2265 xhr.header = function(name, value) {
2266 name = (name + "").toLowerCase();
2267 if (arguments.length < 2) return headers[name];
2268 if (value == null) delete headers[name]; else headers[name] = value + "";
2269 return xhr;
2270 };
2271 xhr.mimeType = function(value) {
2272 if (!arguments.length) return mimeType;
2273 mimeType = value == null ? null : value + "";
2274 return xhr;
2275 };
2276 xhr.responseType = function(value) {
2277 if (!arguments.length) return responseType;
2278 responseType = value;
2279 return xhr;
2280 };
2281 xhr.response = function(value) {
2282 response = value;
2283 return xhr;
2284 };
2285 [ "get", "post" ].forEach(function(method) {
2286 xhr[method] = function() {
2287 return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments)));
2288 };
2289 });
2290 xhr.send = function(method, data, callback) {
2291 if (arguments.length === 2 && typeof data === "function") callback = data, data = null;
2292 request.open(method, url, true);
2293 if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*";
2294 if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]);
2295 if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType);
2296 if (responseType != null) request.responseType = responseType;
2297 if (callback != null) xhr.on("error", callback).on("load", function(request) {
2298 callback(null, request);
2299 });
2300 dispatch.beforesend.call(xhr, request);
2301 request.send(data == null ? null : data);
2302 return xhr;
2303 };
2304 xhr.abort = function() {
2305 request.abort();
2306 return xhr;
2307 };
2308 d3.rebind(xhr, dispatch, "on");
2309 return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback));
2310 }
2311 function d3_xhr_fixCallback(callback) {
2312 return callback.length === 1 ? function(error, request) {
2313 callback(error == null ? request : null);
2314 } : callback;
2315 }
2316 function d3_xhrHasResponse(request) {
2317 var type = request.responseType;
2318 return type && type !== "text" ? request.response : request.responseText;
2319 }
2320 d3.dsv = function(delimiter, mimeType) {
2321 var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0);
2322 function dsv(url, row, callback) {
2323 if (arguments.length < 3) callback = row, row = null;
2324 var xhr = d3_xhr(url, mimeType, row == null ? response : typedResponse(row), callback);
2325 xhr.row = function(_) {
2326 return arguments.length ? xhr.response((row = _) == null ? response : typedResponse(_)) : row;
2327 };
2328 return xhr;
2329 }
2330 function response(request) {
2331 return dsv.parse(request.responseText);
2332 }
2333 function typedResponse(f) {
2334 return function(request) {
2335 return dsv.parse(request.responseText, f);
2336 };
2337 }
2338 dsv.parse = function(text, f) {
2339 var o;
2340 return dsv.parseRows(text, function(row, i) {
2341 if (o) return o(row, i - 1);
2342 var a = new Function("d", "return {" + row.map(function(name, i) {
2343 return JSON.stringify(name) + ": d[" + i + "]";
2344 }).join(",") + "}");
2345 o = f ? function(row, i) {
2346 return f(a(row), i);
2347 } : a;
2348 });
2349 };
2350 dsv.parseRows = function(text, f) {
2351 var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol;
2352 function token() {
2353 if (I >= N) return EOF;
2354 if (eol) return eol = false, EOL;
2355 var j = I;
2356 if (text.charCodeAt(j) === 34) {
2357 var i = j;
2358 while (i++ < N) {
2359 if (text.charCodeAt(i) === 34) {
2360 if (text.charCodeAt(i + 1) !== 34) break;
2361 ++i;
2362 }
2363 }
2364 I = i + 2;
2365 var c = text.charCodeAt(i + 1);
2366 if (c === 13) {
2367 eol = true;
2368 if (text.charCodeAt(i + 2) === 10) ++I;
2369 } else if (c === 10) {
2370 eol = true;
2371 }
2372 return text.slice(j + 1, i).replace(/""/g, '"');
2373 }
2374 while (I < N) {
2375 var c = text.charCodeAt(I++), k = 1;
2376 if (c === 10) eol = true; else if (c === 13) {
2377 eol = true;
2378 if (text.charCodeAt(I) === 10) ++I, ++k;
2379 } else if (c !== delimiterCode) continue;
2380 return text.slice(j, I - k);
2381 }
2382 return text.slice(j);
2383 }
2384 while ((t = token()) !== EOF) {
2385 var a = [];
2386 while (t !== EOL && t !== EOF) {
2387 a.push(t);
2388 t = token();
2389 }
2390 if (f && (a = f(a, n++)) == null) continue;
2391 rows.push(a);
2392 }
2393 return rows;
2394 };
2395 dsv.format = function(rows) {
2396 if (Array.isArray(rows[0])) return dsv.formatRows(rows);
2397 var fieldSet = new d3_Set(), fields = [];
2398 rows.forEach(function(row) {
2399 for (var field in row) {
2400 if (!fieldSet.has(field)) {
2401 fields.push(fieldSet.add(field));
2402 }
2403 }
2404 });
2405 return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) {
2406 return fields.map(function(field) {
2407 return formatValue(row[field]);
2408 }).join(delimiter);
2409 })).join("\n");
2410 };
2411 dsv.formatRows = function(rows) {
2412 return rows.map(formatRow).join("\n");
2413 };
2414 function formatRow(row) {
2415 return row.map(formatValue).join(delimiter);
2416 }
2417 function formatValue(text) {
2418 return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text;
2419 }
2420 return dsv;
2421 };
2422 d3.csv = d3.dsv(",", "text/csv");
2423 d3.tsv = d3.dsv(" ", "text/tab-separated-values");
2424 var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_active, d3_timer_frame = d3_window[d3_vendorSymbol(d3_window, "requestAnimationFrame")] || function(callback) {
2425 setTimeout(callback, 17);
2426 };
2427 d3.timer = function(callback, delay, then) {
2428 var n = arguments.length;
2429 if (n < 2) delay = 0;
2430 if (n < 3) then = Date.now();
2431 var time = then + delay, timer = {
2432 c: callback,
2433 t: time,
2434 f: false,
2435 n: null
2436 };
2437 if (d3_timer_queueTail) d3_timer_queueTail.n = timer; else d3_timer_queueHead = timer;
2438 d3_timer_queueTail = timer;
2439 if (!d3_timer_interval) {
2440 d3_timer_timeout = clearTimeout(d3_timer_timeout);
2441 d3_timer_interval = 1;
2442 d3_timer_frame(d3_timer_step);
2443 }
2444 };
2445 function d3_timer_step() {
2446 var now = d3_timer_mark(), delay = d3_timer_sweep() - now;
2447 if (delay > 24) {
2448 if (isFinite(delay)) {
2449 clearTimeout(d3_timer_timeout);
2450 d3_timer_timeout = setTimeout(d3_timer_step, delay);
2451 }
2452 d3_timer_interval = 0;
2453 } else {
2454 d3_timer_interval = 1;
2455 d3_timer_frame(d3_timer_step);
2456 }
2457 }
2458 d3.timer.flush = function() {
2459 d3_timer_mark();
2460 d3_timer_sweep();
2461 };
2462 function d3_timer_mark() {
2463 var now = Date.now();
2464 d3_timer_active = d3_timer_queueHead;
2465 while (d3_timer_active) {
2466 if (now >= d3_timer_active.t) d3_timer_active.f = d3_timer_active.c(now - d3_timer_active.t);
2467 d3_timer_active = d3_timer_active.n;
2468 }
2469 return now;
2470 }
2471 function d3_timer_sweep() {
2472 var t0, t1 = d3_timer_queueHead, time = Infinity;
2473 while (t1) {
2474 if (t1.f) {
2475 t1 = t0 ? t0.n = t1.n : d3_timer_queueHead = t1.n;
2476 } else {
2477 if (t1.t < time) time = t1.t;
2478 t1 = (t0 = t1).n;
2479 }
2480 }
2481 d3_timer_queueTail = t0;
2482 return time;
2483 }
2484 function d3_format_precision(x, p) {
2485 return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1);
2486 }
2487 d3.round = function(x, n) {
2488 return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x);
2489 };
2490 var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix);
2491 d3.formatPrefix = function(value, precision) {
2492 var i = 0;
2493 if (value) {
2494 if (value < 0) value *= -1;
2495 if (precision) value = d3.round(value, d3_format_precision(value, precision));
2496 i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10);
2497 i = Math.max(-24, Math.min(24, Math.floor((i - 1) / 3) * 3));
2498 }
2499 return d3_formatPrefixes[8 + i / 3];
2500 };
2501 function d3_formatPrefix(d, i) {
2502 var k = Math.pow(10, abs(8 - i) * 3);
2503 return {
2504 scale: i > 8 ? function(d) {
2505 return d / k;
2506 } : function(d) {
2507 return d * k;
2508 },
2509 symbol: d
2510 };
2511 }
2512 function d3_locale_numberFormat(locale) {
2513 var locale_decimal = locale.decimal, locale_thousands = locale.thousands, locale_grouping = locale.grouping, locale_currency = locale.currency, formatGroup = locale_grouping && locale_thousands ? function(value, width) {
2514 var i = value.length, t = [], j = 0, g = locale_grouping[0], length = 0;
2515 while (i > 0 && g > 0) {
2516 if (length + g + 1 > width) g = Math.max(1, width - length);
2517 t.push(value.substring(i -= g, i + g));
2518 if ((length += g + 1) > width) break;
2519 g = locale_grouping[j = (j + 1) % locale_grouping.length];
2520 }
2521 return t.reverse().join(locale_thousands);
2522 } : d3_identity;
2523 return function(specifier) {
2524 var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "-", symbol = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, prefix = "", suffix = "", integer = false, exponent = true;
2525 if (precision) precision = +precision.substring(1);
2526 if (zfill || fill === "0" && align === "=") {
2527 zfill = fill = "0";
2528 align = "=";
2529 }
2530 switch (type) {
2531 case "n":
2532 comma = true;
2533 type = "g";
2534 break;
2535
2536 case "%":
2537 scale = 100;
2538 suffix = "%";
2539 type = "f";
2540 break;
2541
2542 case "p":
2543 scale = 100;
2544 suffix = "%";
2545 type = "r";
2546 break;
2547
2548 case "b":
2549 case "o":
2550 case "x":
2551 case "X":
2552 if (symbol === "#") prefix = "0" + type.toLowerCase();
2553
2554 case "c":
2555 exponent = false;
2556
2557 case "d":
2558 integer = true;
2559 precision = 0;
2560 break;
2561
2562 case "s":
2563 scale = -1;
2564 type = "r";
2565 break;
2566 }
2567 if (symbol === "$") prefix = locale_currency[0], suffix = locale_currency[1];
2568 if (type == "r" && !precision) type = "g";
2569 if (precision != null) {
2570 if (type == "g") precision = Math.max(1, Math.min(21, precision)); else if (type == "e" || type == "f") precision = Math.max(0, Math.min(20, precision));
2571 }
2572 type = d3_format_types.get(type) || d3_format_typeDefault;
2573 var zcomma = zfill && comma;
2574 return function(value) {
2575 var fullSuffix = suffix;
2576 if (integer && value % 1) return "";
2577 var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign === "-" ? "" : sign;
2578 if (scale < 0) {
2579 var unit = d3.formatPrefix(value, precision);
2580 value = unit.scale(value);
2581 fullSuffix = unit.symbol + suffix;
2582 } else {
2583 value *= scale;
2584 }
2585 value = type(value, precision);
2586 var i = value.lastIndexOf("."), before, after;
2587 if (i < 0) {
2588 var j = exponent ? value.lastIndexOf("e") : -1;
2589 if (j < 0) before = value, after = ""; else before = value.substring(0, j), after = value.substring(j);
2590 } else {
2591 before = value.substring(0, i);
2592 after = locale_decimal + value.substring(i + 1);
2593 }
2594 if (!zfill && comma) before = formatGroup(before, Infinity);
2595 var length = prefix.length + before.length + after.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : "";
2596 if (zcomma) before = formatGroup(padding + before, padding.length ? width - after.length : Infinity);
2597 negative += prefix;
2598 value = before + after;
2599 return (align === "<" ? negative + value + padding : align === ">" ? padding + negative + value : align === "^" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length) : negative + (zcomma ? value : padding + value)) + fullSuffix;
2600 };
2601 };
2602 }
2603 var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i;
2604 var d3_format_types = d3.map({
2605 b: function(x) {
2606 return x.toString(2);
2607 },
2608 c: function(x) {
2609 return String.fromCharCode(x);
2610 },
2611 o: function(x) {
2612 return x.toString(8);
2613 },
2614 x: function(x) {
2615 return x.toString(16);
2616 },
2617 X: function(x) {
2618 return x.toString(16).toUpperCase();
2619 },
2620 g: function(x, p) {
2621 return x.toPrecision(p);
2622 },
2623 e: function(x, p) {
2624 return x.toExponential(p);
2625 },
2626 f: function(x, p) {
2627 return x.toFixed(p);
2628 },
2629 r: function(x, p) {
2630 return (x = d3.round(x, d3_format_precision(x, p))).toFixed(Math.max(0, Math.min(20, d3_format_precision(x * (1 + 1e-15), p))));
2631 }
2632 });
2633 function d3_format_typeDefault(x) {
2634 return x + "";
2635 }
2636 var d3_time = d3.time = {}, d3_date = Date;
2637 function d3_date_utc() {
2638 this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]);
2639 }
2640 d3_date_utc.prototype = {
2641 getDate: function() {
2642 return this._.getUTCDate();
2643 },
2644 getDay: function() {
2645 return this._.getUTCDay();
2646 },
2647 getFullYear: function() {
2648 return this._.getUTCFullYear();
2649 },
2650 getHours: function() {
2651 return this._.getUTCHours();
2652 },
2653 getMilliseconds: function() {
2654 return this._.getUTCMilliseconds();
2655 },
2656 getMinutes: function() {
2657 return this._.getUTCMinutes();
2658 },
2659 getMonth: function() {
2660 return this._.getUTCMonth();
2661 },
2662 getSeconds: function() {
2663 return this._.getUTCSeconds();
2664 },
2665 getTime: function() {
2666 return this._.getTime();
2667 },
2668 getTimezoneOffset: function() {
2669 return 0;
2670 },
2671 valueOf: function() {
2672 return this._.valueOf();
2673 },
2674 setDate: function() {
2675 d3_time_prototype.setUTCDate.apply(this._, arguments);
2676 },
2677 setDay: function() {
2678 d3_time_prototype.setUTCDay.apply(this._, arguments);
2679 },
2680 setFullYear: function() {
2681 d3_time_prototype.setUTCFullYear.apply(this._, arguments);
2682 },
2683 setHours: function() {
2684 d3_time_prototype.setUTCHours.apply(this._, arguments);
2685 },
2686 setMilliseconds: function() {
2687 d3_time_prototype.setUTCMilliseconds.apply(this._, arguments);
2688 },
2689 setMinutes: function() {
2690 d3_time_prototype.setUTCMinutes.apply(this._, arguments);
2691 },
2692 setMonth: function() {
2693 d3_time_prototype.setUTCMonth.apply(this._, arguments);
2694 },
2695 setSeconds: function() {
2696 d3_time_prototype.setUTCSeconds.apply(this._, arguments);
2697 },
2698 setTime: function() {
2699 d3_time_prototype.setTime.apply(this._, arguments);
2700 }
2701 };
2702 var d3_time_prototype = Date.prototype;
2703 function d3_time_interval(local, step, number) {
2704 function round(date) {
2705 var d0 = local(date), d1 = offset(d0, 1);
2706 return date - d0 < d1 - date ? d0 : d1;
2707 }
2708 function ceil(date) {
2709 step(date = local(new d3_date(date - 1)), 1);
2710 return date;
2711 }
2712 function offset(date, k) {
2713 step(date = new d3_date(+date), k);
2714 return date;
2715 }
2716 function range(t0, t1, dt) {
2717 var time = ceil(t0), times = [];
2718 if (dt > 1) {
2719 while (time < t1) {
2720 if (!(number(time) % dt)) times.push(new Date(+time));
2721 step(time, 1);
2722 }
2723 } else {
2724 while (time < t1) times.push(new Date(+time)), step(time, 1);
2725 }
2726 return times;
2727 }
2728 function range_utc(t0, t1, dt) {
2729 try {
2730 d3_date = d3_date_utc;
2731 var utc = new d3_date_utc();
2732 utc._ = t0;
2733 return range(utc, t1, dt);
2734 } finally {
2735 d3_date = Date;
2736 }
2737 }
2738 local.floor = local;
2739 local.round = round;
2740 local.ceil = ceil;
2741 local.offset = offset;
2742 local.range = range;
2743 var utc = local.utc = d3_time_interval_utc(local);
2744 utc.floor = utc;
2745 utc.round = d3_time_interval_utc(round);
2746 utc.ceil = d3_time_interval_utc(ceil);
2747 utc.offset = d3_time_interval_utc(offset);
2748 utc.range = range_utc;
2749 return local;
2750 }
2751 function d3_time_interval_utc(method) {
2752 return function(date, k) {
2753 try {
2754 d3_date = d3_date_utc;
2755 var utc = new d3_date_utc();
2756 utc._ = date;
2757 return method(utc, k)._;
2758 } finally {
2759 d3_date = Date;
2760 }
2761 };
2762 }
2763 d3_time.year = d3_time_interval(function(date) {
2764 date = d3_time.day(date);
2765 date.setMonth(0, 1);
2766 return date;
2767 }, function(date, offset) {
2768 date.setFullYear(date.getFullYear() + offset);
2769 }, function(date) {
2770 return date.getFullYear();
2771 });
2772 d3_time.years = d3_time.year.range;
2773 d3_time.years.utc = d3_time.year.utc.range;
2774 d3_time.day = d3_time_interval(function(date) {
2775 var day = new d3_date(2e3, 0);
2776 day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());
2777 return day;
2778 }, function(date, offset) {
2779 date.setDate(date.getDate() + offset);
2780 }, function(date) {
2781 return date.getDate() - 1;
2782 });
2783 d3_time.days = d3_time.day.range;
2784 d3_time.days.utc = d3_time.day.utc.range;
2785 d3_time.dayOfYear = function(date) {
2786 var year = d3_time.year(date);
2787 return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5);
2788 };
2789 [ "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" ].forEach(function(day, i) {
2790 i = 7 - i;
2791 var interval = d3_time[day] = d3_time_interval(function(date) {
2792 (date = d3_time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7);
2793 return date;
2794 }, function(date, offset) {
2795 date.setDate(date.getDate() + Math.floor(offset) * 7);
2796 }, function(date) {
2797 var day = d3_time.year(date).getDay();
2798 return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i);
2799 });
2800 d3_time[day + "s"] = interval.range;
2801 d3_time[day + "s"].utc = interval.utc.range;
2802 d3_time[day + "OfYear"] = function(date) {
2803 var day = d3_time.year(date).getDay();
2804 return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7);
2805 };
2806 });
2807 d3_time.week = d3_time.sunday;
2808 d3_time.weeks = d3_time.sunday.range;
2809 d3_time.weeks.utc = d3_time.sunday.utc.range;
2810 d3_time.weekOfYear = d3_time.sundayOfYear;
2811 function d3_locale_timeFormat(locale) {
2812 var locale_dateTime = locale.dateTime, locale_date = locale.date, locale_time = locale.time, locale_periods = locale.periods, locale_days = locale.days, locale_shortDays = locale.shortDays, locale_months = locale.months, locale_shortMonths = locale.shortMonths;
2813 function d3_time_format(template) {
2814 var n = template.length;
2815 function format(date) {
2816 var string = [], i = -1, j = 0, c, p, f;
2817 while (++i < n) {
2818 if (template.charCodeAt(i) === 37) {
2819 string.push(template.slice(j, i));
2820 if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i);
2821 if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ? " " : "0" : p);
2822 string.push(c);
2823 j = i + 1;
2824 }
2825 }
2826 string.push(template.slice(j, i));
2827 return string.join("");
2828 }
2829 format.parse = function(string) {
2830 var d = {
2831 y: 1900,
2832 m: 0,
2833 d: 1,
2834 H: 0,
2835 M: 0,
2836 S: 0,
2837 L: 0,
2838 Z: null
2839 }, i = d3_time_parse(d, template, string, 0);
2840 if (i != string.length) return null;
2841 if ("p" in d) d.H = d.H % 12 + d.p * 12;
2842 var localZ = d.Z != null && d3_date !== d3_date_utc, date = new (localZ ? d3_date_utc : d3_date)();
2843 if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("w" in d && ("W" in d || "U" in d)) {
2844 date.setFullYear(d.y, 0, 1);
2845 date.setFullYear(d.y, 0, "W" in d ? (d.w + 6) % 7 + d.W * 7 - (date.getDay() + 5) % 7 : d.w + d.U * 7 - (date.getDay() + 6) % 7);
2846 } else date.setFullYear(d.y, d.m, d.d);
2847 date.setHours(d.H + (d.Z / 100 | 0), d.M + d.Z % 100, d.S, d.L);
2848 return localZ ? date._ : date;
2849 };
2850 format.toString = function() {
2851 return template;
2852 };
2853 return format;
2854 }
2855 function d3_time_parse(date, template, string, j) {
2856 var c, p, t, i = 0, n = template.length, m = string.length;
2857 while (i < n) {
2858 if (j >= m) return -1;
2859 c = template.charCodeAt(i++);
2860 if (c === 37) {
2861 t = template.charAt(i++);
2862 p = d3_time_parsers[t in d3_time_formatPads ? template.charAt(i++) : t];
2863 if (!p || (j = p(date, string, j)) < 0) return -1;
2864 } else if (c != string.charCodeAt(j++)) {
2865 return -1;
2866 }
2867 }
2868 return j;
2869 }
2870 d3_time_format.utc = function(template) {
2871 var local = d3_time_format(template);
2872 function format(date) {
2873 try {
2874 d3_date = d3_date_utc;
2875 var utc = new d3_date();
2876 utc._ = date;
2877 return local(utc);
2878 } finally {
2879 d3_date = Date;
2880 }
2881 }
2882 format.parse = function(string) {
2883 try {
2884 d3_date = d3_date_utc;
2885 var date = local.parse(string);
2886 return date && date._;
2887 } finally {
2888 d3_date = Date;
2889 }
2890 };
2891 format.toString = local.toString;
2892 return format;
2893 };
2894 d3_time_format.multi = d3_time_format.utc.multi = d3_time_formatMulti;
2895 var d3_time_periodLookup = d3.map(), d3_time_dayRe = d3_time_formatRe(locale_days), d3_time_dayLookup = d3_time_formatLookup(locale_days), d3_time_dayAbbrevRe = d3_time_formatRe(locale_shortDays), d3_time_dayAbbrevLookup = d3_time_formatLookup(locale_shortDays), d3_time_monthRe = d3_time_formatRe(locale_months), d3_time_monthLookup = d3_time_formatLookup(locale_months), d3_time_monthAbbrevRe = d3_time_formatRe(locale_shortMonths), d3_time_monthAbbrevLookup = d3_time_formatLookup(locale_shortMonths);
2896 locale_periods.forEach(function(p, i) {
2897 d3_time_periodLookup.set(p.toLowerCase(), i);
2898 });
2899 var d3_time_formats = {
2900 a: function(d) {
2901 return locale_shortDays[d.getDay()];
2902 },
2903 A: function(d) {
2904 return locale_days[d.getDay()];
2905 },
2906 b: function(d) {
2907 return locale_shortMonths[d.getMonth()];
2908 },
2909 B: function(d) {
2910 return locale_months[d.getMonth()];
2911 },
2912 c: d3_time_format(locale_dateTime),
2913 d: function(d, p) {
2914 return d3_time_formatPad(d.getDate(), p, 2);
2915 },
2916 e: function(d, p) {
2917 return d3_time_formatPad(d.getDate(), p, 2);
2918 },
2919 H: function(d, p) {
2920 return d3_time_formatPad(d.getHours(), p, 2);
2921 },
2922 I: function(d, p) {
2923 return d3_time_formatPad(d.getHours() % 12 || 12, p, 2);
2924 },
2925 j: function(d, p) {
2926 return d3_time_formatPad(1 + d3_time.dayOfYear(d), p, 3);
2927 },
2928 L: function(d, p) {
2929 return d3_time_formatPad(d.getMilliseconds(), p, 3);
2930 },
2931 m: function(d, p) {
2932 return d3_time_formatPad(d.getMonth() + 1, p, 2);
2933 },
2934 M: function(d, p) {
2935 return d3_time_formatPad(d.getMinutes(), p, 2);
2936 },
2937 p: function(d) {
2938 return locale_periods[+(d.getHours() >= 12)];
2939 },
2940 S: function(d, p) {
2941 return d3_time_formatPad(d.getSeconds(), p, 2);
2942 },
2943 U: function(d, p) {
2944 return d3_time_formatPad(d3_time.sundayOfYear(d), p, 2);
2945 },
2946 w: function(d) {
2947 return d.getDay();
2948 },
2949 W: function(d, p) {
2950 return d3_time_formatPad(d3_time.mondayOfYear(d), p, 2);
2951 },
2952 x: d3_time_format(locale_date),
2953 X: d3_time_format(locale_time),
2954 y: function(d, p) {
2955 return d3_time_formatPad(d.getFullYear() % 100, p, 2);
2956 },
2957 Y: function(d, p) {
2958 return d3_time_formatPad(d.getFullYear() % 1e4, p, 4);
2959 },
2960 Z: d3_time_zone,
2961 "%": function() {
2962 return "%";
2963 }
2964 };
2965 var d3_time_parsers = {
2966 a: d3_time_parseWeekdayAbbrev,
2967 A: d3_time_parseWeekday,
2968 b: d3_time_parseMonthAbbrev,
2969 B: d3_time_parseMonth,
2970 c: d3_time_parseLocaleFull,
2971 d: d3_time_parseDay,
2972 e: d3_time_parseDay,
2973 H: d3_time_parseHour24,
2974 I: d3_time_parseHour24,
2975 j: d3_time_parseDayOfYear,
2976 L: d3_time_parseMilliseconds,
2977 m: d3_time_parseMonthNumber,
2978 M: d3_time_parseMinutes,
2979 p: d3_time_parseAmPm,
2980 S: d3_time_parseSeconds,
2981 U: d3_time_parseWeekNumberSunday,
2982 w: d3_time_parseWeekdayNumber,
2983 W: d3_time_parseWeekNumberMonday,
2984 x: d3_time_parseLocaleDate,
2985 X: d3_time_parseLocaleTime,
2986 y: d3_time_parseYear,
2987 Y: d3_time_parseFullYear,
2988 Z: d3_time_parseZone,
2989 "%": d3_time_parseLiteralPercent
2990 };
2991 function d3_time_parseWeekdayAbbrev(date, string, i) {
2992 d3_time_dayAbbrevRe.lastIndex = 0;
2993 var n = d3_time_dayAbbrevRe.exec(string.slice(i));
2994 return n ? (date.w = d3_time_dayAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
2995 }
2996 function d3_time_parseWeekday(date, string, i) {
2997 d3_time_dayRe.lastIndex = 0;
2998 var n = d3_time_dayRe.exec(string.slice(i));
2999 return n ? (date.w = d3_time_dayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
3000 }
3001 function d3_time_parseMonthAbbrev(date, string, i) {
3002 d3_time_monthAbbrevRe.lastIndex = 0;
3003 var n = d3_time_monthAbbrevRe.exec(string.slice(i));
3004 return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
3005 }
3006 function d3_time_parseMonth(date, string, i) {
3007 d3_time_monthRe.lastIndex = 0;
3008 var n = d3_time_monthRe.exec(string.slice(i));
3009 return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
3010 }
3011 function d3_time_parseLocaleFull(date, string, i) {
3012 return d3_time_parse(date, d3_time_formats.c.toString(), string, i);
3013 }
3014 function d3_time_parseLocaleDate(date, string, i) {
3015 return d3_time_parse(date, d3_time_formats.x.toString(), string, i);
3016 }
3017 function d3_time_parseLocaleTime(date, string, i) {
3018 return d3_time_parse(date, d3_time_formats.X.toString(), string, i);
3019 }
3020 function d3_time_parseAmPm(date, string, i) {
3021 var n = d3_time_periodLookup.get(string.slice(i, i += 2).toLowerCase());
3022 return n == null ? -1 : (date.p = n, i);
3023 }
3024 return d3_time_format;
3025 }
3026 var d3_time_formatPads = {
3027 "-": "",
3028 _: " ",
3029 "0": "0"
3030 }, d3_time_numberRe = /^\s*\d+/, d3_time_percentRe = /^%/;
3031 function d3_time_formatPad(value, fill, width) {
3032 var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length;
3033 return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);
3034 }
3035 function d3_time_formatRe(names) {
3036 return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i");
3037 }
3038 function d3_time_formatLookup(names) {
3039 var map = new d3_Map(), i = -1, n = names.length;
3040 while (++i < n) map.set(names[i].toLowerCase(), i);
3041 return map;
3042 }
3043 function d3_time_parseWeekdayNumber(date, string, i) {
3044 d3_time_numberRe.lastIndex = 0;
3045 var n = d3_time_numberRe.exec(string.slice(i, i + 1));
3046 return n ? (date.w = +n[0], i + n[0].length) : -1;
3047 }
3048 function d3_time_parseWeekNumberSunday(date, string, i) {
3049 d3_time_numberRe.lastIndex = 0;
3050 var n = d3_time_numberRe.exec(string.slice(i));
3051 return n ? (date.U = +n[0], i + n[0].length) : -1;
3052 }
3053 function d3_time_parseWeekNumberMonday(date, string, i) {
3054 d3_time_numberRe.lastIndex = 0;
3055 var n = d3_time_numberRe.exec(string.slice(i));
3056 return n ? (date.W = +n[0], i + n[0].length) : -1;
3057 }
3058 function d3_time_parseFullYear(date, string, i) {
3059 d3_time_numberRe.lastIndex = 0;
3060 var n = d3_time_numberRe.exec(string.slice(i, i + 4));
3061 return n ? (date.y = +n[0], i + n[0].length) : -1;
3062 }
3063 function d3_time_parseYear(date, string, i) {
3064 d3_time_numberRe.lastIndex = 0;
3065 var n = d3_time_numberRe.exec(string.slice(i, i + 2));
3066 return n ? (date.y = d3_time_expandYear(+n[0]), i + n[0].length) : -1;
3067 }
3068 function d3_time_parseZone(date, string, i) {
3069 return /^[+-]\d{4}$/.test(string = string.slice(i, i + 5)) ? (date.Z = -string,
3070 i + 5) : -1;
3071 }
3072 function d3_time_expandYear(d) {
3073 return d + (d > 68 ? 1900 : 2e3);
3074 }
3075 function d3_time_parseMonthNumber(date, string, i) {
3076 d3_time_numberRe.lastIndex = 0;
3077 var n = d3_time_numberRe.exec(string.slice(i, i + 2));
3078 return n ? (date.m = n[0] - 1, i + n[0].length) : -1;
3079 }
3080 function d3_time_parseDay(date, string, i) {
3081 d3_time_numberRe.lastIndex = 0;
3082 var n = d3_time_numberRe.exec(string.slice(i, i + 2));
3083 return n ? (date.d = +n[0], i + n[0].length) : -1;
3084 }
3085 function d3_time_parseDayOfYear(date, string, i) {
3086 d3_time_numberRe.lastIndex = 0;
3087 var n = d3_time_numberRe.exec(string.slice(i, i + 3));
3088 return n ? (date.j = +n[0], i + n[0].length) : -1;
3089 }
3090 function d3_time_parseHour24(date, string, i) {
3091 d3_time_numberRe.lastIndex = 0;
3092 var n = d3_time_numberRe.exec(string.slice(i, i + 2));
3093 return n ? (date.H = +n[0], i + n[0].length) : -1;
3094 }
3095 function d3_time_parseMinutes(date, string, i) {
3096 d3_time_numberRe.lastIndex = 0;
3097 var n = d3_time_numberRe.exec(string.slice(i, i + 2));
3098 return n ? (date.M = +n[0], i + n[0].length) : -1;
3099 }
3100 function d3_time_parseSeconds(date, string, i) {
3101 d3_time_numberRe.lastIndex = 0;
3102 var n = d3_time_numberRe.exec(string.slice(i, i + 2));
3103 return n ? (date.S = +n[0], i + n[0].length) : -1;
3104 }
3105 function d3_time_parseMilliseconds(date, string, i) {
3106 d3_time_numberRe.lastIndex = 0;
3107 var n = d3_time_numberRe.exec(string.slice(i, i + 3));
3108 return n ? (date.L = +n[0], i + n[0].length) : -1;
3109 }
3110 function d3_time_zone(d) {
3111 var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = abs(z) / 60 | 0, zm = abs(z) % 60;
3112 return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2);
3113 }
3114 function d3_time_parseLiteralPercent(date, string, i) {
3115 d3_time_percentRe.lastIndex = 0;
3116 var n = d3_time_percentRe.exec(string.slice(i, i + 1));
3117 return n ? i + n[0].length : -1;
3118 }
3119 function d3_time_formatMulti(formats) {
3120 var n = formats.length, i = -1;
3121 while (++i < n) formats[i][0] = this(formats[i][0]);
3122 return function(date) {
3123 var i = 0, f = formats[i];
3124 while (!f[1](date)) f = formats[++i];
3125 return f[0](date);
3126 };
3127 }
3128 d3.locale = function(locale) {
3129 return {
3130 numberFormat: d3_locale_numberFormat(locale),
3131 timeFormat: d3_locale_timeFormat(locale)
3132 };
3133 };
3134 var d3_locale_enUS = d3.locale({
3135 decimal: ".",
3136 thousands: ",",
3137 grouping: [ 3 ],
3138 currency: [ "$", "" ],
3139 dateTime: "%a %b %e %X %Y",
3140 date: "%m/%d/%Y",
3141 time: "%H:%M:%S",
3142 periods: [ "AM", "PM" ],
3143 days: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ],
3144 shortDays: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ],
3145 months: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ],
3146 shortMonths: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]
3147 });
3148 d3.format = d3_locale_enUS.numberFormat;
3149 d3.geo = {};
3150 function d3_adder() {}
3151 d3_adder.prototype = {
3152 s: 0,
3153 t: 0,
3154 add: function(y) {
3155 d3_adderSum(y, this.t, d3_adderTemp);
3156 d3_adderSum(d3_adderTemp.s, this.s, this);
3157 if (this.s) this.t += d3_adderTemp.t; else this.s = d3_adderTemp.t;
3158 },
3159 reset: function() {
3160 this.s = this.t = 0;
3161 },
3162 valueOf: function() {
3163 return this.s;
3164 }
3165 };
3166 var d3_adderTemp = new d3_adder();
3167 function d3_adderSum(a, b, o) {
3168 var x = o.s = a + b, bv = x - a, av = x - bv;
3169 o.t = a - av + (b - bv);
3170 }
3171 d3.geo.stream = function(object, listener) {
3172 if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) {
3173 d3_geo_streamObjectType[object.type](object, listener);
3174 } else {
3175 d3_geo_streamGeometry(object, listener);
3176 }
3177 };
3178 function d3_geo_streamGeometry(geometry, listener) {
3179 if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) {
3180 d3_geo_streamGeometryType[geometry.type](geometry, listener);
3181 }
3182 }
3183 var d3_geo_streamObjectType = {
3184 Feature: function(feature, listener) {
3185 d3_geo_streamGeometry(feature.geometry, listener);
3186 },
3187 FeatureCollection: function(object, listener) {
3188 var features = object.features, i = -1, n = features.length;
3189 while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener);
3190 }
3191 };
3192 var d3_geo_streamGeometryType = {
3193 Sphere: function(object, listener) {
3194 listener.sphere();
3195 },
3196 Point: function(object, listener) {
3197 object = object.coordinates;
3198 listener.point(object[0], object[1], object[2]);
3199 },
3200 MultiPoint: function(object, listener) {
3201 var coordinates = object.coordinates, i = -1, n = coordinates.length;
3202 while (++i < n) object = coordinates[i], listener.point(object[0], object[1], object[2]);
3203 },
3204 LineString: function(object, listener) {
3205 d3_geo_streamLine(object.coordinates, listener, 0);
3206 },
3207 MultiLineString: function(object, listener) {
3208 var coordinates = object.coordinates, i = -1, n = coordinates.length;
3209 while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0);
3210 },
3211 Polygon: function(object, listener) {
3212 d3_geo_streamPolygon(object.coordinates, listener);
3213 },
3214 MultiPolygon: function(object, listener) {
3215 var coordinates = object.coordinates, i = -1, n = coordinates.length;
3216 while (++i < n) d3_geo_streamPolygon(coordinates[i], listener);
3217 },
3218 GeometryCollection: function(object, listener) {
3219 var geometries = object.geometries, i = -1, n = geometries.length;
3220 while (++i < n) d3_geo_streamGeometry(geometries[i], listener);
3221 }
3222 };
3223 function d3_geo_streamLine(coordinates, listener, closed) {
3224 var i = -1, n = coordinates.length - closed, coordinate;
3225 listener.lineStart();
3226 while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1], coordinate[2]);
3227 listener.lineEnd();
3228 }
3229 function d3_geo_streamPolygon(coordinates, listener) {
3230 var i = -1, n = coordinates.length;
3231 listener.polygonStart();
3232 while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1);
3233 listener.polygonEnd();
3234 }
3235 d3.geo.area = function(object) {
3236 d3_geo_areaSum = 0;
3237 d3.geo.stream(object, d3_geo_area);
3238 return d3_geo_areaSum;
3239 };
3240 var d3_geo_areaSum, d3_geo_areaRingSum = new d3_adder();
3241 var d3_geo_area = {
3242 sphere: function() {
3243 d3_geo_areaSum += 4 * π;
3244 },
3245 point: d3_noop,
3246 lineStart: d3_noop,
3247 lineEnd: d3_noop,
3248 polygonStart: function() {
3249 d3_geo_areaRingSum.reset();
3250 d3_geo_area.lineStart = d3_geo_areaRingStart;
3251 },
3252 polygonEnd: function() {
3253 var area = 2 * d3_geo_areaRingSum;
3254 d3_geo_areaSum += area < 0 ? 4 * π + area : area;
3255 d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop;
3256 }
3257 };
3258 function d3_geo_areaRingStart() {
3259 var λ00, φ00, λ0, cosφ0, sinφ0;
3260 d3_geo_area.point = function(λ, φ) {
3261 d3_geo_area.point = nextPoint;
3262 λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4),
3263 sinφ0 = Math.sin(φ);
3264 };
3265 function nextPoint(λ, φ) {
3266 λ *= d3_radians;
3267 φ = φ * d3_radians / 2 + π / 4;
3268 var dλ = λ - λ0, sdλ = dλ >= 0 ? 1 : -1, adλ = sdλ * dλ, cosφ = Math.cos(φ), sinφ = Math.sin(φ), k = sinφ0 * sinφ, u = cosφ0 * cosφ + k * Math.cos(adλ), v = k * sdλ * Math.sin(adλ);
3269 d3_geo_areaRingSum.add(Math.atan2(v, u));
3270 λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ;
3271 }
3272 d3_geo_area.lineEnd = function() {
3273 nextPoint(λ00, φ00);
3274 };
3275 }
3276 function d3_geo_cartesian(spherical) {
3277 var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ);
3278 return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ];
3279 }
3280 function d3_geo_cartesianDot(a, b) {
3281 return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
3282 }
3283 function d3_geo_cartesianCross(a, b) {
3284 return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] ];
3285 }
3286 function d3_geo_cartesianAdd(a, b) {
3287 a[0] += b[0];
3288 a[1] += b[1];
3289 a[2] += b[2];
3290 }
3291 function d3_geo_cartesianScale(vector, k) {
3292 return [ vector[0] * k, vector[1] * k, vector[2] * k ];
3293 }
3294 function d3_geo_cartesianNormalize(d) {
3295 var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
3296 d[0] /= l;
3297 d[1] /= l;
3298 d[2] /= l;
3299 }
3300 function d3_geo_spherical(cartesian) {
3301 return [ Math.atan2(cartesian[1], cartesian[0]), d3_asin(cartesian[2]) ];
3302 }
3303 function d3_geo_sphericalEqual(a, b) {
3304 return abs(a[0] - b[0]) < ε && abs(a[1] - b[1]) < ε;
3305 }
3306 d3.geo.bounds = function() {
3307 var λ0, φ0, λ1, φ1, λ_, λ__, φ__, p0, dλSum, ranges, range;
3308 var bound = {
3309 point: point,
3310 lineStart: lineStart,
3311 lineEnd: lineEnd,
3312 polygonStart: function() {
3313 bound.point = ringPoint;
3314 bound.lineStart = ringStart;
3315 bound.lineEnd = ringEnd;
3316 dλSum = 0;
3317 d3_geo_area.polygonStart();
3318 },
3319 polygonEnd: function() {
3320 d3_geo_area.polygonEnd();
3321 bound.point = point;
3322 bound.lineStart = lineStart;
3323 bound.lineEnd = lineEnd;
3324 if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90); else if (dλSum > ε) φ1 = 90; else if (dλSum < -ε) φ0 = -90;
3325 range[0] = λ0, range[1] = λ1;
3326 }
3327 };
3328 function point(λ, φ) {
3329 ranges.push(range = [ λ0 = λ, λ1 = λ ]);
3330 if (φ < φ0) φ0 = φ;
3331 if (φ > φ1) φ1 = φ;
3332 }
3333 function linePoint(λ, φ) {
3334 var p = d3_geo_cartesian([ λ * d3_radians, φ * d3_radians ]);
3335 if (p0) {
3336 var normal = d3_geo_cartesianCross(p0, p), equatorial = [ normal[1], -normal[0], 0 ], inflection = d3_geo_cartesianCross(equatorial, normal);
3337 d3_geo_cartesianNormalize(inflection);
3338 inflection = d3_geo_spherical(inflection);
3339 var dλ = λ - λ_, s = dλ > 0 ? 1 : -1, λi = inflection[0] * d3_degrees * s, antimeridian = abs(dλ) > 180;
3340 if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) {
3341 var φi = inflection[1] * d3_degrees;
3342 if (φi > φ1) φ1 = φi;
3343 } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) {
3344 var φi = -inflection[1] * d3_degrees;
3345 if (φi < φ0) φ0 = φi;
3346 } else {
3347 if (φ < φ0) φ0 = φ;
3348 if (φ > φ1) φ1 = φ;
3349 }
3350 if (antimeridian) {
3351 if (λ < λ_) {
3352 if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
3353 } else {
3354 if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
3355 }
3356 } else {
3357 if (λ1 >= λ0) {
3358 if (λ < λ0) λ0 = λ;
3359 if (λ > λ1) λ1 = λ;
3360 } else {
3361 if (λ > λ_) {
3362 if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
3363 } else {
3364 if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
3365 }
3366 }
3367 }
3368 } else {
3369 point(λ, φ);
3370 }
3371 p0 = p, λ_ = λ;
3372 }
3373 function lineStart() {
3374 bound.point = linePoint;
3375 }
3376 function lineEnd() {
3377 range[0] = λ0, range[1] = λ1;
3378 bound.point = point;
3379 p0 = null;
3380 }
3381 function ringPoint(λ, φ) {
3382 if (p0) {
3383 var dλ = λ - λ_;
3384 dλSum += abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ;
3385 } else λ__ = λ, φ__ = φ;
3386 d3_geo_area.point(λ, φ);
3387 linePoint(λ, φ);
3388 }
3389 function ringStart() {
3390 d3_geo_area.lineStart();
3391 }
3392 function ringEnd() {
3393 ringPoint(λ__, φ__);
3394 d3_geo_area.lineEnd();
3395 if (abs(dλSum) > ε) λ0 = -(λ1 = 180);
3396 range[0] = λ0, range[1] = λ1;
3397 p0 = null;
3398 }
3399 function angle(λ0, λ1) {
3400 return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1;
3401 }
3402 function compareRanges(a, b) {
3403 return a[0] - b[0];
3404 }
3405 function withinRange(x, range) {
3406 return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
3407 }
3408 return function(feature) {
3409 φ1 = λ1 = -(λ0 = φ0 = Infinity);
3410 ranges = [];
3411 d3.geo.stream(feature, bound);
3412 var n = ranges.length;
3413 if (n) {
3414 ranges.sort(compareRanges);
3415 for (var i = 1, a = ranges[0], b, merged = [ a ]; i < n; ++i) {
3416 b = ranges[i];
3417 if (withinRange(b[0], a) || withinRange(b[1], a)) {
3418 if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
3419 if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
3420 } else {
3421 merged.push(a = b);
3422 }
3423 }
3424 var best = -Infinity, dλ;
3425 for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) {
3426 b = merged[i];
3427 if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1];
3428 }
3429 }
3430 ranges = range = null;
3431 return λ0 === Infinity || φ0 === Infinity ? [ [ NaN, NaN ], [ NaN, NaN ] ] : [ [ λ0, φ0 ], [ λ1, φ1 ] ];
3432 };
3433 }();
3434 d3.geo.centroid = function(object) {
3435 d3_geo_centroidW0 = d3_geo_centroidW1 = d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;
3436 d3.geo.stream(object, d3_geo_centroid);
3437 var x = d3_geo_centroidX2, y = d3_geo_centroidY2, z = d3_geo_centroidZ2, m = x * x + y * y + z * z;
3438 if (m < ε2) {
3439 x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1;
3440 if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0;
3441 m = x * x + y * y + z * z;
3442 if (m < ε2) return [ NaN, NaN ];
3443 }
3444 return [ Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees ];
3445 };
3446 var d3_geo_centroidW0, d3_geo_centroidW1, d3_geo_centroidX0, d3_geo_centroidY0, d3_geo_centroidZ0, d3_geo_centroidX1, d3_geo_centroidY1, d3_geo_centroidZ1, d3_geo_centroidX2, d3_geo_centroidY2, d3_geo_centroidZ2;
3447 var d3_geo_centroid = {
3448 sphere: d3_noop,
3449 point: d3_geo_centroidPoint,
3450 lineStart: d3_geo_centroidLineStart,
3451 lineEnd: d3_geo_centroidLineEnd,
3452 polygonStart: function() {
3453 d3_geo_centroid.lineStart = d3_geo_centroidRingStart;
3454 },
3455 polygonEnd: function() {
3456 d3_geo_centroid.lineStart = d3_geo_centroidLineStart;
3457 }
3458 };
3459 function d3_geo_centroidPoint(λ, φ) {
3460 λ *= d3_radians;
3461 var cosφ = Math.cos(φ *= d3_radians);
3462 d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ));
3463 }
3464 function d3_geo_centroidPointXYZ(x, y, z) {
3465 ++d3_geo_centroidW0;
3466 d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0;
3467 d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0;
3468 d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0;
3469 }
3470 function d3_geo_centroidLineStart() {
3471 var x0, y0, z0;
3472 d3_geo_centroid.point = function(λ, φ) {
3473 λ *= d3_radians;
3474 var cosφ = Math.cos(φ *= d3_radians);
3475 x0 = cosφ * Math.cos(λ);
3476 y0 = cosφ * Math.sin(λ);
3477 z0 = Math.sin(φ);
3478 d3_geo_centroid.point = nextPoint;
3479 d3_geo_centroidPointXYZ(x0, y0, z0);
3480 };
3481 function nextPoint(λ, φ) {
3482 λ *= d3_radians;
3483 var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z);
3484 d3_geo_centroidW1 += w;
3485 d3_geo_centroidX1 += w * (x0 + (x0 = x));
3486 d3_geo_centroidY1 += w * (y0 + (y0 = y));
3487 d3_geo_centroidZ1 += w * (z0 + (z0 = z));
3488 d3_geo_centroidPointXYZ(x0, y0, z0);
3489 }
3490 }
3491 function d3_geo_centroidLineEnd() {
3492 d3_geo_centroid.point = d3_geo_centroidPoint;
3493 }
3494 function d3_geo_centroidRingStart() {
3495 var λ00, φ00, x0, y0, z0;
3496 d3_geo_centroid.point = function(λ, φ) {
3497 λ00 = λ, φ00 = φ;
3498 d3_geo_centroid.point = nextPoint;
3499 λ *= d3_radians;
3500 var cosφ = Math.cos(φ *= d3_radians);
3501 x0 = cosφ * Math.cos(λ);
3502 y0 = cosφ * Math.sin(λ);
3503 z0 = Math.sin(φ);
3504 d3_geo_centroidPointXYZ(x0, y0, z0);
3505 };
3506 d3_geo_centroid.lineEnd = function() {
3507 nextPoint(λ00, φ00);
3508 d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd;
3509 d3_geo_centroid.point = d3_geo_centroidPoint;
3510 };
3511 function nextPoint(λ, φ) {
3512 λ *= d3_radians;
3513 var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), cx = y0 * z - z0 * y, cy = z0 * x - x0 * z, cz = x0 * y - y0 * x, m = Math.sqrt(cx * cx + cy * cy + cz * cz), u = x0 * x + y0 * y + z0 * z, v = m && -d3_acos(u) / m, w = Math.atan2(m, u);
3514 d3_geo_centroidX2 += v * cx;
3515 d3_geo_centroidY2 += v * cy;
3516 d3_geo_centroidZ2 += v * cz;
3517 d3_geo_centroidW1 += w;
3518 d3_geo_centroidX1 += w * (x0 + (x0 = x));
3519 d3_geo_centroidY1 += w * (y0 + (y0 = y));
3520 d3_geo_centroidZ1 += w * (z0 + (z0 = z));
3521 d3_geo_centroidPointXYZ(x0, y0, z0);
3522 }
3523 }
3524 function d3_geo_compose(a, b) {
3525 function compose(x, y) {
3526 return x = a(x, y), b(x[0], x[1]);
3527 }
3528 if (a.invert && b.invert) compose.invert = function(x, y) {
3529 return x = b.invert(x, y), x && a.invert(x[0], x[1]);
3530 };
3531 return compose;
3532 }
3533 function d3_true() {
3534 return true;
3535 }
3536 function d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener) {
3537 var subject = [], clip = [];
3538 segments.forEach(function(segment) {
3539 if ((n = segment.length - 1) <= 0) return;
3540 var n, p0 = segment[0], p1 = segment[n];
3541 if (d3_geo_sphericalEqual(p0, p1)) {
3542 listener.lineStart();
3543 for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]);
3544 listener.lineEnd();
3545 return;
3546 }
3547 var a = new d3_geo_clipPolygonIntersection(p0, segment, null, true), b = new d3_geo_clipPolygonIntersection(p0, null, a, false);
3548 a.o = b;
3549 subject.push(a);
3550 clip.push(b);
3551 a = new d3_geo_clipPolygonIntersection(p1, segment, null, false);
3552 b = new d3_geo_clipPolygonIntersection(p1, null, a, true);
3553 a.o = b;
3554 subject.push(a);
3555 clip.push(b);
3556 });
3557 clip.sort(compare);
3558 d3_geo_clipPolygonLinkCircular(subject);
3559 d3_geo_clipPolygonLinkCircular(clip);
3560 if (!subject.length) return;
3561 for (var i = 0, entry = clipStartInside, n = clip.length; i < n; ++i) {
3562 clip[i].e = entry = !entry;
3563 }
3564 var start = subject[0], points, point;
3565 while (1) {
3566 var current = start, isSubject = true;
3567 while (current.v) if ((current = current.n) === start) return;
3568 points = current.z;
3569 listener.lineStart();
3570 do {
3571 current.v = current.o.v = true;
3572 if (current.e) {
3573 if (isSubject) {
3574 for (var i = 0, n = points.length; i < n; ++i) listener.point((point = points[i])[0], point[1]);
3575 } else {
3576 interpolate(current.x, current.n.x, 1, listener);
3577 }
3578 current = current.n;
3579 } else {
3580 if (isSubject) {
3581 points = current.p.z;
3582 for (var i = points.length - 1; i >= 0; --i) listener.point((point = points[i])[0], point[1]);
3583 } else {
3584 interpolate(current.x, current.p.x, -1, listener);
3585 }
3586 current = current.p;
3587 }
3588 current = current.o;
3589 points = current.z;
3590 isSubject = !isSubject;
3591 } while (!current.v);
3592 listener.lineEnd();
3593 }
3594 }
3595 function d3_geo_clipPolygonLinkCircular(array) {
3596 if (!(n = array.length)) return;
3597 var n, i = 0, a = array[0], b;
3598 while (++i < n) {
3599 a.n = b = array[i];
3600 b.p = a;
3601 a = b;
3602 }
3603 a.n = b = array[0];
3604 b.p = a;
3605 }
3606 function d3_geo_clipPolygonIntersection(point, points, other, entry) {
3607 this.x = point;
3608 this.z = points;
3609 this.o = other;
3610 this.e = entry;
3611 this.v = false;
3612 this.n = this.p = null;
3613 }
3614 function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) {
3615 return function(rotate, listener) {
3616 var line = clipLine(listener), rotatedClipStart = rotate.invert(clipStart[0], clipStart[1]);
3617 var clip = {
3618 point: point,
3619 lineStart: lineStart,
3620 lineEnd: lineEnd,
3621 polygonStart: function() {
3622 clip.point = pointRing;
3623 clip.lineStart = ringStart;
3624 clip.lineEnd = ringEnd;
3625 segments = [];
3626 polygon = [];
3627 },
3628 polygonEnd: function() {
3629 clip.point = point;
3630 clip.lineStart = lineStart;
3631 clip.lineEnd = lineEnd;
3632 segments = d3.merge(segments);
3633 var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon);
3634 if (segments.length) {
3635 if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
3636 d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, listener);
3637 } else if (clipStartInside) {
3638 if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
3639 listener.lineStart();
3640 interpolate(null, null, 1, listener);
3641 listener.lineEnd();
3642 }
3643 if (polygonStarted) listener.polygonEnd(), polygonStarted = false;
3644 segments = polygon = null;
3645 },
3646 sphere: function() {
3647 listener.polygonStart();
3648 listener.lineStart();
3649 interpolate(null, null, 1, listener);
3650 listener.lineEnd();
3651 listener.polygonEnd();
3652 }
3653 };
3654 function point(λ, φ) {
3655 var point = rotate(λ, φ);
3656 if (pointVisible(λ = point[0], φ = point[1])) listener.point(λ, φ);
3657 }
3658 function pointLine(λ, φ) {
3659 var point = rotate(λ, φ);
3660 line.point(point[0], point[1]);
3661 }
3662 function lineStart() {
3663 clip.point = pointLine;
3664 line.lineStart();
3665 }
3666 function lineEnd() {
3667 clip.point = point;
3668 line.lineEnd();
3669 }
3670 var segments;
3671 var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygonStarted = false, polygon, ring;
3672 function pointRing(λ, φ) {
3673 ring.push([ λ, φ ]);
3674 var point = rotate(λ, φ);
3675 ringListener.point(point[0], point[1]);
3676 }
3677 function ringStart() {
3678 ringListener.lineStart();
3679 ring = [];
3680 }
3681 function ringEnd() {
3682 pointRing(ring[0][0], ring[0][1]);
3683 ringListener.lineEnd();
3684 var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length;
3685 ring.pop();
3686 polygon.push(ring);
3687 ring = null;
3688 if (!n) return;
3689 if (clean & 1) {
3690 segment = ringSegments[0];
3691 var n = segment.length - 1, i = -1, point;
3692 if (n > 0) {
3693 if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
3694 listener.lineStart();
3695 while (++i < n) listener.point((point = segment[i])[0], point[1]);
3696 listener.lineEnd();
3697 }
3698 return;
3699 }
3700 if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
3701 segments.push(ringSegments.filter(d3_geo_clipSegmentLength1));
3702 }
3703 return clip;
3704 };
3705 }
3706 function d3_geo_clipSegmentLength1(segment) {
3707 return segment.length > 1;
3708 }
3709 function d3_geo_clipBufferListener() {
3710 var lines = [], line;
3711 return {
3712 lineStart: function() {
3713 lines.push(line = []);
3714 },
3715 point: function(λ, φ) {
3716 line.push([ λ, φ ]);
3717 },
3718 lineEnd: d3_noop,
3719 buffer: function() {
3720 var buffer = lines;
3721 lines = [];
3722 line = null;
3723 return buffer;
3724 },
3725 rejoin: function() {
3726 if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
3727 }
3728 };
3729 }
3730 function d3_geo_clipSort(a, b) {
3731 return ((a = a.x)[0] < 0 ? a[1] - halfπ - ε : halfπ - a[1]) - ((b = b.x)[0] < 0 ? b[1] - halfπ - ε : halfπ - b[1]);
3732 }
3733 var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate, [ -π, -π / 2 ]);
3734 function d3_geo_clipAntimeridianLine(listener) {
3735 var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean;
3736 return {
3737 lineStart: function() {
3738 listener.lineStart();
3739 clean = 1;
3740 },
3741 point: function(λ1, φ1) {
3742 var sλ1 = λ1 > 0 ? π : -π, dλ = abs(λ1 - λ0);
3743 if (abs(dλ - π) < ε) {
3744 listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? halfπ : -halfπ);
3745 listener.point(sλ0, φ0);
3746 listener.lineEnd();
3747 listener.lineStart();
3748 listener.point(sλ1, φ0);
3749 listener.point(λ1, φ0);
3750 clean = 0;
3751 } else if (sλ0 !== sλ1 && dλ >= π) {
3752 if (abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε;
3753 if (abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε;
3754 φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1);
3755 listener.point(sλ0, φ0);
3756 listener.lineEnd();
3757 listener.lineStart();
3758 listener.point(sλ1, φ0);
3759 clean = 0;
3760 }
3761 listener.point(λ0 = λ1, φ0 = φ1);
3762 sλ0 = sλ1;
3763 },
3764 lineEnd: function() {
3765 listener.lineEnd();
3766 λ0 = φ0 = NaN;
3767 },
3768 clean: function() {
3769 return 2 - clean;
3770 }
3771 };
3772 }
3773 function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) {
3774 var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1);
3775 return abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) / (cosφ0 * cosφ1 * sinλ0_λ1)) : (φ0 + φ1) / 2;
3776 }
3777 function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) {
3778 var φ;
3779 if (from == null) {
3780 φ = direction * halfπ;
3781 listener.point(-π, φ);
3782 listener.point(0, φ);
3783 listener.point(π, φ);
3784 listener.point(π, 0);
3785 listener.point(π, -φ);
3786 listener.point(0, -φ);
3787 listener.point(-π, -φ);
3788 listener.point(-π, 0);
3789 listener.point(-π, φ);
3790 } else if (abs(from[0] - to[0]) > ε) {
3791 var s = from[0] < to[0] ? π : -π;
3792 φ = direction * s / 2;
3793 listener.point(-s, φ);
3794 listener.point(0, φ);
3795 listener.point(s, φ);
3796 } else {
3797 listener.point(to[0], to[1]);
3798 }
3799 }
3800 function d3_geo_pointInPolygon(point, polygon) {
3801 var meridian = point[0], parallel = point[1], meridianNormal = [ Math.sin(meridian), -Math.cos(meridian), 0 ], polarAngle = 0, winding = 0;
3802 d3_geo_areaRingSum.reset();
3803 for (var i = 0, n = polygon.length; i < n; ++i) {
3804 var ring = polygon[i], m = ring.length;
3805 if (!m) continue;
3806 var point0 = ring[0], λ0 = point0[0], φ0 = point0[1] / 2 + π / 4, sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), j = 1;
3807 while (true) {
3808 if (j === m) j = 0;
3809 point = ring[j];
3810 var λ = point[0], φ = point[1] / 2 + π / 4, sinφ = Math.sin(φ), cosφ = Math.cos(φ), dλ = λ - λ0, sdλ = dλ >= 0 ? 1 : -1, adλ = sdλ * dλ, antimeridian = adλ > π, k = sinφ0 * sinφ;
3811 d3_geo_areaRingSum.add(Math.atan2(k * sdλ * Math.sin(adλ), cosφ0 * cosφ + k * Math.cos(adλ)));
3812 polarAngle += antimeridian ? dλ + sdλ * τ : dλ;
3813 if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) {
3814 var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point));
3815 d3_geo_cartesianNormalize(arc);
3816 var intersection = d3_geo_cartesianCross(meridianNormal, arc);
3817 d3_geo_cartesianNormalize(intersection);
3818 var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]);
3819 if (parallel > φarc || parallel === φarc && (arc[0] || arc[1])) {
3820 winding += antimeridian ^ dλ >= 0 ? 1 : -1;
3821 }
3822 }
3823 if (!j++) break;
3824 λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point;
3825 }
3826 }
3827 return (polarAngle < -ε || polarAngle < ε && d3_geo_areaRingSum < 0) ^ winding & 1;
3828 }
3829 function d3_geo_clipCircle(radius) {
3830 var cr = Math.cos(radius), smallRadius = cr > 0, notHemisphere = abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians);
3831 return d3_geo_clip(visible, clipLine, interpolate, smallRadius ? [ 0, -radius ] : [ -π, radius - π ]);
3832 function visible(λ, φ) {
3833 return Math.cos(λ) * Math.cos(φ) > cr;
3834 }
3835 function clipLine(listener) {
3836 var point0, c0, v0, v00, clean;
3837 return {
3838 lineStart: function() {
3839 v00 = v0 = false;
3840 clean = 1;
3841 },
3842 point: function(λ, φ) {
3843 var point1 = [ λ, φ ], point2, v = visible(λ, φ), c = smallRadius ? v ? 0 : code(λ, φ) : v ? code(λ + (λ < 0 ? π : -π), φ) : 0;
3844 if (!point0 && (v00 = v0 = v)) listener.lineStart();
3845 if (v !== v0) {
3846 point2 = intersect(point0, point1);
3847 if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) {
3848 point1[0] += ε;
3849 point1[1] += ε;
3850 v = visible(point1[0], point1[1]);
3851 }
3852 }
3853 if (v !== v0) {
3854 clean = 0;
3855 if (v) {
3856 listener.lineStart();
3857 point2 = intersect(point1, point0);
3858 listener.point(point2[0], point2[1]);
3859 } else {
3860 point2 = intersect(point0, point1);
3861 listener.point(point2[0], point2[1]);
3862 listener.lineEnd();
3863 }
3864 point0 = point2;
3865 } else if (notHemisphere && point0 && smallRadius ^ v) {
3866 var t;
3867 if (!(c & c0) && (t = intersect(point1, point0, true))) {
3868 clean = 0;
3869 if (smallRadius) {
3870 listener.lineStart();
3871 listener.point(t[0][0], t[0][1]);
3872 listener.point(t[1][0], t[1][1]);
3873 listener.lineEnd();
3874 } else {
3875 listener.point(t[1][0], t[1][1]);
3876 listener.lineEnd();
3877 listener.lineStart();
3878 listener.point(t[0][0], t[0][1]);
3879 }
3880 }
3881 }
3882 if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) {
3883 listener.point(point1[0], point1[1]);
3884 }
3885 point0 = point1, v0 = v, c0 = c;
3886 },
3887 lineEnd: function() {
3888 if (v0) listener.lineEnd();
3889 point0 = null;
3890 },
3891 clean: function() {
3892 return clean | (v00 && v0) << 1;
3893 }
3894 };
3895 }
3896 function intersect(a, b, two) {
3897 var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b);
3898 var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2;
3899 if (!determinant) return !two && a;
3900 var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B = d3_geo_cartesianScale(n2, c2);
3901 d3_geo_cartesianAdd(A, B);
3902 var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1);
3903 if (t2 < 0) return;
3904 var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu);
3905 d3_geo_cartesianAdd(q, A);
3906 q = d3_geo_spherical(q);
3907 if (!two) return q;
3908 var λ0 = a[0], λ1 = b[0], φ0 = a[1], φ1 = b[1], z;
3909 if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z;
3910 var δλ = λ1 - λ0, polar = abs(δλ - π) < ε, meridian = polar || δλ < ε;
3911 if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z;
3912 if (meridian ? polar ? φ0 + φ1 > 0 ^ q[1] < (abs(q[0] - λ0) < ε ? φ0 : φ1) : φ0 <= q[1] && q[1] <= φ1 : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) {
3913 var q1 = d3_geo_cartesianScale(u, (-w + t) / uu);
3914 d3_geo_cartesianAdd(q1, A);
3915 return [ q, d3_geo_spherical(q1) ];
3916 }
3917 }
3918 function code(λ, φ) {
3919 var r = smallRadius ? radius : π - radius, code = 0;
3920 if (λ < -r) code |= 1; else if (λ > r) code |= 2;
3921 if (φ < -r) code |= 4; else if (φ > r) code |= 8;
3922 return code;
3923 }
3924 }
3925 function d3_geom_clipLine(x0, y0, x1, y1) {
3926 return function(line) {
3927 var a = line.a, b = line.b, ax = a.x, ay = a.y, bx = b.x, by = b.y, t0 = 0, t1 = 1, dx = bx - ax, dy = by - ay, r;
3928 r = x0 - ax;
3929 if (!dx && r > 0) return;
3930 r /= dx;
3931 if (dx < 0) {
3932 if (r < t0) return;
3933 if (r < t1) t1 = r;
3934 } else if (dx > 0) {
3935 if (r > t1) return;
3936 if (r > t0) t0 = r;
3937 }
3938 r = x1 - ax;
3939 if (!dx && r < 0) return;
3940 r /= dx;
3941 if (dx < 0) {
3942 if (r > t1) return;
3943 if (r > t0) t0 = r;
3944 } else if (dx > 0) {
3945 if (r < t0) return;
3946 if (r < t1) t1 = r;
3947 }
3948 r = y0 - ay;
3949 if (!dy && r > 0) return;
3950 r /= dy;
3951 if (dy < 0) {
3952 if (r < t0) return;
3953 if (r < t1) t1 = r;
3954 } else if (dy > 0) {
3955 if (r > t1) return;
3956 if (r > t0) t0 = r;
3957 }
3958 r = y1 - ay;
3959 if (!dy && r < 0) return;
3960 r /= dy;
3961 if (dy < 0) {
3962 if (r > t1) return;
3963 if (r > t0) t0 = r;
3964 } else if (dy > 0) {
3965 if (r < t0) return;
3966 if (r < t1) t1 = r;
3967 }
3968 if (t0 > 0) line.a = {
3969 x: ax + t0 * dx,
3970 y: ay + t0 * dy
3971 };
3972 if (t1 < 1) line.b = {
3973 x: ax + t1 * dx,
3974 y: ay + t1 * dy
3975 };
3976 return line;
3977 };
3978 }
3979 var d3_geo_clipExtentMAX = 1e9;
3980 d3.geo.clipExtent = function() {
3981 var x0, y0, x1, y1, stream, clip, clipExtent = {
3982 stream: function(output) {
3983 if (stream) stream.valid = false;
3984 stream = clip(output);
3985 stream.valid = true;
3986 return stream;
3987 },
3988 extent: function(_) {
3989 if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ];
3990 clip = d3_geo_clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]);
3991 if (stream) stream.valid = false, stream = null;
3992 return clipExtent;
3993 }
3994 };
3995 return clipExtent.extent([ [ 0, 0 ], [ 960, 500 ] ]);
3996 };
3997 function d3_geo_clipExtent(x0, y0, x1, y1) {
3998 return function(listener) {
3999 var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), clipLine = d3_geom_clipLine(x0, y0, x1, y1), segments, polygon, ring;
4000 var clip = {
4001 point: point,
4002 lineStart: lineStart,
4003 lineEnd: lineEnd,
4004 polygonStart: function() {
4005 listener = bufferListener;
4006 segments = [];
4007 polygon = [];
4008 clean = true;
4009 },
4010 polygonEnd: function() {
4011 listener = listener_;
4012 segments = d3.merge(segments);
4013 var clipStartInside = insidePolygon([ x0, y1 ]), inside = clean && clipStartInside, visible = segments.length;
4014 if (inside || visible) {
4015 listener.polygonStart();
4016 if (inside) {
4017 listener.lineStart();
4018 interpolate(null, null, 1, listener);
4019 listener.lineEnd();
4020 }
4021 if (visible) {
4022 d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener);
4023 }
4024 listener.polygonEnd();
4025 }
4026 segments = polygon = ring = null;
4027 }
4028 };
4029 function insidePolygon(p) {
4030 var wn = 0, n = polygon.length, y = p[1];
4031 for (var i = 0; i < n; ++i) {
4032 for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) {
4033 b = v[j];
4034 if (a[1] <= y) {
4035 if (b[1] > y && d3_cross2d(a, b, p) > 0) ++wn;
4036 } else {
4037 if (b[1] <= y && d3_cross2d(a, b, p) < 0) --wn;
4038 }
4039 a = b;
4040 }
4041 }
4042 return wn !== 0;
4043 }
4044 function interpolate(from, to, direction, listener) {
4045 var a = 0, a1 = 0;
4046 if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoints(from, to) < 0 ^ direction > 0) {
4047 do {
4048 listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
4049 } while ((a = (a + direction + 4) % 4) !== a1);
4050 } else {
4051 listener.point(to[0], to[1]);
4052 }
4053 }
4054 function pointVisible(x, y) {
4055 return x0 <= x && x <= x1 && y0 <= y && y <= y1;
4056 }
4057 function point(x, y) {
4058 if (pointVisible(x, y)) listener.point(x, y);
4059 }
4060 var x__, y__, v__, x_, y_, v_, first, clean;
4061 function lineStart() {
4062 clip.point = linePoint;
4063 if (polygon) polygon.push(ring = []);
4064 first = true;
4065 v_ = false;
4066 x_ = y_ = NaN;
4067 }
4068 function lineEnd() {
4069 if (segments) {
4070 linePoint(x__, y__);
4071 if (v__ && v_) bufferListener.rejoin();
4072 segments.push(bufferListener.buffer());
4073 }
4074 clip.point = point;
4075 if (v_) listener.lineEnd();
4076 }
4077 function linePoint(x, y) {
4078 x = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x));
4079 y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y));
4080 var v = pointVisible(x, y);
4081 if (polygon) ring.push([ x, y ]);
4082 if (first) {
4083 x__ = x, y__ = y, v__ = v;
4084 first = false;
4085 if (v) {
4086 listener.lineStart();
4087 listener.point(x, y);
4088 }
4089 } else {
4090 if (v && v_) listener.point(x, y); else {
4091 var l = {
4092 a: {
4093 x: x_,
4094 y: y_
4095 },
4096 b: {
4097 x: x,
4098 y: y
4099 }
4100 };
4101 if (clipLine(l)) {
4102 if (!v_) {
4103 listener.lineStart();
4104 listener.point(l.a.x, l.a.y);
4105 }
4106 listener.point(l.b.x, l.b.y);
4107 if (!v) listener.lineEnd();
4108 clean = false;
4109 } else if (v) {
4110 listener.lineStart();
4111 listener.point(x, y);
4112 clean = false;
4113 }
4114 }
4115 }
4116 x_ = x, y_ = y, v_ = v;
4117 }
4118 return clip;
4119 };
4120 function corner(p, direction) {
4121 return abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 : abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2;
4122 }
4123 function compare(a, b) {
4124 return comparePoints(a.x, b.x);
4125 }
4126 function comparePoints(a, b) {
4127 var ca = corner(a, 1), cb = corner(b, 1);
4128 return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0];
4129 }
4130 }
4131 function d3_geo_conic(projectAt) {
4132 var φ0 = 0, φ1 = π / 3, m = d3_geo_projectionMutator(projectAt), p = m(φ0, φ1);
4133 p.parallels = function(_) {
4134 if (!arguments.length) return [ φ0 / π * 180, φ1 / π * 180 ];
4135 return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180);
4136 };
4137 return p;
4138 }
4139 function d3_geo_conicEqualArea(φ0, φ1) {
4140 var sinφ0 = Math.sin(φ0), n = (sinφ0 + Math.sin(φ1)) / 2, C = 1 + sinφ0 * (2 * n - sinφ0), ρ0 = Math.sqrt(C) / n;
4141 function forward(λ, φ) {
4142 var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n;
4143 return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ];
4144 }
4145 forward.invert = function(x, y) {
4146 var ρ0_y = ρ0 - y;
4147 return [ Math.atan2(x, ρ0_y) / n, d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ];
4148 };
4149 return forward;
4150 }
4151 (d3.geo.conicEqualArea = function() {
4152 return d3_geo_conic(d3_geo_conicEqualArea);
4153 }).raw = d3_geo_conicEqualArea;
4154 d3.geo.albers = function() {
4155 return d3.geo.conicEqualArea().rotate([ 96, 0 ]).center([ -.6, 38.7 ]).parallels([ 29.5, 45.5 ]).scale(1070);
4156 };
4157 d3.geo.albersUsa = function() {
4158 var lower48 = d3.geo.albers();
4159 var alaska = d3.geo.conicEqualArea().rotate([ 154, 0 ]).center([ -2, 58.5 ]).parallels([ 55, 65 ]);
4160 var hawaii = d3.geo.conicEqualArea().rotate([ 157, 0 ]).center([ -3, 19.9 ]).parallels([ 8, 18 ]);
4161 var point, pointStream = {
4162 point: function(x, y) {
4163 point = [ x, y ];
4164 }
4165 }, lower48Point, alaskaPoint, hawaiiPoint;
4166 function albersUsa(coordinates) {
4167 var x = coordinates[0], y = coordinates[1];
4168 point = null;
4169 (lower48Point(x, y), point) || (alaskaPoint(x, y), point) || hawaiiPoint(x, y);
4170 return point;
4171 }
4172 albersUsa.invert = function(coordinates) {
4173 var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k, y = (coordinates[1] - t[1]) / k;
4174 return (y >= .12 && y < .234 && x >= -.425 && x < -.214 ? alaska : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii : lower48).invert(coordinates);
4175 };
4176 albersUsa.stream = function(stream) {
4177 var lower48Stream = lower48.stream(stream), alaskaStream = alaska.stream(stream), hawaiiStream = hawaii.stream(stream);
4178 return {
4179 point: function(x, y) {
4180 lower48Stream.point(x, y);
4181 alaskaStream.point(x, y);
4182 hawaiiStream.point(x, y);
4183 },
4184 sphere: function() {
4185 lower48Stream.sphere();
4186 alaskaStream.sphere();
4187 hawaiiStream.sphere();
4188 },
4189 lineStart: function() {
4190 lower48Stream.lineStart();
4191 alaskaStream.lineStart();
4192 hawaiiStream.lineStart();
4193 },
4194 lineEnd: function() {
4195 lower48Stream.lineEnd();
4196 alaskaStream.lineEnd();
4197 hawaiiStream.lineEnd();
4198 },
4199 polygonStart: function() {
4200 lower48Stream.polygonStart();
4201 alaskaStream.polygonStart();
4202 hawaiiStream.polygonStart();
4203 },
4204 polygonEnd: function() {
4205 lower48Stream.polygonEnd();
4206 alaskaStream.polygonEnd();
4207 hawaiiStream.polygonEnd();
4208 }
4209 };
4210 };
4211 albersUsa.precision = function(_) {
4212 if (!arguments.length) return lower48.precision();
4213 lower48.precision(_);
4214 alaska.precision(_);
4215 hawaii.precision(_);
4216 return albersUsa;
4217 };
4218 albersUsa.scale = function(_) {
4219 if (!arguments.length) return lower48.scale();
4220 lower48.scale(_);
4221 alaska.scale(_ * .35);
4222 hawaii.scale(_);
4223 return albersUsa.translate(lower48.translate());
4224 };
4225 albersUsa.translate = function(_) {
4226 if (!arguments.length) return lower48.translate();
4227 var k = lower48.scale(), x = +_[0], y = +_[1];
4228 lower48Point = lower48.translate(_).clipExtent([ [ x - .455 * k, y - .238 * k ], [ x + .455 * k, y + .238 * k ] ]).stream(pointStream).point;
4229 alaskaPoint = alaska.translate([ x - .307 * k, y + .201 * k ]).clipExtent([ [ x - .425 * k + ε, y + .12 * k + ε ], [ x - .214 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point;
4230 hawaiiPoint = hawaii.translate([ x - .205 * k, y + .212 * k ]).clipExtent([ [ x - .214 * k + ε, y + .166 * k + ε ], [ x - .115 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point;
4231 return albersUsa;
4232 };
4233 return albersUsa.scale(1070);
4234 };
4235 var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = {
4236 point: d3_noop,
4237 lineStart: d3_noop,
4238 lineEnd: d3_noop,
4239 polygonStart: function() {
4240 d3_geo_pathAreaPolygon = 0;
4241 d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart;
4242 },
4243 polygonEnd: function() {
4244 d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop;
4245 d3_geo_pathAreaSum += abs(d3_geo_pathAreaPolygon / 2);
4246 }
4247 };
4248 function d3_geo_pathAreaRingStart() {
4249 var x00, y00, x0, y0;
4250 d3_geo_pathArea.point = function(x, y) {
4251 d3_geo_pathArea.point = nextPoint;
4252 x00 = x0 = x, y00 = y0 = y;
4253 };
4254 function nextPoint(x, y) {
4255 d3_geo_pathAreaPolygon += y0 * x - x0 * y;
4256 x0 = x, y0 = y;
4257 }
4258 d3_geo_pathArea.lineEnd = function() {
4259 nextPoint(x00, y00);
4260 };
4261 }
4262 var d3_geo_pathBoundsX0, d3_geo_pathBoundsY0, d3_geo_pathBoundsX1, d3_geo_pathBoundsY1;
4263 var d3_geo_pathBounds = {
4264 point: d3_geo_pathBoundsPoint,
4265 lineStart: d3_noop,
4266 lineEnd: d3_noop,
4267 polygonStart: d3_noop,
4268 polygonEnd: d3_noop
4269 };
4270 function d3_geo_pathBoundsPoint(x, y) {
4271 if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x;
4272 if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x;
4273 if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y;
4274 if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y;
4275 }
4276 function d3_geo_pathBuffer() {
4277 var pointCircle = d3_geo_pathBufferCircle(4.5), buffer = [];
4278 var stream = {
4279 point: point,
4280 lineStart: function() {
4281 stream.point = pointLineStart;
4282 },
4283 lineEnd: lineEnd,
4284 polygonStart: function() {
4285 stream.lineEnd = lineEndPolygon;
4286 },
4287 polygonEnd: function() {
4288 stream.lineEnd = lineEnd;
4289 stream.point = point;
4290 },
4291 pointRadius: function(_) {
4292 pointCircle = d3_geo_pathBufferCircle(_);
4293 return stream;
4294 },
4295 result: function() {
4296 if (buffer.length) {
4297 var result = buffer.join("");
4298 buffer = [];
4299 return result;
4300 }
4301 }
4302 };
4303 function point(x, y) {
4304 buffer.push("M", x, ",", y, pointCircle);
4305 }
4306 function pointLineStart(x, y) {
4307 buffer.push("M", x, ",", y);
4308 stream.point = pointLine;
4309 }
4310 function pointLine(x, y) {
4311 buffer.push("L", x, ",", y);
4312 }
4313 function lineEnd() {
4314 stream.point = point;
4315 }
4316 function lineEndPolygon() {
4317 buffer.push("Z");
4318 }
4319 return stream;
4320 }
4321 function d3_geo_pathBufferCircle(radius) {
4322 return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z";
4323 }
4324 var d3_geo_pathCentroid = {
4325 point: d3_geo_pathCentroidPoint,
4326 lineStart: d3_geo_pathCentroidLineStart,
4327 lineEnd: d3_geo_pathCentroidLineEnd,
4328 polygonStart: function() {
4329 d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart;
4330 },
4331 polygonEnd: function() {
4332 d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
4333 d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart;
4334 d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd;
4335 }
4336 };
4337 function d3_geo_pathCentroidPoint(x, y) {
4338 d3_geo_centroidX0 += x;
4339 d3_geo_centroidY0 += y;
4340 ++d3_geo_centroidZ0;
4341 }
4342 function d3_geo_pathCentroidLineStart() {
4343 var x0, y0;
4344 d3_geo_pathCentroid.point = function(x, y) {
4345 d3_geo_pathCentroid.point = nextPoint;
4346 d3_geo_pathCentroidPoint(x0 = x, y0 = y);
4347 };
4348 function nextPoint(x, y) {
4349 var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
4350 d3_geo_centroidX1 += z * (x0 + x) / 2;
4351 d3_geo_centroidY1 += z * (y0 + y) / 2;
4352 d3_geo_centroidZ1 += z;
4353 d3_geo_pathCentroidPoint(x0 = x, y0 = y);
4354 }
4355 }
4356 function d3_geo_pathCentroidLineEnd() {
4357 d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
4358 }
4359 function d3_geo_pathCentroidRingStart() {
4360 var x00, y00, x0, y0;
4361 d3_geo_pathCentroid.point = function(x, y) {
4362 d3_geo_pathCentroid.point = nextPoint;
4363 d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y);
4364 };
4365 function nextPoint(x, y) {
4366 var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
4367 d3_geo_centroidX1 += z * (x0 + x) / 2;
4368 d3_geo_centroidY1 += z * (y0 + y) / 2;
4369 d3_geo_centroidZ1 += z;
4370 z = y0 * x - x0 * y;
4371 d3_geo_centroidX2 += z * (x0 + x);
4372 d3_geo_centroidY2 += z * (y0 + y);
4373 d3_geo_centroidZ2 += z * 3;
4374 d3_geo_pathCentroidPoint(x0 = x, y0 = y);
4375 }
4376 d3_geo_pathCentroid.lineEnd = function() {
4377 nextPoint(x00, y00);
4378 };
4379 }
4380 function d3_geo_pathContext(context) {
4381 var pointRadius = 4.5;
4382 var stream = {
4383 point: point,
4384 lineStart: function() {
4385 stream.point = pointLineStart;
4386 },
4387 lineEnd: lineEnd,
4388 polygonStart: function() {
4389 stream.lineEnd = lineEndPolygon;
4390 },
4391 polygonEnd: function() {
4392 stream.lineEnd = lineEnd;
4393 stream.point = point;
4394 },
4395 pointRadius: function(_) {
4396 pointRadius = _;
4397 return stream;
4398 },
4399 result: d3_noop
4400 };
4401 function point(x, y) {
4402 context.moveTo(x + pointRadius, y);
4403 context.arc(x, y, pointRadius, 0, τ);
4404 }
4405 function pointLineStart(x, y) {
4406 context.moveTo(x, y);
4407 stream.point = pointLine;
4408 }
4409 function pointLine(x, y) {
4410 context.lineTo(x, y);
4411 }
4412 function lineEnd() {
4413 stream.point = point;
4414 }
4415 function lineEndPolygon() {
4416 context.closePath();
4417 }
4418 return stream;
4419 }
4420 function d3_geo_resample(project) {
4421 var δ2 = .5, cosMinDistance = Math.cos(30 * d3_radians), maxDepth = 16;
4422 function resample(stream) {
4423 return (maxDepth ? resampleRecursive : resampleNone)(stream);
4424 }
4425 function resampleNone(stream) {
4426 return d3_geo_transformPoint(stream, function(x, y) {
4427 x = project(x, y);
4428 stream.point(x[0], x[1]);
4429 });
4430 }
4431 function resampleRecursive(stream) {
4432 var λ00, φ00, x00, y00, a00, b00, c00, λ0, x0, y0, a0, b0, c0;
4433 var resample = {
4434 point: point,
4435 lineStart: lineStart,
4436 lineEnd: lineEnd,
4437 polygonStart: function() {
4438 stream.polygonStart();
4439 resample.lineStart = ringStart;
4440 },
4441 polygonEnd: function() {
4442 stream.polygonEnd();
4443 resample.lineStart = lineStart;
4444 }
4445 };
4446 function point(x, y) {
4447 x = project(x, y);
4448 stream.point(x[0], x[1]);
4449 }
4450 function lineStart() {
4451 x0 = NaN;
4452 resample.point = linePoint;
4453 stream.lineStart();
4454 }
4455 function linePoint(λ, φ) {
4456 var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ);
4457 resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
4458 stream.point(x0, y0);
4459 }
4460 function lineEnd() {
4461 resample.point = point;
4462 stream.lineEnd();
4463 }
4464 function ringStart() {
4465 lineStart();
4466 resample.point = ringPoint;
4467 resample.lineEnd = ringEnd;
4468 }
4469 function ringPoint(λ, φ) {
4470 linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
4471 resample.point = linePoint;
4472 }
4473 function ringEnd() {
4474 resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream);
4475 resample.lineEnd = lineEnd;
4476 lineEnd();
4477 }
4478 return resample;
4479 }
4480 function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) {
4481 var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy;
4482 if (d2 > 4 * δ2 && depth--) {
4483 var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c), φ2 = Math.asin(c /= m), λ2 = abs(abs(c) - 1) < ε || abs(λ0 - λ1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), p = project(λ2, φ2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 - y0, dz = dy * dx2 - dx * dy2;
4484 if (dz * dz / d2 > δ2 || abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) {
4485 resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream);
4486 stream.point(x2, y2);
4487 resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream);
4488 }
4489 }
4490 }
4491 resample.precision = function(_) {
4492 if (!arguments.length) return Math.sqrt(δ2);
4493 maxDepth = (δ2 = _ * _) > 0 && 16;
4494 return resample;
4495 };
4496 return resample;
4497 }
4498 d3.geo.path = function() {
4499 var pointRadius = 4.5, projection, context, projectStream, contextStream, cacheStream;
4500 function path(object) {
4501 if (object) {
4502 if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
4503 if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream);
4504 d3.geo.stream(object, cacheStream);
4505 }
4506 return contextStream.result();
4507 }
4508 path.area = function(object) {
4509 d3_geo_pathAreaSum = 0;
4510 d3.geo.stream(object, projectStream(d3_geo_pathArea));
4511 return d3_geo_pathAreaSum;
4512 };
4513 path.centroid = function(object) {
4514 d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;
4515 d3.geo.stream(object, projectStream(d3_geo_pathCentroid));
4516 return d3_geo_centroidZ2 ? [ d3_geo_centroidX2 / d3_geo_centroidZ2, d3_geo_centroidY2 / d3_geo_centroidZ2 ] : d3_geo_centroidZ1 ? [ d3_geo_centroidX1 / d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1 ] : d3_geo_centroidZ0 ? [ d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0 ] : [ NaN, NaN ];
4517 };
4518 path.bounds = function(object) {
4519 d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity);
4520 d3.geo.stream(object, projectStream(d3_geo_pathBounds));
4521 return [ [ d3_geo_pathBoundsX0, d3_geo_pathBoundsY0 ], [ d3_geo_pathBoundsX1, d3_geo_pathBoundsY1 ] ];
4522 };
4523 path.projection = function(_) {
4524 if (!arguments.length) return projection;
4525 projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity;
4526 return reset();
4527 };
4528 path.context = function(_) {
4529 if (!arguments.length) return context;
4530 contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_);
4531 if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
4532 return reset();
4533 };
4534 path.pointRadius = function(_) {
4535 if (!arguments.length) return pointRadius;
4536 pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
4537 return path;
4538 };
4539 function reset() {
4540 cacheStream = null;
4541 return path;
4542 }
4543 return path.projection(d3.geo.albersUsa()).context(null);
4544 };
4545 function d3_geo_pathProjectStream(project) {
4546 var resample = d3_geo_resample(function(x, y) {
4547 return project([ x * d3_degrees, y * d3_degrees ]);
4548 });
4549 return function(stream) {
4550 return d3_geo_projectionRadians(resample(stream));
4551 };
4552 }
4553 d3.geo.transform = function(methods) {
4554 return {
4555 stream: function(stream) {
4556 var transform = new d3_geo_transform(stream);
4557 for (var k in methods) transform[k] = methods[k];
4558 return transform;
4559 }
4560 };
4561 };
4562 function d3_geo_transform(stream) {
4563 this.stream = stream;
4564 }
4565 d3_geo_transform.prototype = {
4566 point: function(x, y) {
4567 this.stream.point(x, y);
4568 },
4569 sphere: function() {
4570 this.stream.sphere();
4571 },
4572 lineStart: function() {
4573 this.stream.lineStart();
4574 },
4575 lineEnd: function() {
4576 this.stream.lineEnd();
4577 },
4578 polygonStart: function() {
4579 this.stream.polygonStart();
4580 },
4581 polygonEnd: function() {
4582 this.stream.polygonEnd();
4583 }
4584 };
4585 function d3_geo_transformPoint(stream, point) {
4586 return {
4587 point: point,
4588 sphere: function() {
4589 stream.sphere();
4590 },
4591 lineStart: function() {
4592 stream.lineStart();
4593 },
4594 lineEnd: function() {
4595 stream.lineEnd();
4596 },
4597 polygonStart: function() {
4598 stream.polygonStart();
4599 },
4600 polygonEnd: function() {
4601 stream.polygonEnd();
4602 }
4603 };
4604 }
4605 d3.geo.projection = d3_geo_projection;
4606 d3.geo.projectionMutator = d3_geo_projectionMutator;
4607 function d3_geo_projection(project) {
4608 return d3_geo_projectionMutator(function() {
4609 return project;
4610 })();
4611 }
4612 function d3_geo_projectionMutator(projectAt) {
4613 var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) {
4614 x = project(x, y);
4615 return [ x[0] * k + δx, δy - x[1] * k ];
4616 }), k = 150, x = 480, y = 250, λ = 0, φ = 0, δλ = 0, δφ = 0, δγ = 0, δx, δy, preclip = d3_geo_clipAntimeridian, postclip = d3_identity, clipAngle = null, clipExtent = null, stream;
4617 function projection(point) {
4618 point = projectRotate(point[0] * d3_radians, point[1] * d3_radians);
4619 return [ point[0] * k + δx, δy - point[1] * k ];
4620 }
4621 function invert(point) {
4622 point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k);
4623 return point && [ point[0] * d3_degrees, point[1] * d3_degrees ];
4624 }
4625 projection.stream = function(output) {
4626 if (stream) stream.valid = false;
4627 stream = d3_geo_projectionRadians(preclip(rotate, projectResample(postclip(output))));
4628 stream.valid = true;
4629 return stream;
4630 };
4631 projection.clipAngle = function(_) {
4632 if (!arguments.length) return clipAngle;
4633 preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians);
4634 return invalidate();
4635 };
4636 projection.clipExtent = function(_) {
4637 if (!arguments.length) return clipExtent;
4638 clipExtent = _;
4639 postclip = _ ? d3_geo_clipExtent(_[0][0], _[0][1], _[1][0], _[1][1]) : d3_identity;
4640 return invalidate();
4641 };
4642 projection.scale = function(_) {
4643 if (!arguments.length) return k;
4644 k = +_;
4645 return reset();
4646 };
4647 projection.translate = function(_) {
4648 if (!arguments.length) return [ x, y ];
4649 x = +_[0];
4650 y = +_[1];
4651 return reset();
4652 };
4653 projection.center = function(_) {
4654 if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ];
4655 λ = _[0] % 360 * d3_radians;
4656 φ = _[1] % 360 * d3_radians;
4657 return reset();
4658 };
4659 projection.rotate = function(_) {
4660 if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ];
4661 δλ = _[0] % 360 * d3_radians;
4662 δφ = _[1] % 360 * d3_radians;
4663 δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0;
4664 return reset();
4665 };
4666 d3.rebind(projection, projectResample, "precision");
4667 function reset() {
4668 projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project);
4669 var center = project(λ, φ);
4670 δx = x - center[0] * k;
4671 δy = y + center[1] * k;
4672 return invalidate();
4673 }
4674 function invalidate() {
4675 if (stream) stream.valid = false, stream = null;
4676 return projection;
4677 }
4678 return function() {
4679 project = projectAt.apply(this, arguments);
4680 projection.invert = project.invert && invert;
4681 return reset();
4682 };
4683 }
4684 function d3_geo_projectionRadians(stream) {
4685 return d3_geo_transformPoint(stream, function(x, y) {
4686 stream.point(x * d3_radians, y * d3_radians);
4687 });
4688 }
4689 function d3_geo_equirectangular(λ, φ) {
4690 return [ λ, φ ];
4691 }
4692 (d3.geo.equirectangular = function() {
4693 return d3_geo_projection(d3_geo_equirectangular);
4694 }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular;
4695 d3.geo.rotation = function(rotate) {
4696 rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0);
4697 function forward(coordinates) {
4698 coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians);
4699 return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
4700 }
4701 forward.invert = function(coordinates) {
4702 coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians);
4703 return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
4704 };
4705 return forward;
4706 };
4707 function d3_geo_identityRotation(λ, φ) {
4708 return [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ];
4709 }
4710 d3_geo_identityRotation.invert = d3_geo_equirectangular;
4711 function d3_geo_rotation(δλ, δφ, δγ) {
4712 return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_identityRotation;
4713 }
4714 function d3_geo_forwardRotationλ(δλ) {
4715 return function(λ, φ) {
4716 return λ += δλ, [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ];
4717 };
4718 }
4719 function d3_geo_rotationλ(δλ) {
4720 var rotation = d3_geo_forwardRotationλ(δλ);
4721 rotation.invert = d3_geo_forwardRotationλ(-δλ);
4722 return rotation;
4723 }
4724 function d3_geo_rotationφγ(δφ, δγ) {
4725 var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ);
4726 function rotation(λ, φ) {
4727 var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ;
4728 return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), d3_asin(k * cosδγ + y * sinδγ) ];
4729 }
4730 rotation.invert = function(λ, φ) {
4731 var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ;
4732 return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), d3_asin(k * cosδφ - x * sinδφ) ];
4733 };
4734 return rotation;
4735 }
4736 d3.geo.circle = function() {
4737 var origin = [ 0, 0 ], angle, precision = 6, interpolate;
4738 function circle() {
4739 var center = typeof origin === "function" ? origin.apply(this, arguments) : origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, ring = [];
4740 interpolate(null, null, 1, {
4741 point: function(x, y) {
4742 ring.push(x = rotate(x, y));
4743 x[0] *= d3_degrees, x[1] *= d3_degrees;
4744 }
4745 });
4746 return {
4747 type: "Polygon",
4748 coordinates: [ ring ]
4749 };
4750 }
4751 circle.origin = function(x) {
4752 if (!arguments.length) return origin;
4753 origin = x;
4754 return circle;
4755 };
4756 circle.angle = function(x) {
4757 if (!arguments.length) return angle;
4758 interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians);
4759 return circle;
4760 };
4761 circle.precision = function(_) {
4762 if (!arguments.length) return precision;
4763 interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians);
4764 return circle;
4765 };
4766 return circle.angle(90);
4767 };
4768 function d3_geo_circleInterpolate(radius, precision) {
4769 var cr = Math.cos(radius), sr = Math.sin(radius);
4770 return function(from, to, direction, listener) {
4771 var step = direction * precision;
4772 if (from != null) {
4773 from = d3_geo_circleAngle(cr, from);
4774 to = d3_geo_circleAngle(cr, to);
4775 if (direction > 0 ? from < to : from > to) from += direction * τ;
4776 } else {
4777 from = radius + direction * τ;
4778 to = radius - .5 * step;
4779 }
4780 for (var point, t = from; direction > 0 ? t > to : t < to; t -= step) {
4781 listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]);
4782 }
4783 };
4784 }
4785 function d3_geo_circleAngle(cr, point) {
4786 var a = d3_geo_cartesian(point);
4787 a[0] -= cr;
4788 d3_geo_cartesianNormalize(a);
4789 var angle = d3_acos(-a[1]);
4790 return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI);
4791 }
4792 d3.geo.distance = function(a, b) {
4793 var Δλ = (b[0] - a[0]) * d3_radians, φ0 = a[1] * d3_radians, φ1 = b[1] * d3_radians, sinΔλ = Math.sin(Δλ), cosΔλ = Math.cos(Δλ), sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), sinφ1 = Math.sin(φ1), cosφ1 = Math.cos(φ1), t;
4794 return Math.atan2(Math.sqrt((t = cosφ1 * sinΔλ) * t + (t = cosφ0 * sinφ1 - sinφ0 * cosφ1 * cosΔλ) * t), sinφ0 * sinφ1 + cosφ0 * cosφ1 * cosΔλ);
4795 };
4796 d3.geo.graticule = function() {
4797 var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5;
4798 function graticule() {
4799 return {
4800 type: "MultiLineString",
4801 coordinates: lines()
4802 };
4803 }
4804 function lines() {
4805 return d3.range(Math.ceil(X0 / DX) * DX, X1, DX).map(X).concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1, DY).map(Y)).concat(d3.range(Math.ceil(x0 / dx) * dx, x1, dx).filter(function(x) {
4806 return abs(x % DX) > ε;
4807 }).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) {
4808 return abs(y % DY) > ε;
4809 }).map(y));
4810 }
4811 graticule.lines = function() {
4812 return lines().map(function(coordinates) {
4813 return {
4814 type: "LineString",
4815 coordinates: coordinates
4816 };
4817 });
4818 };
4819 graticule.outline = function() {
4820 return {
4821 type: "Polygon",
4822 coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1), Y(Y0).reverse().slice(1)) ]
4823 };
4824 };
4825 graticule.extent = function(_) {
4826 if (!arguments.length) return graticule.minorExtent();
4827 return graticule.majorExtent(_).minorExtent(_);
4828 };
4829 graticule.majorExtent = function(_) {
4830 if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ];
4831 X0 = +_[0][0], X1 = +_[1][0];
4832 Y0 = +_[0][1], Y1 = +_[1][1];
4833 if (X0 > X1) _ = X0, X0 = X1, X1 = _;
4834 if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _;
4835 return graticule.precision(precision);
4836 };
4837 graticule.minorExtent = function(_) {
4838 if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ];
4839 x0 = +_[0][0], x1 = +_[1][0];
4840 y0 = +_[0][1], y1 = +_[1][1];
4841 if (x0 > x1) _ = x0, x0 = x1, x1 = _;
4842 if (y0 > y1) _ = y0, y0 = y1, y1 = _;
4843 return graticule.precision(precision);
4844 };
4845 graticule.step = function(_) {
4846 if (!arguments.length) return graticule.minorStep();
4847 return graticule.majorStep(_).minorStep(_);
4848 };
4849 graticule.majorStep = function(_) {
4850 if (!arguments.length) return [ DX, DY ];
4851 DX = +_[0], DY = +_[1];
4852 return graticule;
4853 };
4854 graticule.minorStep = function(_) {
4855 if (!arguments.length) return [ dx, dy ];
4856 dx = +_[0], dy = +_[1];
4857 return graticule;
4858 };
4859 graticule.precision = function(_) {
4860 if (!arguments.length) return precision;
4861 precision = +_;
4862 x = d3_geo_graticuleX(y0, y1, 90);
4863 y = d3_geo_graticuleY(x0, x1, precision);
4864 X = d3_geo_graticuleX(Y0, Y1, 90);
4865 Y = d3_geo_graticuleY(X0, X1, precision);
4866 return graticule;
4867 };
4868 return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([ [ -180, -80 - ε ], [ 180, 80 + ε ] ]);
4869 };
4870 function d3_geo_graticuleX(y0, y1, dy) {
4871 var y = d3.range(y0, y1 - ε, dy).concat(y1);
4872 return function(x) {
4873 return y.map(function(y) {
4874 return [ x, y ];
4875 });
4876 };
4877 }
4878 function d3_geo_graticuleY(x0, x1, dx) {
4879 var x = d3.range(x0, x1 - ε, dx).concat(x1);
4880 return function(y) {
4881 return x.map(function(x) {
4882 return [ x, y ];
4883 });
4884 };
4885 }
4886 function d3_source(d) {
4887 return d.source;
4888 }
4889 function d3_target(d) {
4890 return d.target;
4891 }
4892 d3.geo.greatArc = function() {
4893 var source = d3_source, source_, target = d3_target, target_;
4894 function greatArc() {
4895 return {
4896 type: "LineString",
4897 coordinates: [ source_ || source.apply(this, arguments), target_ || target.apply(this, arguments) ]
4898 };
4899 }
4900 greatArc.distance = function() {
4901 return d3.geo.distance(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments));
4902 };
4903 greatArc.source = function(_) {
4904 if (!arguments.length) return source;
4905 source = _, source_ = typeof _ === "function" ? null : _;
4906 return greatArc;
4907 };
4908 greatArc.target = function(_) {
4909 if (!arguments.length) return target;
4910 target = _, target_ = typeof _ === "function" ? null : _;
4911 return greatArc;
4912 };
4913 greatArc.precision = function() {
4914 return arguments.length ? greatArc : 0;
4915 };
4916 return greatArc;
4917 };
4918 d3.geo.interpolate = function(source, target) {
4919 return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians);
4920 };
4921 function d3_geo_interpolate(x0, y0, x1, y1) {
4922 var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = 2 * Math.asin(Math.sqrt(d3_haversin(y1 - y0) + cy0 * cy1 * d3_haversin(x1 - x0))), k = 1 / Math.sin(d);
4923 var interpolate = d ? function(t) {
4924 var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1;
4925 return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) * d3_degrees ];
4926 } : function() {
4927 return [ x0 * d3_degrees, y0 * d3_degrees ];
4928 };
4929 interpolate.distance = d;
4930 return interpolate;
4931 }
4932 d3.geo.length = function(object) {
4933 d3_geo_lengthSum = 0;
4934 d3.geo.stream(object, d3_geo_length);
4935 return d3_geo_lengthSum;
4936 };
4937 var d3_geo_lengthSum;
4938 var d3_geo_length = {
4939 sphere: d3_noop,
4940 point: d3_noop,
4941 lineStart: d3_geo_lengthLineStart,
4942 lineEnd: d3_noop,
4943 polygonStart: d3_noop,
4944 polygonEnd: d3_noop
4945 };
4946 function d3_geo_lengthLineStart() {
4947 var λ0, sinφ0, cosφ0;
4948 d3_geo_length.point = function(λ, φ) {
4949 λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ);
4950 d3_geo_length.point = nextPoint;
4951 };
4952 d3_geo_length.lineEnd = function() {
4953 d3_geo_length.point = d3_geo_length.lineEnd = d3_noop;
4954 };
4955 function nextPoint(λ, φ) {
4956 var sinφ = Math.sin(φ *= d3_radians), cosφ = Math.cos(φ), t = abs((λ *= d3_radians) - λ0), cosΔλ = Math.cos(t);
4957 d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosφ * Math.sin(t)) * t + (t = cosφ0 * sinφ - sinφ0 * cosφ * cosΔλ) * t), sinφ0 * sinφ + cosφ0 * cosφ * cosΔλ);
4958 λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ;
4959 }
4960 }
4961 function d3_geo_azimuthal(scale, angle) {
4962 function azimuthal(λ, φ) {
4963 var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ);
4964 return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ];
4965 }
4966 azimuthal.invert = function(x, y) {
4967 var ρ = Math.sqrt(x * x + y * y), c = angle(ρ), sinc = Math.sin(c), cosc = Math.cos(c);
4968 return [ Math.atan2(x * sinc, ρ * cosc), Math.asin(ρ && y * sinc / ρ) ];
4969 };
4970 return azimuthal;
4971 }
4972 var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) {
4973 return Math.sqrt(2 / (1 + cosλcosφ));
4974 }, function(ρ) {
4975 return 2 * Math.asin(ρ / 2);
4976 });
4977 (d3.geo.azimuthalEqualArea = function() {
4978 return d3_geo_projection(d3_geo_azimuthalEqualArea);
4979 }).raw = d3_geo_azimuthalEqualArea;
4980 var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) {
4981 var c = Math.acos(cosλcosφ);
4982 return c && c / Math.sin(c);
4983 }, d3_identity);
4984 (d3.geo.azimuthalEquidistant = function() {
4985 return d3_geo_projection(d3_geo_azimuthalEquidistant);
4986 }).raw = d3_geo_azimuthalEquidistant;
4987 function d3_geo_conicConformal(φ0, φ1) {
4988 var cosφ0 = Math.cos(φ0), t = function(φ) {
4989 return Math.tan(π / 4 + φ / 2);
4990 }, n = φ0 === φ1 ? Math.sin(φ0) : Math.log(cosφ0 / Math.cos(φ1)) / Math.log(t(φ1) / t(φ0)), F = cosφ0 * Math.pow(t(φ0), n) / n;
4991 if (!n) return d3_geo_mercator;
4992 function forward(λ, φ) {
4993 if (F > 0) {
4994 if (φ < -halfπ + ε) φ = -halfπ + ε;
4995 } else {
4996 if (φ > halfπ - ε) φ = halfπ - ε;
4997 }
4998 var ρ = F / Math.pow(t(φ), n);
4999 return [ ρ * Math.sin(n * λ), F - ρ * Math.cos(n * λ) ];
5000 }
5001 forward.invert = function(x, y) {
5002 var ρ0_y = F - y, ρ = d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y);
5003 return [ Math.atan2(x, ρ0_y) / n, 2 * Math.atan(Math.pow(F / ρ, 1 / n)) - halfπ ];
5004 };
5005 return forward;
5006 }
5007 (d3.geo.conicConformal = function() {
5008 return d3_geo_conic(d3_geo_conicConformal);
5009 }).raw = d3_geo_conicConformal;
5010 function d3_geo_conicEquidistant(φ0, φ1) {
5011 var cosφ0 = Math.cos(φ0), n = φ0 === φ1 ? Math.sin(φ0) : (cosφ0 - Math.cos(φ1)) / (φ1 - φ0), G = cosφ0 / n + φ0;
5012 if (abs(n) < ε) return d3_geo_equirectangular;
5013 function forward(λ, φ) {
5014 var ρ = G - φ;
5015 return [ ρ * Math.sin(n * λ), G - ρ * Math.cos(n * λ) ];
5016 }
5017 forward.invert = function(x, y) {
5018 var ρ0_y = G - y;
5019 return [ Math.atan2(x, ρ0_y) / n, G - d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y) ];
5020 };
5021 return forward;
5022 }
5023 (d3.geo.conicEquidistant = function() {
5024 return d3_geo_conic(d3_geo_conicEquidistant);
5025 }).raw = d3_geo_conicEquidistant;
5026 var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) {
5027 return 1 / cosλcosφ;
5028 }, Math.atan);
5029 (d3.geo.gnomonic = function() {
5030 return d3_geo_projection(d3_geo_gnomonic);
5031 }).raw = d3_geo_gnomonic;
5032 function d3_geo_mercator(λ, φ) {
5033 return [ λ, Math.log(Math.tan(π / 4 + φ / 2)) ];
5034 }
5035 d3_geo_mercator.invert = function(x, y) {
5036 return [ x, 2 * Math.atan(Math.exp(y)) - halfπ ];
5037 };
5038 function d3_geo_mercatorProjection(project) {
5039 var m = d3_geo_projection(project), scale = m.scale, translate = m.translate, clipExtent = m.clipExtent, clipAuto;
5040 m.scale = function() {
5041 var v = scale.apply(m, arguments);
5042 return v === m ? clipAuto ? m.clipExtent(null) : m : v;
5043 };
5044 m.translate = function() {
5045 var v = translate.apply(m, arguments);
5046 return v === m ? clipAuto ? m.clipExtent(null) : m : v;
5047 };
5048 m.clipExtent = function(_) {
5049 var v = clipExtent.apply(m, arguments);
5050 if (v === m) {
5051 if (clipAuto = _ == null) {
5052 var k = π * scale(), t = translate();
5053 clipExtent([ [ t[0] - k, t[1] - k ], [ t[0] + k, t[1] + k ] ]);
5054 }
5055 } else if (clipAuto) {
5056 v = null;
5057 }
5058 return v;
5059 };
5060 return m.clipExtent(null);
5061 }
5062 (d3.geo.mercator = function() {
5063 return d3_geo_mercatorProjection(d3_geo_mercator);
5064 }).raw = d3_geo_mercator;
5065 var d3_geo_orthographic = d3_geo_azimuthal(function() {
5066 return 1;
5067 }, Math.asin);
5068 (d3.geo.orthographic = function() {
5069 return d3_geo_projection(d3_geo_orthographic);
5070 }).raw = d3_geo_orthographic;
5071 var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) {
5072 return 1 / (1 + cosλcosφ);
5073 }, function(ρ) {
5074 return 2 * Math.atan(ρ);
5075 });
5076 (d3.geo.stereographic = function() {
5077 return d3_geo_projection(d3_geo_stereographic);
5078 }).raw = d3_geo_stereographic;
5079 function d3_geo_transverseMercator(λ, φ) {
5080 return [ Math.log(Math.tan(π / 4 + φ / 2)), -λ ];
5081 }
5082 d3_geo_transverseMercator.invert = function(x, y) {
5083 return [ -y, 2 * Math.atan(Math.exp(x)) - halfπ ];
5084 };
5085 (d3.geo.transverseMercator = function() {
5086 var projection = d3_geo_mercatorProjection(d3_geo_transverseMercator), center = projection.center, rotate = projection.rotate;
5087 projection.center = function(_) {
5088 return _ ? center([ -_[1], _[0] ]) : (_ = center(), [ _[1], -_[0] ]);
5089 };
5090 projection.rotate = function(_) {
5091 return _ ? rotate([ _[0], _[1], _.length > 2 ? _[2] + 90 : 90 ]) : (_ = rotate(),
5092 [ _[0], _[1], _[2] - 90 ]);
5093 };
5094 return rotate([ 0, 0, 90 ]);
5095 }).raw = d3_geo_transverseMercator;
5096 d3.geom = {};
5097 function d3_geom_pointX(d) {
5098 return d[0];
5099 }
5100 function d3_geom_pointY(d) {
5101 return d[1];
5102 }
5103 d3.geom.hull = function(vertices) {
5104 var x = d3_geom_pointX, y = d3_geom_pointY;
5105 if (arguments.length) return hull(vertices);
5106 function hull(data) {
5107 if (data.length < 3) return [];
5108 var fx = d3_functor(x), fy = d3_functor(y), i, n = data.length, points = [], flippedPoints = [];
5109 for (i = 0; i < n; i++) {
5110 points.push([ +fx.call(this, data[i], i), +fy.call(this, data[i], i), i ]);
5111 }
5112 points.sort(d3_geom_hullOrder);
5113 for (i = 0; i < n; i++) flippedPoints.push([ points[i][0], -points[i][1] ]);
5114 var upper = d3_geom_hullUpper(points), lower = d3_geom_hullUpper(flippedPoints);
5115 var skipLeft = lower[0] === upper[0], skipRight = lower[lower.length - 1] === upper[upper.length - 1], polygon = [];
5116 for (i = upper.length - 1; i >= 0; --i) polygon.push(data[points[upper[i]][2]]);
5117 for (i = +skipLeft; i < lower.length - skipRight; ++i) polygon.push(data[points[lower[i]][2]]);
5118 return polygon;
5119 }
5120 hull.x = function(_) {
5121 return arguments.length ? (x = _, hull) : x;
5122 };
5123 hull.y = function(_) {
5124 return arguments.length ? (y = _, hull) : y;
5125 };
5126 return hull;
5127 };
5128 function d3_geom_hullUpper(points) {
5129 var n = points.length, hull = [ 0, 1 ], hs = 2;
5130 for (var i = 2; i < n; i++) {
5131 while (hs > 1 && d3_cross2d(points[hull[hs - 2]], points[hull[hs - 1]], points[i]) <= 0) --hs;
5132 hull[hs++] = i;
5133 }
5134 return hull.slice(0, hs);
5135 }
5136 function d3_geom_hullOrder(a, b) {
5137 return a[0] - b[0] || a[1] - b[1];
5138 }
5139 d3.geom.polygon = function(coordinates) {
5140 d3_subclass(coordinates, d3_geom_polygonPrototype);
5141 return coordinates;
5142 };
5143 var d3_geom_polygonPrototype = d3.geom.polygon.prototype = [];
5144 d3_geom_polygonPrototype.area = function() {
5145 var i = -1, n = this.length, a, b = this[n - 1], area = 0;
5146 while (++i < n) {
5147 a = b;
5148 b = this[i];
5149 area += a[1] * b[0] - a[0] * b[1];
5150 }
5151 return area * .5;
5152 };
5153 d3_geom_polygonPrototype.centroid = function(k) {
5154 var i = -1, n = this.length, x = 0, y = 0, a, b = this[n - 1], c;
5155 if (!arguments.length) k = -1 / (6 * this.area());
5156 while (++i < n) {
5157 a = b;
5158 b = this[i];
5159 c = a[0] * b[1] - b[0] * a[1];
5160 x += (a[0] + b[0]) * c;
5161 y += (a[1] + b[1]) * c;
5162 }
5163 return [ x * k, y * k ];
5164 };
5165 d3_geom_polygonPrototype.clip = function(subject) {
5166 var input, closed = d3_geom_polygonClosed(subject), i = -1, n = this.length - d3_geom_polygonClosed(this), j, m, a = this[n - 1], b, c, d;
5167 while (++i < n) {
5168 input = subject.slice();
5169 subject.length = 0;
5170 b = this[i];
5171 c = input[(m = input.length - closed) - 1];
5172 j = -1;
5173 while (++j < m) {
5174 d = input[j];
5175 if (d3_geom_polygonInside(d, a, b)) {
5176 if (!d3_geom_polygonInside(c, a, b)) {
5177 subject.push(d3_geom_polygonIntersect(c, d, a, b));
5178 }
5179 subject.push(d);
5180 } else if (d3_geom_polygonInside(c, a, b)) {
5181 subject.push(d3_geom_polygonIntersect(c, d, a, b));
5182 }
5183 c = d;
5184 }
5185 if (closed) subject.push(subject[0]);
5186 a = b;
5187 }
5188 return subject;
5189 };
5190 function d3_geom_polygonInside(p, a, b) {
5191 return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]);
5192 }
5193 function d3_geom_polygonIntersect(c, d, a, b) {
5194 var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21);
5195 return [ x1 + ua * x21, y1 + ua * y21 ];
5196 }
5197 function d3_geom_polygonClosed(coordinates) {
5198 var a = coordinates[0], b = coordinates[coordinates.length - 1];
5199 return !(a[0] - b[0] || a[1] - b[1]);
5200 }
5201 var d3_geom_voronoiEdges, d3_geom_voronoiCells, d3_geom_voronoiBeaches, d3_geom_voronoiBeachPool = [], d3_geom_voronoiFirstCircle, d3_geom_voronoiCircles, d3_geom_voronoiCirclePool = [];
5202 function d3_geom_voronoiBeach() {
5203 d3_geom_voronoiRedBlackNode(this);
5204 this.edge = this.site = this.circle = null;
5205 }
5206 function d3_geom_voronoiCreateBeach(site) {
5207 var beach = d3_geom_voronoiBeachPool.pop() || new d3_geom_voronoiBeach();
5208 beach.site = site;
5209 return beach;
5210 }
5211 function d3_geom_voronoiDetachBeach(beach) {
5212 d3_geom_voronoiDetachCircle(beach);
5213 d3_geom_voronoiBeaches.remove(beach);
5214 d3_geom_voronoiBeachPool.push(beach);
5215 d3_geom_voronoiRedBlackNode(beach);
5216 }
5217 function d3_geom_voronoiRemoveBeach(beach) {
5218 var circle = beach.circle, x = circle.x, y = circle.cy, vertex = {
5219 x: x,
5220 y: y
5221 }, previous = beach.P, next = beach.N, disappearing = [ beach ];
5222 d3_geom_voronoiDetachBeach(beach);
5223 var lArc = previous;
5224 while (lArc.circle && abs(x - lArc.circle.x) < ε && abs(y - lArc.circle.cy) < ε) {
5225 previous = lArc.P;
5226 disappearing.unshift(lArc);
5227 d3_geom_voronoiDetachBeach(lArc);
5228 lArc = previous;
5229 }
5230 disappearing.unshift(lArc);
5231 d3_geom_voronoiDetachCircle(lArc);
5232 var rArc = next;
5233 while (rArc.circle && abs(x - rArc.circle.x) < ε && abs(y - rArc.circle.cy) < ε) {
5234 next = rArc.N;
5235 disappearing.push(rArc);
5236 d3_geom_voronoiDetachBeach(rArc);
5237 rArc = next;
5238 }
5239 disappearing.push(rArc);
5240 d3_geom_voronoiDetachCircle(rArc);
5241 var nArcs = disappearing.length, iArc;
5242 for (iArc = 1; iArc < nArcs; ++iArc) {
5243 rArc = disappearing[iArc];
5244 lArc = disappearing[iArc - 1];
5245 d3_geom_voronoiSetEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex);
5246 }
5247 lArc = disappearing[0];
5248 rArc = disappearing[nArcs - 1];
5249 rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, rArc.site, null, vertex);
5250 d3_geom_voronoiAttachCircle(lArc);
5251 d3_geom_voronoiAttachCircle(rArc);
5252 }
5253 function d3_geom_voronoiAddBeach(site) {
5254 var x = site.x, directrix = site.y, lArc, rArc, dxl, dxr, node = d3_geom_voronoiBeaches._;
5255 while (node) {
5256 dxl = d3_geom_voronoiLeftBreakPoint(node, directrix) - x;
5257 if (dxl > ε) node = node.L; else {
5258 dxr = x - d3_geom_voronoiRightBreakPoint(node, directrix);
5259 if (dxr > ε) {
5260 if (!node.R) {
5261 lArc = node;
5262 break;
5263 }
5264 node = node.R;
5265 } else {
5266 if (dxl > -ε) {
5267 lArc = node.P;
5268 rArc = node;
5269 } else if (dxr > -ε) {
5270 lArc = node;
5271 rArc = node.N;
5272 } else {
5273 lArc = rArc = node;
5274 }
5275 break;
5276 }
5277 }
5278 }
5279 var newArc = d3_geom_voronoiCreateBeach(site);
5280 d3_geom_voronoiBeaches.insert(lArc, newArc);
5281 if (!lArc && !rArc) return;
5282 if (lArc === rArc) {
5283 d3_geom_voronoiDetachCircle(lArc);
5284 rArc = d3_geom_voronoiCreateBeach(lArc.site);
5285 d3_geom_voronoiBeaches.insert(newArc, rArc);
5286 newArc.edge = rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site);
5287 d3_geom_voronoiAttachCircle(lArc);
5288 d3_geom_voronoiAttachCircle(rArc);
5289 return;
5290 }
5291 if (!rArc) {
5292 newArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site);
5293 return;
5294 }
5295 d3_geom_voronoiDetachCircle(lArc);
5296 d3_geom_voronoiDetachCircle(rArc);
5297 var lSite = lArc.site, ax = lSite.x, ay = lSite.y, bx = site.x - ax, by = site.y - ay, rSite = rArc.site, cx = rSite.x - ax, cy = rSite.y - ay, d = 2 * (bx * cy - by * cx), hb = bx * bx + by * by, hc = cx * cx + cy * cy, vertex = {
5298 x: (cy * hb - by * hc) / d + ax,
5299 y: (bx * hc - cx * hb) / d + ay
5300 };
5301 d3_geom_voronoiSetEdgeEnd(rArc.edge, lSite, rSite, vertex);
5302 newArc.edge = d3_geom_voronoiCreateEdge(lSite, site, null, vertex);
5303 rArc.edge = d3_geom_voronoiCreateEdge(site, rSite, null, vertex);
5304 d3_geom_voronoiAttachCircle(lArc);
5305 d3_geom_voronoiAttachCircle(rArc);
5306 }
5307 function d3_geom_voronoiLeftBreakPoint(arc, directrix) {
5308 var site = arc.site, rfocx = site.x, rfocy = site.y, pby2 = rfocy - directrix;
5309 if (!pby2) return rfocx;
5310 var lArc = arc.P;
5311 if (!lArc) return -Infinity;
5312 site = lArc.site;
5313 var lfocx = site.x, lfocy = site.y, plby2 = lfocy - directrix;
5314 if (!plby2) return lfocx;
5315 var hl = lfocx - rfocx, aby2 = 1 / pby2 - 1 / plby2, b = hl / plby2;
5316 if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx;
5317 return (rfocx + lfocx) / 2;
5318 }
5319 function d3_geom_voronoiRightBreakPoint(arc, directrix) {
5320 var rArc = arc.N;
5321 if (rArc) return d3_geom_voronoiLeftBreakPoint(rArc, directrix);
5322 var site = arc.site;
5323 return site.y === directrix ? site.x : Infinity;
5324 }
5325 function d3_geom_voronoiCell(site) {
5326 this.site = site;
5327 this.edges = [];
5328 }
5329 d3_geom_voronoiCell.prototype.prepare = function() {
5330 var halfEdges = this.edges, iHalfEdge = halfEdges.length, edge;
5331 while (iHalfEdge--) {
5332 edge = halfEdges[iHalfEdge].edge;
5333 if (!edge.b || !edge.a) halfEdges.splice(iHalfEdge, 1);
5334 }
5335 halfEdges.sort(d3_geom_voronoiHalfEdgeOrder);
5336 return halfEdges.length;
5337 };
5338 function d3_geom_voronoiCloseCells(extent) {
5339 var x0 = extent[0][0], x1 = extent[1][0], y0 = extent[0][1], y1 = extent[1][1], x2, y2, x3, y3, cells = d3_geom_voronoiCells, iCell = cells.length, cell, iHalfEdge, halfEdges, nHalfEdges, start, end;
5340 while (iCell--) {
5341 cell = cells[iCell];
5342 if (!cell || !cell.prepare()) continue;
5343 halfEdges = cell.edges;
5344 nHalfEdges = halfEdges.length;
5345 iHalfEdge = 0;
5346 while (iHalfEdge < nHalfEdges) {
5347 end = halfEdges[iHalfEdge].end(), x3 = end.x, y3 = end.y;
5348 start = halfEdges[++iHalfEdge % nHalfEdges].start(), x2 = start.x, y2 = start.y;
5349 if (abs(x3 - x2) > ε || abs(y3 - y2) > ε) {
5350 halfEdges.splice(iHalfEdge, 0, new d3_geom_voronoiHalfEdge(d3_geom_voronoiCreateBorderEdge(cell.site, end, abs(x3 - x0) < ε && y1 - y3 > ε ? {
5351 x: x0,
5352 y: abs(x2 - x0) < ε ? y2 : y1
5353 } : abs(y3 - y1) < ε && x1 - x3 > ε ? {
5354 x: abs(y2 - y1) < ε ? x2 : x1,
5355 y: y1
5356 } : abs(x3 - x1) < ε && y3 - y0 > ε ? {
5357 x: x1,
5358 y: abs(x2 - x1) < ε ? y2 : y0
5359 } : abs(y3 - y0) < ε && x3 - x0 > ε ? {
5360 x: abs(y2 - y0) < ε ? x2 : x0,
5361 y: y0
5362 } : null), cell.site, null));
5363 ++nHalfEdges;
5364 }
5365 }
5366 }
5367 }
5368 function d3_geom_voronoiHalfEdgeOrder(a, b) {
5369 return b.angle - a.angle;
5370 }
5371 function d3_geom_voronoiCircle() {
5372 d3_geom_voronoiRedBlackNode(this);
5373 this.x = this.y = this.arc = this.site = this.cy = null;
5374 }
5375 function d3_geom_voronoiAttachCircle(arc) {
5376 var lArc = arc.P, rArc = arc.N;
5377 if (!lArc || !rArc) return;
5378 var lSite = lArc.site, cSite = arc.site, rSite = rArc.site;
5379 if (lSite === rSite) return;
5380 var bx = cSite.x, by = cSite.y, ax = lSite.x - bx, ay = lSite.y - by, cx = rSite.x - bx, cy = rSite.y - by;
5381 var d = 2 * (ax * cy - ay * cx);
5382 if (d >= -ε2) return;
5383 var ha = ax * ax + ay * ay, hc = cx * cx + cy * cy, x = (cy * ha - ay * hc) / d, y = (ax * hc - cx * ha) / d, cy = y + by;
5384 var circle = d3_geom_voronoiCirclePool.pop() || new d3_geom_voronoiCircle();
5385 circle.arc = arc;
5386 circle.site = cSite;
5387 circle.x = x + bx;
5388 circle.y = cy + Math.sqrt(x * x + y * y);
5389 circle.cy = cy;
5390 arc.circle = circle;
5391 var before = null, node = d3_geom_voronoiCircles._;
5392 while (node) {
5393 if (circle.y < node.y || circle.y === node.y && circle.x <= node.x) {
5394 if (node.L) node = node.L; else {
5395 before = node.P;
5396 break;
5397 }
5398 } else {
5399 if (node.R) node = node.R; else {
5400 before = node;
5401 break;
5402 }
5403 }
5404 }
5405 d3_geom_voronoiCircles.insert(before, circle);
5406 if (!before) d3_geom_voronoiFirstCircle = circle;
5407 }
5408 function d3_geom_voronoiDetachCircle(arc) {
5409 var circle = arc.circle;
5410 if (circle) {
5411 if (!circle.P) d3_geom_voronoiFirstCircle = circle.N;
5412 d3_geom_voronoiCircles.remove(circle);
5413 d3_geom_voronoiCirclePool.push(circle);
5414 d3_geom_voronoiRedBlackNode(circle);
5415 arc.circle = null;
5416 }
5417 }
5418 function d3_geom_voronoiClipEdges(extent) {
5419 var edges = d3_geom_voronoiEdges, clip = d3_geom_clipLine(extent[0][0], extent[0][1], extent[1][0], extent[1][1]), i = edges.length, e;
5420 while (i--) {
5421 e = edges[i];
5422 if (!d3_geom_voronoiConnectEdge(e, extent) || !clip(e) || abs(e.a.x - e.b.x) < ε && abs(e.a.y - e.b.y) < ε) {
5423 e.a = e.b = null;
5424 edges.splice(i, 1);
5425 }
5426 }
5427 }
5428 function d3_geom_voronoiConnectEdge(edge, extent) {
5429 var vb = edge.b;
5430 if (vb) return true;
5431 var va = edge.a, x0 = extent[0][0], x1 = extent[1][0], y0 = extent[0][1], y1 = extent[1][1], lSite = edge.l, rSite = edge.r, lx = lSite.x, ly = lSite.y, rx = rSite.x, ry = rSite.y, fx = (lx + rx) / 2, fy = (ly + ry) / 2, fm, fb;
5432 if (ry === ly) {
5433 if (fx < x0 || fx >= x1) return;
5434 if (lx > rx) {
5435 if (!va) va = {
5436 x: fx,
5437 y: y0
5438 }; else if (va.y >= y1) return;
5439 vb = {
5440 x: fx,
5441 y: y1
5442 };
5443 } else {
5444 if (!va) va = {
5445 x: fx,
5446 y: y1
5447 }; else if (va.y < y0) return;
5448 vb = {
5449 x: fx,
5450 y: y0
5451 };
5452 }
5453 } else {
5454 fm = (lx - rx) / (ry - ly);
5455 fb = fy - fm * fx;
5456 if (fm < -1 || fm > 1) {
5457 if (lx > rx) {
5458 if (!va) va = {
5459 x: (y0 - fb) / fm,
5460 y: y0
5461 }; else if (va.y >= y1) return;
5462 vb = {
5463 x: (y1 - fb) / fm,
5464 y: y1
5465 };
5466 } else {
5467 if (!va) va = {
5468 x: (y1 - fb) / fm,
5469 y: y1
5470 }; else if (va.y < y0) return;
5471 vb = {
5472 x: (y0 - fb) / fm,
5473 y: y0
5474 };
5475 }
5476 } else {
5477 if (ly < ry) {
5478 if (!va) va = {
5479 x: x0,
5480 y: fm * x0 + fb
5481 }; else if (va.x >= x1) return;
5482 vb = {
5483 x: x1,
5484 y: fm * x1 + fb
5485 };
5486 } else {
5487 if (!va) va = {
5488 x: x1,
5489 y: fm * x1 + fb
5490 }; else if (va.x < x0) return;
5491 vb = {
5492 x: x0,
5493 y: fm * x0 + fb
5494 };
5495 }
5496 }
5497 }
5498 edge.a = va;
5499 edge.b = vb;
5500 return true;
5501 }
5502 function d3_geom_voronoiEdge(lSite, rSite) {
5503 this.l = lSite;
5504 this.r = rSite;
5505 this.a = this.b = null;
5506 }
5507 function d3_geom_voronoiCreateEdge(lSite, rSite, va, vb) {
5508 var edge = new d3_geom_voronoiEdge(lSite, rSite);
5509 d3_geom_voronoiEdges.push(edge);
5510 if (va) d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, va);
5511 if (vb) d3_geom_voronoiSetEdgeEnd(edge, rSite, lSite, vb);
5512 d3_geom_voronoiCells[lSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, lSite, rSite));
5513 d3_geom_voronoiCells[rSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, rSite, lSite));
5514 return edge;
5515 }
5516 function d3_geom_voronoiCreateBorderEdge(lSite, va, vb) {
5517 var edge = new d3_geom_voronoiEdge(lSite, null);
5518 edge.a = va;
5519 edge.b = vb;
5520 d3_geom_voronoiEdges.push(edge);
5521 return edge;
5522 }
5523 function d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, vertex) {
5524 if (!edge.a && !edge.b) {
5525 edge.a = vertex;
5526 edge.l = lSite;
5527 edge.r = rSite;
5528 } else if (edge.l === rSite) {
5529 edge.b = vertex;
5530 } else {
5531 edge.a = vertex;
5532 }
5533 }
5534 function d3_geom_voronoiHalfEdge(edge, lSite, rSite) {
5535 var va = edge.a, vb = edge.b;
5536 this.edge = edge;
5537 this.site = lSite;
5538 this.angle = rSite ? Math.atan2(rSite.y - lSite.y, rSite.x - lSite.x) : edge.l === lSite ? Math.atan2(vb.x - va.x, va.y - vb.y) : Math.atan2(va.x - vb.x, vb.y - va.y);
5539 }
5540 d3_geom_voronoiHalfEdge.prototype = {
5541 start: function() {
5542 return this.edge.l === this.site ? this.edge.a : this.edge.b;
5543 },
5544 end: function() {
5545 return this.edge.l === this.site ? this.edge.b : this.edge.a;
5546 }
5547 };
5548 function d3_geom_voronoiRedBlackTree() {
5549 this._ = null;
5550 }
5551 function d3_geom_voronoiRedBlackNode(node) {
5552 node.U = node.C = node.L = node.R = node.P = node.N = null;
5553 }
5554 d3_geom_voronoiRedBlackTree.prototype = {
5555 insert: function(after, node) {
5556 var parent, grandpa, uncle;
5557 if (after) {
5558 node.P = after;
5559 node.N = after.N;
5560 if (after.N) after.N.P = node;
5561 after.N = node;
5562 if (after.R) {
5563 after = after.R;
5564 while (after.L) after = after.L;
5565 after.L = node;
5566 } else {
5567 after.R = node;
5568 }
5569 parent = after;
5570 } else if (this._) {
5571 after = d3_geom_voronoiRedBlackFirst(this._);
5572 node.P = null;
5573 node.N = after;
5574 after.P = after.L = node;
5575 parent = after;
5576 } else {
5577 node.P = node.N = null;
5578 this._ = node;
5579 parent = null;
5580 }
5581 node.L = node.R = null;
5582 node.U = parent;
5583 node.C = true;
5584 after = node;
5585 while (parent && parent.C) {
5586 grandpa = parent.U;
5587 if (parent === grandpa.L) {
5588 uncle = grandpa.R;
5589 if (uncle && uncle.C) {
5590 parent.C = uncle.C = false;
5591 grandpa.C = true;
5592 after = grandpa;
5593 } else {
5594 if (after === parent.R) {
5595 d3_geom_voronoiRedBlackRotateLeft(this, parent);
5596 after = parent;
5597 parent = after.U;
5598 }
5599 parent.C = false;
5600 grandpa.C = true;
5601 d3_geom_voronoiRedBlackRotateRight(this, grandpa);
5602 }
5603 } else {
5604 uncle = grandpa.L;
5605 if (uncle && uncle.C) {
5606 parent.C = uncle.C = false;
5607 grandpa.C = true;
5608 after = grandpa;
5609 } else {
5610 if (after === parent.L) {
5611 d3_geom_voronoiRedBlackRotateRight(this, parent);
5612 after = parent;
5613 parent = after.U;
5614 }
5615 parent.C = false;
5616 grandpa.C = true;
5617 d3_geom_voronoiRedBlackRotateLeft(this, grandpa);
5618 }
5619 }
5620 parent = after.U;
5621 }
5622 this._.C = false;
5623 },
5624 remove: function(node) {
5625 if (node.N) node.N.P = node.P;
5626 if (node.P) node.P.N = node.N;
5627 node.N = node.P = null;
5628 var parent = node.U, sibling, left = node.L, right = node.R, next, red;
5629 if (!left) next = right; else if (!right) next = left; else next = d3_geom_voronoiRedBlackFirst(right);
5630 if (parent) {
5631 if (parent.L === node) parent.L = next; else parent.R = next;
5632 } else {
5633 this._ = next;
5634 }
5635 if (left && right) {
5636 red = next.C;
5637 next.C = node.C;
5638 next.L = left;
5639 left.U = next;
5640 if (next !== right) {
5641 parent = next.U;
5642 next.U = node.U;
5643 node = next.R;
5644 parent.L = node;
5645 next.R = right;
5646 right.U = next;
5647 } else {
5648 next.U = parent;
5649 parent = next;
5650 node = next.R;
5651 }
5652 } else {
5653 red = node.C;
5654 node = next;
5655 }
5656 if (node) node.U = parent;
5657 if (red) return;
5658 if (node && node.C) {
5659 node.C = false;
5660 return;
5661 }
5662 do {
5663 if (node === this._) break;
5664 if (node === parent.L) {
5665 sibling = parent.R;
5666 if (sibling.C) {
5667 sibling.C = false;
5668 parent.C = true;
5669 d3_geom_voronoiRedBlackRotateLeft(this, parent);
5670 sibling = parent.R;
5671 }
5672 if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) {
5673 if (!sibling.R || !sibling.R.C) {
5674 sibling.L.C = false;
5675 sibling.C = true;
5676 d3_geom_voronoiRedBlackRotateRight(this, sibling);
5677 sibling = parent.R;
5678 }
5679 sibling.C = parent.C;
5680 parent.C = sibling.R.C = false;
5681 d3_geom_voronoiRedBlackRotateLeft(this, parent);
5682 node = this._;
5683 break;
5684 }
5685 } else {
5686 sibling = parent.L;
5687 if (sibling.C) {
5688 sibling.C = false;
5689 parent.C = true;
5690 d3_geom_voronoiRedBlackRotateRight(this, parent);
5691 sibling = parent.L;
5692 }
5693 if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) {
5694 if (!sibling.L || !sibling.L.C) {
5695 sibling.R.C = false;
5696 sibling.C = true;
5697 d3_geom_voronoiRedBlackRotateLeft(this, sibling);
5698 sibling = parent.L;
5699 }
5700 sibling.C = parent.C;
5701 parent.C = sibling.L.C = false;
5702 d3_geom_voronoiRedBlackRotateRight(this, parent);
5703 node = this._;
5704 break;
5705 }
5706 }
5707 sibling.C = true;
5708 node = parent;
5709 parent = parent.U;
5710 } while (!node.C);
5711 if (node) node.C = false;
5712 }
5713 };
5714 function d3_geom_voronoiRedBlackRotateLeft(tree, node) {
5715 var p = node, q = node.R, parent = p.U;
5716 if (parent) {
5717 if (parent.L === p) parent.L = q; else parent.R = q;
5718 } else {
5719 tree._ = q;
5720 }
5721 q.U = parent;
5722 p.U = q;
5723 p.R = q.L;
5724 if (p.R) p.R.U = p;
5725 q.L = p;
5726 }
5727 function d3_geom_voronoiRedBlackRotateRight(tree, node) {
5728 var p = node, q = node.L, parent = p.U;
5729 if (parent) {
5730 if (parent.L === p) parent.L = q; else parent.R = q;
5731 } else {
5732 tree._ = q;
5733 }
5734 q.U = parent;
5735 p.U = q;
5736 p.L = q.R;
5737 if (p.L) p.L.U = p;
5738 q.R = p;
5739 }
5740 function d3_geom_voronoiRedBlackFirst(node) {
5741 while (node.L) node = node.L;
5742 return node;
5743 }
5744 function d3_geom_voronoi(sites, bbox) {
5745 var site = sites.sort(d3_geom_voronoiVertexOrder).pop(), x0, y0, circle;
5746 d3_geom_voronoiEdges = [];
5747 d3_geom_voronoiCells = new Array(sites.length);
5748 d3_geom_voronoiBeaches = new d3_geom_voronoiRedBlackTree();
5749 d3_geom_voronoiCircles = new d3_geom_voronoiRedBlackTree();
5750 while (true) {
5751 circle = d3_geom_voronoiFirstCircle;
5752 if (site && (!circle || site.y < circle.y || site.y === circle.y && site.x < circle.x)) {
5753 if (site.x !== x0 || site.y !== y0) {
5754 d3_geom_voronoiCells[site.i] = new d3_geom_voronoiCell(site);
5755 d3_geom_voronoiAddBeach(site);
5756 x0 = site.x, y0 = site.y;
5757 }
5758 site = sites.pop();
5759 } else if (circle) {
5760 d3_geom_voronoiRemoveBeach(circle.arc);
5761 } else {
5762 break;
5763 }
5764 }
5765 if (bbox) d3_geom_voronoiClipEdges(bbox), d3_geom_voronoiCloseCells(bbox);
5766 var diagram = {
5767 cells: d3_geom_voronoiCells,
5768 edges: d3_geom_voronoiEdges
5769 };
5770 d3_geom_voronoiBeaches = d3_geom_voronoiCircles = d3_geom_voronoiEdges = d3_geom_voronoiCells = null;
5771 return diagram;
5772 }
5773 function d3_geom_voronoiVertexOrder(a, b) {
5774 return b.y - a.y || b.x - a.x;
5775 }
5776 d3.geom.voronoi = function(points) {
5777 var x = d3_geom_pointX, y = d3_geom_pointY, fx = x, fy = y, clipExtent = d3_geom_voronoiClipExtent;
5778 if (points) return voronoi(points);
5779 function voronoi(data) {
5780 var polygons = new Array(data.length), x0 = clipExtent[0][0], y0 = clipExtent[0][1], x1 = clipExtent[1][0], y1 = clipExtent[1][1];
5781 d3_geom_voronoi(sites(data), clipExtent).cells.forEach(function(cell, i) {
5782 var edges = cell.edges, site = cell.site, polygon = polygons[i] = edges.length ? edges.map(function(e) {
5783 var s = e.start();
5784 return [ s.x, s.y ];
5785 }) : site.x >= x0 && site.x <= x1 && site.y >= y0 && site.y <= y1 ? [ [ x0, y1 ], [ x1, y1 ], [ x1, y0 ], [ x0, y0 ] ] : [];
5786 polygon.point = data[i];
5787 });
5788 return polygons;
5789 }
5790 function sites(data) {
5791 return data.map(function(d, i) {
5792 return {
5793 x: Math.round(fx(d, i) / ε) * ε,
5794 y: Math.round(fy(d, i) / ε) * ε,
5795 i: i
5796 };
5797 });
5798 }
5799 voronoi.links = function(data) {
5800 return d3_geom_voronoi(sites(data)).edges.filter(function(edge) {
5801 return edge.l && edge.r;
5802 }).map(function(edge) {
5803 return {
5804 source: data[edge.l.i],
5805 target: data[edge.r.i]
5806 };
5807 });
5808 };
5809 voronoi.triangles = function(data) {
5810 var triangles = [];
5811 d3_geom_voronoi(sites(data)).cells.forEach(function(cell, i) {
5812 var site = cell.site, edges = cell.edges.sort(d3_geom_voronoiHalfEdgeOrder), j = -1, m = edges.length, e0, s0, e1 = edges[m - 1].edge, s1 = e1.l === site ? e1.r : e1.l;
5813 while (++j < m) {
5814 e0 = e1;
5815 s0 = s1;
5816 e1 = edges[j].edge;
5817 s1 = e1.l === site ? e1.r : e1.l;
5818 if (i < s0.i && i < s1.i && d3_geom_voronoiTriangleArea(site, s0, s1) < 0) {
5819 triangles.push([ data[i], data[s0.i], data[s1.i] ]);
5820 }
5821 }
5822 });
5823 return triangles;
5824 };
5825 voronoi.x = function(_) {
5826 return arguments.length ? (fx = d3_functor(x = _), voronoi) : x;
5827 };
5828 voronoi.y = function(_) {
5829 return arguments.length ? (fy = d3_functor(y = _), voronoi) : y;
5830 };
5831 voronoi.clipExtent = function(_) {
5832 if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null : clipExtent;
5833 clipExtent = _ == null ? d3_geom_voronoiClipExtent : _;
5834 return voronoi;
5835 };
5836 voronoi.size = function(_) {
5837 if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null : clipExtent && clipExtent[1];
5838 return voronoi.clipExtent(_ && [ [ 0, 0 ], _ ]);
5839 };
5840 return voronoi;
5841 };
5842 var d3_geom_voronoiClipExtent = [ [ -1e6, -1e6 ], [ 1e6, 1e6 ] ];
5843 function d3_geom_voronoiTriangleArea(a, b, c) {
5844 return (a.x - c.x) * (b.y - a.y) - (a.x - b.x) * (c.y - a.y);
5845 }
5846 d3.geom.delaunay = function(vertices) {
5847 return d3.geom.voronoi().triangles(vertices);
5848 };
5849 d3.geom.quadtree = function(points, x1, y1, x2, y2) {
5850 var x = d3_geom_pointX, y = d3_geom_pointY, compat;
5851 if (compat = arguments.length) {
5852 x = d3_geom_quadtreeCompatX;
5853 y = d3_geom_quadtreeCompatY;
5854 if (compat === 3) {
5855 y2 = y1;
5856 x2 = x1;
5857 y1 = x1 = 0;
5858 }
5859 return quadtree(points);
5860 }
5861 function quadtree(data) {
5862 var d, fx = d3_functor(x), fy = d3_functor(y), xs, ys, i, n, x1_, y1_, x2_, y2_;
5863 if (x1 != null) {
5864 x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2;
5865 } else {
5866 x2_ = y2_ = -(x1_ = y1_ = Infinity);
5867 xs = [], ys = [];
5868 n = data.length;
5869 if (compat) for (i = 0; i < n; ++i) {
5870 d = data[i];
5871 if (d.x < x1_) x1_ = d.x;
5872 if (d.y < y1_) y1_ = d.y;
5873 if (d.x > x2_) x2_ = d.x;
5874 if (d.y > y2_) y2_ = d.y;
5875 xs.push(d.x);
5876 ys.push(d.y);
5877 } else for (i = 0; i < n; ++i) {
5878 var x_ = +fx(d = data[i], i), y_ = +fy(d, i);
5879 if (x_ < x1_) x1_ = x_;
5880 if (y_ < y1_) y1_ = y_;
5881 if (x_ > x2_) x2_ = x_;
5882 if (y_ > y2_) y2_ = y_;
5883 xs.push(x_);
5884 ys.push(y_);
5885 }
5886 }
5887 var dx = x2_ - x1_, dy = y2_ - y1_;
5888 if (dx > dy) y2_ = y1_ + dx; else x2_ = x1_ + dy;
5889 function insert(n, d, x, y, x1, y1, x2, y2) {
5890 if (isNaN(x) || isNaN(y)) return;
5891 if (n.leaf) {
5892 var nx = n.x, ny = n.y;
5893 if (nx != null) {
5894 if (abs(nx - x) + abs(ny - y) < .01) {
5895 insertChild(n, d, x, y, x1, y1, x2, y2);
5896 } else {
5897 var nPoint = n.point;
5898 n.x = n.y = n.point = null;
5899 insertChild(n, nPoint, nx, ny, x1, y1, x2, y2);
5900 insertChild(n, d, x, y, x1, y1, x2, y2);
5901 }
5902 } else {
5903 n.x = x, n.y = y, n.point = d;
5904 }
5905 } else {
5906 insertChild(n, d, x, y, x1, y1, x2, y2);
5907 }
5908 }
5909 function insertChild(n, d, x, y, x1, y1, x2, y2) {
5910 var xm = (x1 + x2) * .5, ym = (y1 + y2) * .5, right = x >= xm, below = y >= ym, i = below << 1 | right;
5911 n.leaf = false;
5912 n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode());
5913 if (right) x1 = xm; else x2 = xm;
5914 if (below) y1 = ym; else y2 = ym;
5915 insert(n, d, x, y, x1, y1, x2, y2);
5916 }
5917 var root = d3_geom_quadtreeNode();
5918 root.add = function(d) {
5919 insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_);
5920 };
5921 root.visit = function(f) {
5922 d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_);
5923 };
5924 root.find = function(point) {
5925 return d3_geom_quadtreeFind(root, point[0], point[1], x1_, y1_, x2_, y2_);
5926 };
5927 i = -1;
5928 if (x1 == null) {
5929 while (++i < n) {
5930 insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_);
5931 }
5932 --i;
5933 } else data.forEach(root.add);
5934 xs = ys = data = d = null;
5935 return root;
5936 }
5937 quadtree.x = function(_) {
5938 return arguments.length ? (x = _, quadtree) : x;
5939 };
5940 quadtree.y = function(_) {
5941 return arguments.length ? (y = _, quadtree) : y;
5942 };
5943 quadtree.extent = function(_) {
5944 if (!arguments.length) return x1 == null ? null : [ [ x1, y1 ], [ x2, y2 ] ];
5945 if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0],
5946 y2 = +_[1][1];
5947 return quadtree;
5948 };
5949 quadtree.size = function(_) {
5950 if (!arguments.length) return x1 == null ? null : [ x2 - x1, y2 - y1 ];
5951 if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = y1 = 0, x2 = +_[0], y2 = +_[1];
5952 return quadtree;
5953 };
5954 return quadtree;
5955 };
5956 function d3_geom_quadtreeCompatX(d) {
5957 return d.x;
5958 }
5959 function d3_geom_quadtreeCompatY(d) {
5960 return d.y;
5961 }
5962 function d3_geom_quadtreeNode() {
5963 return {
5964 leaf: true,
5965 nodes: [],
5966 point: null,
5967 x: null,
5968 y: null
5969 };
5970 }
5971 function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) {
5972 if (!f(node, x1, y1, x2, y2)) {
5973 var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes;
5974 if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy);
5975 if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy);
5976 if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2);
5977 if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2);
5978 }
5979 }
5980 function d3_geom_quadtreeFind(root, x, y, x0, y0, x3, y3) {
5981 var minDistance2 = Infinity, closestPoint;
5982 (function find(node, x1, y1, x2, y2) {
5983 if (x1 > x3 || y1 > y3 || x2 < x0 || y2 < y0) return;
5984 if (point = node.point) {
5985 var point, dx = x - point[0], dy = y - point[1], distance2 = dx * dx + dy * dy;
5986 if (distance2 < minDistance2) {
5987 var distance = Math.sqrt(minDistance2 = distance2);
5988 x0 = x - distance, y0 = y - distance;
5989 x3 = x + distance, y3 = y + distance;
5990 closestPoint = point;
5991 }
5992 }
5993 var children = node.nodes, xm = (x1 + x2) * .5, ym = (y1 + y2) * .5, right = x >= xm, below = y >= ym;
5994 for (var i = below << 1 | right, j = i + 4; i < j; ++i) {
5995 if (node = children[i & 3]) switch (i & 3) {
5996 case 0:
5997 find(node, x1, y1, xm, ym);
5998 break;
5999
6000 case 1:
6001 find(node, xm, y1, x2, ym);
6002 break;
6003
6004 case 2:
6005 find(node, x1, ym, xm, y2);
6006 break;
6007
6008 case 3:
6009 find(node, xm, ym, x2, y2);
6010 break;
6011 }
6012 }
6013 })(root, x0, y0, x3, y3);
6014 return closestPoint;
6015 }
6016 d3.interpolateRgb = d3_interpolateRgb;
6017 function d3_interpolateRgb(a, b) {
6018 a = d3.rgb(a);
6019 b = d3.rgb(b);
6020 var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab;
6021 return function(t) {
6022 return "#" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t));
6023 };
6024 }
6025 d3.interpolateObject = d3_interpolateObject;
6026 function d3_interpolateObject(a, b) {
6027 var i = {}, c = {}, k;
6028 for (k in a) {
6029 if (k in b) {
6030 i[k] = d3_interpolate(a[k], b[k]);
6031 } else {
6032 c[k] = a[k];
6033 }
6034 }
6035 for (k in b) {
6036 if (!(k in a)) {
6037 c[k] = b[k];
6038 }
6039 }
6040 return function(t) {
6041 for (k in i) c[k] = i[k](t);
6042 return c;
6043 };
6044 }
6045 d3.interpolateNumber = d3_interpolateNumber;
6046 function d3_interpolateNumber(a, b) {
6047 a = +a, b = +b;
6048 return function(t) {
6049 return a * (1 - t) + b * t;
6050 };
6051 }
6052 d3.interpolateString = d3_interpolateString;
6053 function d3_interpolateString(a, b) {
6054 var bi = d3_interpolate_numberA.lastIndex = d3_interpolate_numberB.lastIndex = 0, am, bm, bs, i = -1, s = [], q = [];
6055 a = a + "", b = b + "";
6056 while ((am = d3_interpolate_numberA.exec(a)) && (bm = d3_interpolate_numberB.exec(b))) {
6057 if ((bs = bm.index) > bi) {
6058 bs = b.slice(bi, bs);
6059 if (s[i]) s[i] += bs; else s[++i] = bs;
6060 }
6061 if ((am = am[0]) === (bm = bm[0])) {
6062 if (s[i]) s[i] += bm; else s[++i] = bm;
6063 } else {
6064 s[++i] = null;
6065 q.push({
6066 i: i,
6067 x: d3_interpolateNumber(am, bm)
6068 });
6069 }
6070 bi = d3_interpolate_numberB.lastIndex;
6071 }
6072 if (bi < b.length) {
6073 bs = b.slice(bi);
6074 if (s[i]) s[i] += bs; else s[++i] = bs;
6075 }
6076 return s.length < 2 ? q[0] ? (b = q[0].x, function(t) {
6077 return b(t) + "";
6078 }) : function() {
6079 return b;
6080 } : (b = q.length, function(t) {
6081 for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
6082 return s.join("");
6083 });
6084 }
6085 var d3_interpolate_numberA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g, d3_interpolate_numberB = new RegExp(d3_interpolate_numberA.source, "g");
6086 d3.interpolate = d3_interpolate;
6087 function d3_interpolate(a, b) {
6088 var i = d3.interpolators.length, f;
6089 while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ;
6090 return f;
6091 }
6092 d3.interpolators = [ function(a, b) {
6093 var t = typeof b;
6094 return (t === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) ? d3_interpolateRgb : d3_interpolateString : b instanceof d3_color ? d3_interpolateRgb : Array.isArray(b) ? d3_interpolateArray : t === "object" && isNaN(b) ? d3_interpolateObject : d3_interpolateNumber)(a, b);
6095 } ];
6096 d3.interpolateArray = d3_interpolateArray;
6097 function d3_interpolateArray(a, b) {
6098 var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i;
6099 for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i]));
6100 for (;i < na; ++i) c[i] = a[i];
6101 for (;i < nb; ++i) c[i] = b[i];
6102 return function(t) {
6103 for (i = 0; i < n0; ++i) c[i] = x[i](t);
6104 return c;
6105 };
6106 }
6107 var d3_ease_default = function() {
6108 return d3_identity;
6109 };
6110 var d3_ease = d3.map({
6111 linear: d3_ease_default,
6112 poly: d3_ease_poly,
6113 quad: function() {
6114 return d3_ease_quad;
6115 },
6116 cubic: function() {
6117 return d3_ease_cubic;
6118 },
6119 sin: function() {
6120 return d3_ease_sin;
6121 },
6122 exp: function() {
6123 return d3_ease_exp;
6124 },
6125 circle: function() {
6126 return d3_ease_circle;
6127 },
6128 elastic: d3_ease_elastic,
6129 back: d3_ease_back,
6130 bounce: function() {
6131 return d3_ease_bounce;
6132 }
6133 });
6134 var d3_ease_mode = d3.map({
6135 "in": d3_identity,
6136 out: d3_ease_reverse,
6137 "in-out": d3_ease_reflect,
6138 "out-in": function(f) {
6139 return d3_ease_reflect(d3_ease_reverse(f));
6140 }
6141 });
6142 d3.ease = function(name) {
6143 var i = name.indexOf("-"), t = i >= 0 ? name.slice(0, i) : name, m = i >= 0 ? name.slice(i + 1) : "in";
6144 t = d3_ease.get(t) || d3_ease_default;
6145 m = d3_ease_mode.get(m) || d3_identity;
6146 return d3_ease_clamp(m(t.apply(null, d3_arraySlice.call(arguments, 1))));
6147 };
6148 function d3_ease_clamp(f) {
6149 return function(t) {
6150 return t <= 0 ? 0 : t >= 1 ? 1 : f(t);
6151 };
6152 }
6153 function d3_ease_reverse(f) {
6154 return function(t) {
6155 return 1 - f(1 - t);
6156 };
6157 }
6158 function d3_ease_reflect(f) {
6159 return function(t) {
6160 return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t));
6161 };
6162 }
6163 function d3_ease_quad(t) {
6164 return t * t;
6165 }
6166 function d3_ease_cubic(t) {
6167 return t * t * t;
6168 }
6169 function d3_ease_cubicInOut(t) {
6170 if (t <= 0) return 0;
6171 if (t >= 1) return 1;
6172 var t2 = t * t, t3 = t2 * t;
6173 return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75);
6174 }
6175 function d3_ease_poly(e) {
6176 return function(t) {
6177 return Math.pow(t, e);
6178 };
6179 }
6180 function d3_ease_sin(t) {
6181 return 1 - Math.cos(t * halfπ);
6182 }
6183 function d3_ease_exp(t) {
6184 return Math.pow(2, 10 * (t - 1));
6185 }
6186 function d3_ease_circle(t) {
6187 return 1 - Math.sqrt(1 - t * t);
6188 }
6189 function d3_ease_elastic(a, p) {
6190 var s;
6191 if (arguments.length < 2) p = .45;
6192 if (arguments.length) s = p / τ * Math.asin(1 / a); else a = 1, s = p / 4;
6193 return function(t) {
6194 return 1 + a * Math.pow(2, -10 * t) * Math.sin((t - s) * τ / p);
6195 };
6196 }
6197 function d3_ease_back(s) {
6198 if (!s) s = 1.70158;
6199 return function(t) {
6200 return t * t * ((s + 1) * t - s);
6201 };
6202 }
6203 function d3_ease_bounce(t) {
6204 return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375;
6205 }
6206 d3.interpolateHcl = d3_interpolateHcl;
6207 function d3_interpolateHcl(a, b) {
6208 a = d3.hcl(a);
6209 b = d3.hcl(b);
6210 var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al;
6211 if (isNaN(bc)) bc = 0, ac = isNaN(ac) ? b.c : ac;
6212 if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360;
6213 return function(t) {
6214 return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + "";
6215 };
6216 }
6217 d3.interpolateHsl = d3_interpolateHsl;
6218 function d3_interpolateHsl(a, b) {
6219 a = d3.hsl(a);
6220 b = d3.hsl(b);
6221 var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al;
6222 if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as;
6223 if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360;
6224 return function(t) {
6225 return d3_hsl_rgb(ah + bh * t, as + bs * t, al + bl * t) + "";
6226 };
6227 }
6228 d3.interpolateLab = d3_interpolateLab;
6229 function d3_interpolateLab(a, b) {
6230 a = d3.lab(a);
6231 b = d3.lab(b);
6232 var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab;
6233 return function(t) {
6234 return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + "";
6235 };
6236 }
6237 d3.interpolateRound = d3_interpolateRound;
6238 function d3_interpolateRound(a, b) {
6239 b -= a;
6240 return function(t) {
6241 return Math.round(a + b * t);
6242 };
6243 }
6244 d3.transform = function(string) {
6245 var g = d3_document.createElementNS(d3.ns.prefix.svg, "g");
6246 return (d3.transform = function(string) {
6247 if (string != null) {
6248 g.setAttribute("transform", string);
6249 var t = g.transform.baseVal.consolidate();
6250 }
6251 return new d3_transform(t ? t.matrix : d3_transformIdentity);
6252 })(string);
6253 };
6254 function d3_transform(m) {
6255 var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0;
6256 if (r0[0] * r1[1] < r1[0] * r0[1]) {
6257 r0[0] *= -1;
6258 r0[1] *= -1;
6259 kx *= -1;
6260 kz *= -1;
6261 }
6262 this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees;
6263 this.translate = [ m.e, m.f ];
6264 this.scale = [ kx, ky ];
6265 this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0;
6266 }
6267 d3_transform.prototype.toString = function() {
6268 return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")";
6269 };
6270 function d3_transformDot(a, b) {
6271 return a[0] * b[0] + a[1] * b[1];
6272 }
6273 function d3_transformNormalize(a) {
6274 var k = Math.sqrt(d3_transformDot(a, a));
6275 if (k) {
6276 a[0] /= k;
6277 a[1] /= k;
6278 }
6279 return k;
6280 }
6281 function d3_transformCombine(a, b, k) {
6282 a[0] += k * b[0];
6283 a[1] += k * b[1];
6284 return a;
6285 }
6286 var d3_transformIdentity = {
6287 a: 1,
6288 b: 0,
6289 c: 0,
6290 d: 1,
6291 e: 0,
6292 f: 0
6293 };
6294 d3.interpolateTransform = d3_interpolateTransform;
6295 function d3_interpolateTransform(a, b) {
6296 var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale;
6297 if (ta[0] != tb[0] || ta[1] != tb[1]) {
6298 s.push("translate(", null, ",", null, ")");
6299 q.push({
6300 i: 1,
6301 x: d3_interpolateNumber(ta[0], tb[0])
6302 }, {
6303 i: 3,
6304 x: d3_interpolateNumber(ta[1], tb[1])
6305 });
6306 } else if (tb[0] || tb[1]) {
6307 s.push("translate(" + tb + ")");
6308 } else {
6309 s.push("");
6310 }
6311 if (ra != rb) {
6312 if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360;
6313 q.push({
6314 i: s.push(s.pop() + "rotate(", null, ")") - 2,
6315 x: d3_interpolateNumber(ra, rb)
6316 });
6317 } else if (rb) {
6318 s.push(s.pop() + "rotate(" + rb + ")");
6319 }
6320 if (wa != wb) {
6321 q.push({
6322 i: s.push(s.pop() + "skewX(", null, ")") - 2,
6323 x: d3_interpolateNumber(wa, wb)
6324 });
6325 } else if (wb) {
6326 s.push(s.pop() + "skewX(" + wb + ")");
6327 }
6328 if (ka[0] != kb[0] || ka[1] != kb[1]) {
6329 n = s.push(s.pop() + "scale(", null, ",", null, ")");
6330 q.push({
6331 i: n - 4,
6332 x: d3_interpolateNumber(ka[0], kb[0])
6333 }, {
6334 i: n - 2,
6335 x: d3_interpolateNumber(ka[1], kb[1])
6336 });
6337 } else if (kb[0] != 1 || kb[1] != 1) {
6338 s.push(s.pop() + "scale(" + kb + ")");
6339 }
6340 n = q.length;
6341 return function(t) {
6342 var i = -1, o;
6343 while (++i < n) s[(o = q[i]).i] = o.x(t);
6344 return s.join("");
6345 };
6346 }
6347 function d3_uninterpolateNumber(a, b) {
6348 b = (b -= a = +a) || 1 / b;
6349 return function(x) {
6350 return (x - a) / b;
6351 };
6352 }
6353 function d3_uninterpolateClamp(a, b) {
6354 b = (b -= a = +a) || 1 / b;
6355 return function(x) {
6356 return Math.max(0, Math.min(1, (x - a) / b));
6357 };
6358 }
6359 d3.layout = {};
6360 d3.layout.bundle = function() {
6361 return function(links) {
6362 var paths = [], i = -1, n = links.length;
6363 while (++i < n) paths.push(d3_layout_bundlePath(links[i]));
6364 return paths;
6365 };
6366 };
6367 function d3_layout_bundlePath(link) {
6368 var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ];
6369 while (start !== lca) {
6370 start = start.parent;
6371 points.push(start);
6372 }
6373 var k = points.length;
6374 while (end !== lca) {
6375 points.splice(k, 0, end);
6376 end = end.parent;
6377 }
6378 return points;
6379 }
6380 function d3_layout_bundleAncestors(node) {
6381 var ancestors = [], parent = node.parent;
6382 while (parent != null) {
6383 ancestors.push(node);
6384 node = parent;
6385 parent = parent.parent;
6386 }
6387 ancestors.push(node);
6388 return ancestors;
6389 }
6390 function d3_layout_bundleLeastCommonAncestor(a, b) {
6391 if (a === b) return a;
6392 var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null;
6393 while (aNode === bNode) {
6394 sharedNode = aNode;
6395 aNode = aNodes.pop();
6396 bNode = bNodes.pop();
6397 }
6398 return sharedNode;
6399 }
6400 d3.layout.chord = function() {
6401 var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords;
6402 function relayout() {
6403 var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j;
6404 chords = [];
6405 groups = [];
6406 k = 0, i = -1;
6407 while (++i < n) {
6408 x = 0, j = -1;
6409 while (++j < n) {
6410 x += matrix[i][j];
6411 }
6412 groupSums.push(x);
6413 subgroupIndex.push(d3.range(n));
6414 k += x;
6415 }
6416 if (sortGroups) {
6417 groupIndex.sort(function(a, b) {
6418 return sortGroups(groupSums[a], groupSums[b]);
6419 });
6420 }
6421 if (sortSubgroups) {
6422 subgroupIndex.forEach(function(d, i) {
6423 d.sort(function(a, b) {
6424 return sortSubgroups(matrix[i][a], matrix[i][b]);
6425 });
6426 });
6427 }
6428 k = (τ - padding * n) / k;
6429 x = 0, i = -1;
6430 while (++i < n) {
6431 x0 = x, j = -1;
6432 while (++j < n) {
6433 var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k;
6434 subgroups[di + "-" + dj] = {
6435 index: di,
6436 subindex: dj,
6437 startAngle: a0,
6438 endAngle: a1,
6439 value: v
6440 };
6441 }
6442 groups[di] = {
6443 index: di,
6444 startAngle: x0,
6445 endAngle: x,
6446 value: (x - x0) / k
6447 };
6448 x += padding;
6449 }
6450 i = -1;
6451 while (++i < n) {
6452 j = i - 1;
6453 while (++j < n) {
6454 var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i];
6455 if (source.value || target.value) {
6456 chords.push(source.value < target.value ? {
6457 source: target,
6458 target: source
6459 } : {
6460 source: source,
6461 target: target
6462 });
6463 }
6464 }
6465 }
6466 if (sortChords) resort();
6467 }
6468 function resort() {
6469 chords.sort(function(a, b) {
6470 return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2);
6471 });
6472 }
6473 chord.matrix = function(x) {
6474 if (!arguments.length) return matrix;
6475 n = (matrix = x) && matrix.length;
6476 chords = groups = null;
6477 return chord;
6478 };
6479 chord.padding = function(x) {
6480 if (!arguments.length) return padding;
6481 padding = x;
6482 chords = groups = null;
6483 return chord;
6484 };
6485 chord.sortGroups = function(x) {
6486 if (!arguments.length) return sortGroups;
6487 sortGroups = x;
6488 chords = groups = null;
6489 return chord;
6490 };
6491 chord.sortSubgroups = function(x) {
6492 if (!arguments.length) return sortSubgroups;
6493 sortSubgroups = x;
6494 chords = null;
6495 return chord;
6496 };
6497 chord.sortChords = function(x) {
6498 if (!arguments.length) return sortChords;
6499 sortChords = x;
6500 if (chords) resort();
6501 return chord;
6502 };
6503 chord.chords = function() {
6504 if (!chords) relayout();
6505 return chords;
6506 };
6507 chord.groups = function() {
6508 if (!groups) relayout();
6509 return groups;
6510 };
6511 return chord;
6512 };
6513 d3.layout.force = function() {
6514 var force = {}, event = d3.dispatch("start", "tick", "end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, chargeDistance2 = d3_layout_forceChargeDistance2, gravity = .1, theta2 = .64, nodes = [], links = [], distances, strengths, charges;
6515 function repulse(node) {
6516 return function(quad, x1, _, x2) {
6517 if (quad.point !== node) {
6518 var dx = quad.cx - node.x, dy = quad.cy - node.y, dw = x2 - x1, dn = dx * dx + dy * dy;
6519 if (dw * dw / theta2 < dn) {
6520 if (dn < chargeDistance2) {
6521 var k = quad.charge / dn;
6522 node.px -= dx * k;
6523 node.py -= dy * k;
6524 }
6525 return true;
6526 }
6527 if (quad.point && dn && dn < chargeDistance2) {
6528 var k = quad.pointCharge / dn;
6529 node.px -= dx * k;
6530 node.py -= dy * k;
6531 }
6532 }
6533 return !quad.charge;
6534 };
6535 }
6536 force.tick = function() {
6537 if ((alpha *= .99) < .005) {
6538 event.end({
6539 type: "end",
6540 alpha: alpha = 0
6541 });
6542 return true;
6543 }
6544 var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y;
6545 for (i = 0; i < m; ++i) {
6546 o = links[i];
6547 s = o.source;
6548 t = o.target;
6549 x = t.x - s.x;
6550 y = t.y - s.y;
6551 if (l = x * x + y * y) {
6552 l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l;
6553 x *= l;
6554 y *= l;
6555 t.x -= x * (k = s.weight / (t.weight + s.weight));
6556 t.y -= y * k;
6557 s.x += x * (k = 1 - k);
6558 s.y += y * k;
6559 }
6560 }
6561 if (k = alpha * gravity) {
6562 x = size[0] / 2;
6563 y = size[1] / 2;
6564 i = -1;
6565 if (k) while (++i < n) {
6566 o = nodes[i];
6567 o.x += (x - o.x) * k;
6568 o.y += (y - o.y) * k;
6569 }
6570 }
6571 if (charge) {
6572 d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges);
6573 i = -1;
6574 while (++i < n) {
6575 if (!(o = nodes[i]).fixed) {
6576 q.visit(repulse(o));
6577 }
6578 }
6579 }
6580 i = -1;
6581 while (++i < n) {
6582 o = nodes[i];
6583 if (o.fixed) {
6584 o.x = o.px;
6585 o.y = o.py;
6586 } else {
6587 o.x -= (o.px - (o.px = o.x)) * friction;
6588 o.y -= (o.py - (o.py = o.y)) * friction;
6589 }
6590 }
6591 event.tick({
6592 type: "tick",
6593 alpha: alpha
6594 });
6595 };
6596 force.nodes = function(x) {
6597 if (!arguments.length) return nodes;
6598 nodes = x;
6599 return force;
6600 };
6601 force.links = function(x) {
6602 if (!arguments.length) return links;
6603 links = x;
6604 return force;
6605 };
6606 force.size = function(x) {
6607 if (!arguments.length) return size;
6608 size = x;
6609 return force;
6610 };
6611 force.linkDistance = function(x) {
6612 if (!arguments.length) return linkDistance;
6613 linkDistance = typeof x === "function" ? x : +x;
6614 return force;
6615 };
6616 force.distance = force.linkDistance;
6617 force.linkStrength = function(x) {
6618 if (!arguments.length) return linkStrength;
6619 linkStrength = typeof x === "function" ? x : +x;
6620 return force;
6621 };
6622 force.friction = function(x) {
6623 if (!arguments.length) return friction;
6624 friction = +x;
6625 return force;
6626 };
6627 force.charge = function(x) {
6628 if (!arguments.length) return charge;
6629 charge = typeof x === "function" ? x : +x;
6630 return force;
6631 };
6632 force.chargeDistance = function(x) {
6633 if (!arguments.length) return Math.sqrt(chargeDistance2);
6634 chargeDistance2 = x * x;
6635 return force;
6636 };
6637 force.gravity = function(x) {
6638 if (!arguments.length) return gravity;
6639 gravity = +x;
6640 return force;
6641 };
6642 force.theta = function(x) {
6643 if (!arguments.length) return Math.sqrt(theta2);
6644 theta2 = x * x;
6645 return force;
6646 };
6647 force.alpha = function(x) {
6648 if (!arguments.length) return alpha;
6649 x = +x;
6650 if (alpha) {
6651 if (x > 0) alpha = x; else alpha = 0;
6652 } else if (x > 0) {
6653 event.start({
6654 type: "start",
6655 alpha: alpha = x
6656 });
6657 d3.timer(force.tick);
6658 }
6659 return force;
6660 };
6661 force.start = function() {
6662 var i, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o;
6663 for (i = 0; i < n; ++i) {
6664 (o = nodes[i]).index = i;
6665 o.weight = 0;
6666 }
6667 for (i = 0; i < m; ++i) {
6668 o = links[i];
6669 if (typeof o.source == "number") o.source = nodes[o.source];
6670 if (typeof o.target == "number") o.target = nodes[o.target];
6671 ++o.source.weight;
6672 ++o.target.weight;
6673 }
6674 for (i = 0; i < n; ++i) {
6675 o = nodes[i];
6676 if (isNaN(o.x)) o.x = position("x", w);
6677 if (isNaN(o.y)) o.y = position("y", h);
6678 if (isNaN(o.px)) o.px = o.x;
6679 if (isNaN(o.py)) o.py = o.y;
6680 }
6681 distances = [];
6682 if (typeof linkDistance === "function") for (i = 0; i < m; ++i) distances[i] = +linkDistance.call(this, links[i], i); else for (i = 0; i < m; ++i) distances[i] = linkDistance;
6683 strengths = [];
6684 if (typeof linkStrength === "function") for (i = 0; i < m; ++i) strengths[i] = +linkStrength.call(this, links[i], i); else for (i = 0; i < m; ++i) strengths[i] = linkStrength;
6685 charges = [];
6686 if (typeof charge === "function") for (i = 0; i < n; ++i) charges[i] = +charge.call(this, nodes[i], i); else for (i = 0; i < n; ++i) charges[i] = charge;
6687 function position(dimension, size) {
6688 if (!neighbors) {
6689 neighbors = new Array(n);
6690 for (j = 0; j < n; ++j) {
6691 neighbors[j] = [];
6692 }
6693 for (j = 0; j < m; ++j) {
6694 var o = links[j];
6695 neighbors[o.source.index].push(o.target);
6696 neighbors[o.target.index].push(o.source);
6697 }
6698 }
6699 var candidates = neighbors[i], j = -1, m = candidates.length, x;
6700 while (++j < m) if (!isNaN(x = candidates[j][dimension])) return x;
6701 return Math.random() * size;
6702 }
6703 return force.resume();
6704 };
6705 force.resume = function() {
6706 return force.alpha(.1);
6707 };
6708 force.stop = function() {
6709 return force.alpha(0);
6710 };
6711 force.drag = function() {
6712 if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart.force", d3_layout_forceDragstart).on("drag.force", dragmove).on("dragend.force", d3_layout_forceDragend);
6713 if (!arguments.length) return drag;
6714 this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag);
6715 };
6716 function dragmove(d) {
6717 d.px = d3.event.x, d.py = d3.event.y;
6718 force.resume();
6719 }
6720 return d3.rebind(force, event, "on");
6721 };
6722 function d3_layout_forceDragstart(d) {
6723 d.fixed |= 2;
6724 }
6725 function d3_layout_forceDragend(d) {
6726 d.fixed &= ~6;
6727 }
6728 function d3_layout_forceMouseover(d) {
6729 d.fixed |= 4;
6730 d.px = d.x, d.py = d.y;
6731 }
6732 function d3_layout_forceMouseout(d) {
6733 d.fixed &= ~4;
6734 }
6735 function d3_layout_forceAccumulate(quad, alpha, charges) {
6736 var cx = 0, cy = 0;
6737 quad.charge = 0;
6738 if (!quad.leaf) {
6739 var nodes = quad.nodes, n = nodes.length, i = -1, c;
6740 while (++i < n) {
6741 c = nodes[i];
6742 if (c == null) continue;
6743 d3_layout_forceAccumulate(c, alpha, charges);
6744 quad.charge += c.charge;
6745 cx += c.charge * c.cx;
6746 cy += c.charge * c.cy;
6747 }
6748 }
6749 if (quad.point) {
6750 if (!quad.leaf) {
6751 quad.point.x += Math.random() - .5;
6752 quad.point.y += Math.random() - .5;
6753 }
6754 var k = alpha * charges[quad.point.index];
6755 quad.charge += quad.pointCharge = k;
6756 cx += k * quad.point.x;
6757 cy += k * quad.point.y;
6758 }
6759 quad.cx = cx / quad.charge;
6760 quad.cy = cy / quad.charge;
6761 }
6762 var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1, d3_layout_forceChargeDistance2 = Infinity;
6763 d3.layout.hierarchy = function() {
6764 var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue;
6765 function hierarchy(root) {
6766 var stack = [ root ], nodes = [], node;
6767 root.depth = 0;
6768 while ((node = stack.pop()) != null) {
6769 nodes.push(node);
6770 if ((childs = children.call(hierarchy, node, node.depth)) && (n = childs.length)) {
6771 var n, childs, child;
6772 while (--n >= 0) {
6773 stack.push(child = childs[n]);
6774 child.parent = node;
6775 child.depth = node.depth + 1;
6776 }
6777 if (value) node.value = 0;
6778 node.children = childs;
6779 } else {
6780 if (value) node.value = +value.call(hierarchy, node, node.depth) || 0;
6781 delete node.children;
6782 }
6783 }
6784 d3_layout_hierarchyVisitAfter(root, function(node) {
6785 var childs, parent;
6786 if (sort && (childs = node.children)) childs.sort(sort);
6787 if (value && (parent = node.parent)) parent.value += node.value;
6788 });
6789 return nodes;
6790 }
6791 hierarchy.sort = function(x) {
6792 if (!arguments.length) return sort;
6793 sort = x;
6794 return hierarchy;
6795 };
6796 hierarchy.children = function(x) {
6797 if (!arguments.length) return children;
6798 children = x;
6799 return hierarchy;
6800 };
6801 hierarchy.value = function(x) {
6802 if (!arguments.length) return value;
6803 value = x;
6804 return hierarchy;
6805 };
6806 hierarchy.revalue = function(root) {
6807 if (value) {
6808 d3_layout_hierarchyVisitBefore(root, function(node) {
6809 if (node.children) node.value = 0;
6810 });
6811 d3_layout_hierarchyVisitAfter(root, function(node) {
6812 var parent;
6813 if (!node.children) node.value = +value.call(hierarchy, node, node.depth) || 0;
6814 if (parent = node.parent) parent.value += node.value;
6815 });
6816 }
6817 return root;
6818 };
6819 return hierarchy;
6820 };
6821 function d3_layout_hierarchyRebind(object, hierarchy) {
6822 d3.rebind(object, hierarchy, "sort", "children", "value");
6823 object.nodes = object;
6824 object.links = d3_layout_hierarchyLinks;
6825 return object;
6826 }
6827 function d3_layout_hierarchyVisitBefore(node, callback) {
6828 var nodes = [ node ];
6829 while ((node = nodes.pop()) != null) {
6830 callback(node);
6831 if ((children = node.children) && (n = children.length)) {
6832 var n, children;
6833 while (--n >= 0) nodes.push(children[n]);
6834 }
6835 }
6836 }
6837 function d3_layout_hierarchyVisitAfter(node, callback) {
6838 var nodes = [ node ], nodes2 = [];
6839 while ((node = nodes.pop()) != null) {
6840 nodes2.push(node);
6841 if ((children = node.children) && (n = children.length)) {
6842 var i = -1, n, children;
6843 while (++i < n) nodes.push(children[i]);
6844 }
6845 }
6846 while ((node = nodes2.pop()) != null) {
6847 callback(node);
6848 }
6849 }
6850 function d3_layout_hierarchyChildren(d) {
6851 return d.children;
6852 }
6853 function d3_layout_hierarchyValue(d) {
6854 return d.value;
6855 }
6856 function d3_layout_hierarchySort(a, b) {
6857 return b.value - a.value;
6858 }
6859 function d3_layout_hierarchyLinks(nodes) {
6860 return d3.merge(nodes.map(function(parent) {
6861 return (parent.children || []).map(function(child) {
6862 return {
6863 source: parent,
6864 target: child
6865 };
6866 });
6867 }));
6868 }
6869 d3.layout.partition = function() {
6870 var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ];
6871 function position(node, x, dx, dy) {
6872 var children = node.children;
6873 node.x = x;
6874 node.y = node.depth * dy;
6875 node.dx = dx;
6876 node.dy = dy;
6877 if (children && (n = children.length)) {
6878 var i = -1, n, c, d;
6879 dx = node.value ? dx / node.value : 0;
6880 while (++i < n) {
6881 position(c = children[i], x, d = c.value * dx, dy);
6882 x += d;
6883 }
6884 }
6885 }
6886 function depth(node) {
6887 var children = node.children, d = 0;
6888 if (children && (n = children.length)) {
6889 var i = -1, n;
6890 while (++i < n) d = Math.max(d, depth(children[i]));
6891 }
6892 return 1 + d;
6893 }
6894 function partition(d, i) {
6895 var nodes = hierarchy.call(this, d, i);
6896 position(nodes[0], 0, size[0], size[1] / depth(nodes[0]));
6897 return nodes;
6898 }
6899 partition.size = function(x) {
6900 if (!arguments.length) return size;
6901 size = x;
6902 return partition;
6903 };
6904 return d3_layout_hierarchyRebind(partition, hierarchy);
6905 };
6906 d3.layout.pie = function() {
6907 var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = τ, padAngle = 0;
6908 function pie(data) {
6909 var n = data.length, values = data.map(function(d, i) {
6910 return +value.call(pie, d, i);
6911 }), a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle), da = (typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - a, p = Math.min(Math.abs(da) / n, +(typeof padAngle === "function" ? padAngle.apply(this, arguments) : padAngle)), pa = p * (da < 0 ? -1 : 1), k = (da - n * pa) / d3.sum(values), index = d3.range(n), arcs = [], v;
6912 if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) {
6913 return values[j] - values[i];
6914 } : function(i, j) {
6915 return sort(data[i], data[j]);
6916 });
6917 index.forEach(function(i) {
6918 arcs[i] = {
6919 data: data[i],
6920 value: v = values[i],
6921 startAngle: a,
6922 endAngle: a += v * k + pa,
6923 padAngle: p
6924 };
6925 });
6926 return arcs;
6927 }
6928 pie.value = function(_) {
6929 if (!arguments.length) return value;
6930 value = _;
6931 return pie;
6932 };
6933 pie.sort = function(_) {
6934 if (!arguments.length) return sort;
6935 sort = _;
6936 return pie;
6937 };
6938 pie.startAngle = function(_) {
6939 if (!arguments.length) return startAngle;
6940 startAngle = _;
6941 return pie;
6942 };
6943 pie.endAngle = function(_) {
6944 if (!arguments.length) return endAngle;
6945 endAngle = _;
6946 return pie;
6947 };
6948 pie.padAngle = function(_) {
6949 if (!arguments.length) return padAngle;
6950 padAngle = _;
6951 return pie;
6952 };
6953 return pie;
6954 };
6955 var d3_layout_pieSortByValue = {};
6956 d3.layout.stack = function() {
6957 var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY;
6958 function stack(data, index) {
6959 if (!(n = data.length)) return data;
6960 var series = data.map(function(d, i) {
6961 return values.call(stack, d, i);
6962 });
6963 var points = series.map(function(d) {
6964 return d.map(function(v, i) {
6965 return [ x.call(stack, v, i), y.call(stack, v, i) ];
6966 });
6967 });
6968 var orders = order.call(stack, points, index);
6969 series = d3.permute(series, orders);
6970 points = d3.permute(points, orders);
6971 var offsets = offset.call(stack, points, index);
6972 var m = series[0].length, n, i, j, o;
6973 for (j = 0; j < m; ++j) {
6974 out.call(stack, series[0][j], o = offsets[j], points[0][j][1]);
6975 for (i = 1; i < n; ++i) {
6976 out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]);
6977 }
6978 }
6979 return data;
6980 }
6981 stack.values = function(x) {
6982 if (!arguments.length) return values;
6983 values = x;
6984 return stack;
6985 };
6986 stack.order = function(x) {
6987 if (!arguments.length) return order;
6988 order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault;
6989 return stack;
6990 };
6991 stack.offset = function(x) {
6992 if (!arguments.length) return offset;
6993 offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero;
6994 return stack;
6995 };
6996 stack.x = function(z) {
6997 if (!arguments.length) return x;
6998 x = z;
6999 return stack;
7000 };
7001 stack.y = function(z) {
7002 if (!arguments.length) return y;
7003 y = z;
7004 return stack;
7005 };
7006 stack.out = function(z) {
7007 if (!arguments.length) return out;
7008 out = z;
7009 return stack;
7010 };
7011 return stack;
7012 };
7013 function d3_layout_stackX(d) {
7014 return d.x;
7015 }
7016 function d3_layout_stackY(d) {
7017 return d.y;
7018 }
7019 function d3_layout_stackOut(d, y0, y) {
7020 d.y0 = y0;
7021 d.y = y;
7022 }
7023 var d3_layout_stackOrders = d3.map({
7024 "inside-out": function(data) {
7025 var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) {
7026 return max[a] - max[b];
7027 }), top = 0, bottom = 0, tops = [], bottoms = [];
7028 for (i = 0; i < n; ++i) {
7029 j = index[i];
7030 if (top < bottom) {
7031 top += sums[j];
7032 tops.push(j);
7033 } else {
7034 bottom += sums[j];
7035 bottoms.push(j);
7036 }
7037 }
7038 return bottoms.reverse().concat(tops);
7039 },
7040 reverse: function(data) {
7041 return d3.range(data.length).reverse();
7042 },
7043 "default": d3_layout_stackOrderDefault
7044 });
7045 var d3_layout_stackOffsets = d3.map({
7046 silhouette: function(data) {
7047 var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = [];
7048 for (j = 0; j < m; ++j) {
7049 for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
7050 if (o > max) max = o;
7051 sums.push(o);
7052 }
7053 for (j = 0; j < m; ++j) {
7054 y0[j] = (max - sums[j]) / 2;
7055 }
7056 return y0;
7057 },
7058 wiggle: function(data) {
7059 var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = [];
7060 y0[0] = o = o0 = 0;
7061 for (j = 1; j < m; ++j) {
7062 for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1];
7063 for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) {
7064 for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) {
7065 s3 += (data[k][j][1] - data[k][j - 1][1]) / dx;
7066 }
7067 s2 += s3 * data[i][j][1];
7068 }
7069 y0[j] = o -= s1 ? s2 / s1 * dx : 0;
7070 if (o < o0) o0 = o;
7071 }
7072 for (j = 0; j < m; ++j) y0[j] -= o0;
7073 return y0;
7074 },
7075 expand: function(data) {
7076 var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = [];
7077 for (j = 0; j < m; ++j) {
7078 for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
7079 if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k;
7080 }
7081 for (j = 0; j < m; ++j) y0[j] = 0;
7082 return y0;
7083 },
7084 zero: d3_layout_stackOffsetZero
7085 });
7086 function d3_layout_stackOrderDefault(data) {
7087 return d3.range(data.length);
7088 }
7089 function d3_layout_stackOffsetZero(data) {
7090 var j = -1, m = data[0].length, y0 = [];
7091 while (++j < m) y0[j] = 0;
7092 return y0;
7093 }
7094 function d3_layout_stackMaxIndex(array) {
7095 var i = 1, j = 0, v = array[0][1], k, n = array.length;
7096 for (;i < n; ++i) {
7097 if ((k = array[i][1]) > v) {
7098 j = i;
7099 v = k;
7100 }
7101 }
7102 return j;
7103 }
7104 function d3_layout_stackReduceSum(d) {
7105 return d.reduce(d3_layout_stackSum, 0);
7106 }
7107 function d3_layout_stackSum(p, d) {
7108 return p + d[1];
7109 }
7110 d3.layout.histogram = function() {
7111 var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges;
7112 function histogram(data, i) {
7113 var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x;
7114 while (++i < m) {
7115 bin = bins[i] = [];
7116 bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]);
7117 bin.y = 0;
7118 }
7119 if (m > 0) {
7120 i = -1;
7121 while (++i < n) {
7122 x = values[i];
7123 if (x >= range[0] && x <= range[1]) {
7124 bin = bins[d3.bisect(thresholds, x, 1, m) - 1];
7125 bin.y += k;
7126 bin.push(data[i]);
7127 }
7128 }
7129 }
7130 return bins;
7131 }
7132 histogram.value = function(x) {
7133 if (!arguments.length) return valuer;
7134 valuer = x;
7135 return histogram;
7136 };
7137 histogram.range = function(x) {
7138 if (!arguments.length) return ranger;
7139 ranger = d3_functor(x);
7140 return histogram;
7141 };
7142 histogram.bins = function(x) {
7143 if (!arguments.length) return binner;
7144 binner = typeof x === "number" ? function(range) {
7145 return d3_layout_histogramBinFixed(range, x);
7146 } : d3_functor(x);
7147 return histogram;
7148 };
7149 histogram.frequency = function(x) {
7150 if (!arguments.length) return frequency;
7151 frequency = !!x;
7152 return histogram;
7153 };
7154 return histogram;
7155 };
7156 function d3_layout_histogramBinSturges(range, values) {
7157 return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1));
7158 }
7159 function d3_layout_histogramBinFixed(range, n) {
7160 var x = -1, b = +range[0], m = (range[1] - b) / n, f = [];
7161 while (++x <= n) f[x] = m * x + b;
7162 return f;
7163 }
7164 function d3_layout_histogramRange(values) {
7165 return [ d3.min(values), d3.max(values) ];
7166 }
7167 d3.layout.pack = function() {
7168 var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ], radius;
7169 function pack(d, i) {
7170 var nodes = hierarchy.call(this, d, i), root = nodes[0], w = size[0], h = size[1], r = radius == null ? Math.sqrt : typeof radius === "function" ? radius : function() {
7171 return radius;
7172 };
7173 root.x = root.y = 0;
7174 d3_layout_hierarchyVisitAfter(root, function(d) {
7175 d.r = +r(d.value);
7176 });
7177 d3_layout_hierarchyVisitAfter(root, d3_layout_packSiblings);
7178 if (padding) {
7179 var dr = padding * (radius ? 1 : Math.max(2 * root.r / w, 2 * root.r / h)) / 2;
7180 d3_layout_hierarchyVisitAfter(root, function(d) {
7181 d.r += dr;
7182 });
7183 d3_layout_hierarchyVisitAfter(root, d3_layout_packSiblings);
7184 d3_layout_hierarchyVisitAfter(root, function(d) {
7185 d.r -= dr;
7186 });
7187 }
7188 d3_layout_packTransform(root, w / 2, h / 2, radius ? 1 : 1 / Math.max(2 * root.r / w, 2 * root.r / h));
7189 return nodes;
7190 }
7191 pack.size = function(_) {
7192 if (!arguments.length) return size;
7193 size = _;
7194 return pack;
7195 };
7196 pack.radius = function(_) {
7197 if (!arguments.length) return radius;
7198 radius = _ == null || typeof _ === "function" ? _ : +_;
7199 return pack;
7200 };
7201 pack.padding = function(_) {
7202 if (!arguments.length) return padding;
7203 padding = +_;
7204 return pack;
7205 };
7206 return d3_layout_hierarchyRebind(pack, hierarchy);
7207 };
7208 function d3_layout_packSort(a, b) {
7209 return a.value - b.value;
7210 }
7211 function d3_layout_packInsert(a, b) {
7212 var c = a._pack_next;
7213 a._pack_next = b;
7214 b._pack_prev = a;
7215 b._pack_next = c;
7216 c._pack_prev = b;
7217 }
7218 function d3_layout_packSplice(a, b) {
7219 a._pack_next = b;
7220 b._pack_prev = a;
7221 }
7222 function d3_layout_packIntersects(a, b) {
7223 var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r;
7224 return .999 * dr * dr > dx * dx + dy * dy;
7225 }
7226 function d3_layout_packSiblings(node) {
7227 if (!(nodes = node.children) || !(n = nodes.length)) return;
7228 var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n;
7229 function bound(node) {
7230 xMin = Math.min(node.x - node.r, xMin);
7231 xMax = Math.max(node.x + node.r, xMax);
7232 yMin = Math.min(node.y - node.r, yMin);
7233 yMax = Math.max(node.y + node.r, yMax);
7234 }
7235 nodes.forEach(d3_layout_packLink);
7236 a = nodes[0];
7237 a.x = -a.r;
7238 a.y = 0;
7239 bound(a);
7240 if (n > 1) {
7241 b = nodes[1];
7242 b.x = b.r;
7243 b.y = 0;
7244 bound(b);
7245 if (n > 2) {
7246 c = nodes[2];
7247 d3_layout_packPlace(a, b, c);
7248 bound(c);
7249 d3_layout_packInsert(a, c);
7250 a._pack_prev = c;
7251 d3_layout_packInsert(c, b);
7252 b = a._pack_next;
7253 for (i = 3; i < n; i++) {
7254 d3_layout_packPlace(a, b, c = nodes[i]);
7255 var isect = 0, s1 = 1, s2 = 1;
7256 for (j = b._pack_next; j !== b; j = j._pack_next, s1++) {
7257 if (d3_layout_packIntersects(j, c)) {
7258 isect = 1;
7259 break;
7260 }
7261 }
7262 if (isect == 1) {
7263 for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) {
7264 if (d3_layout_packIntersects(k, c)) {
7265 break;
7266 }
7267 }
7268 }
7269 if (isect) {
7270 if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b);
7271 i--;
7272 } else {
7273 d3_layout_packInsert(a, c);
7274 b = c;
7275 bound(c);
7276 }
7277 }
7278 }
7279 }
7280 var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0;
7281 for (i = 0; i < n; i++) {
7282 c = nodes[i];
7283 c.x -= cx;
7284 c.y -= cy;
7285 cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y));
7286 }
7287 node.r = cr;
7288 nodes.forEach(d3_layout_packUnlink);
7289 }
7290 function d3_layout_packLink(node) {
7291 node._pack_next = node._pack_prev = node;
7292 }
7293 function d3_layout_packUnlink(node) {
7294 delete node._pack_next;
7295 delete node._pack_prev;
7296 }
7297 function d3_layout_packTransform(node, x, y, k) {
7298 var children = node.children;
7299 node.x = x += k * node.x;
7300 node.y = y += k * node.y;
7301 node.r *= k;
7302 if (children) {
7303 var i = -1, n = children.length;
7304 while (++i < n) d3_layout_packTransform(children[i], x, y, k);
7305 }
7306 }
7307 function d3_layout_packPlace(a, b, c) {
7308 var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y;
7309 if (db && (dx || dy)) {
7310 var da = b.r + c.r, dc = dx * dx + dy * dy;
7311 da *= da;
7312 db *= db;
7313 var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc);
7314 c.x = a.x + x * dx + y * dy;
7315 c.y = a.y + x * dy - y * dx;
7316 } else {
7317 c.x = a.x + db;
7318 c.y = a.y;
7319 }
7320 }
7321 d3.layout.tree = function() {
7322 var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = null;
7323 function tree(d, i) {
7324 var nodes = hierarchy.call(this, d, i), root0 = nodes[0], root1 = wrapTree(root0);
7325 d3_layout_hierarchyVisitAfter(root1, firstWalk), root1.parent.m = -root1.z;
7326 d3_layout_hierarchyVisitBefore(root1, secondWalk);
7327 if (nodeSize) d3_layout_hierarchyVisitBefore(root0, sizeNode); else {
7328 var left = root0, right = root0, bottom = root0;
7329 d3_layout_hierarchyVisitBefore(root0, function(node) {
7330 if (node.x < left.x) left = node;
7331 if (node.x > right.x) right = node;
7332 if (node.depth > bottom.depth) bottom = node;
7333 });
7334 var tx = separation(left, right) / 2 - left.x, kx = size[0] / (right.x + separation(right, left) / 2 + tx), ky = size[1] / (bottom.depth || 1);
7335 d3_layout_hierarchyVisitBefore(root0, function(node) {
7336 node.x = (node.x + tx) * kx;
7337 node.y = node.depth * ky;
7338 });
7339 }
7340 return nodes;
7341 }
7342 function wrapTree(root0) {
7343 var root1 = {
7344 A: null,
7345 children: [ root0 ]
7346 }, queue = [ root1 ], node1;
7347 while ((node1 = queue.pop()) != null) {
7348 for (var children = node1.children, child, i = 0, n = children.length; i < n; ++i) {
7349 queue.push((children[i] = child = {
7350 _: children[i],
7351 parent: node1,
7352 children: (child = children[i].children) && child.slice() || [],
7353 A: null,
7354 a: null,
7355 z: 0,
7356 m: 0,
7357 c: 0,
7358 s: 0,
7359 t: null,
7360 i: i
7361 }).a = child);
7362 }
7363 }
7364 return root1.children[0];
7365 }
7366 function firstWalk(v) {
7367 var children = v.children, siblings = v.parent.children, w = v.i ? siblings[v.i - 1] : null;
7368 if (children.length) {
7369 d3_layout_treeShift(v);
7370 var midpoint = (children[0].z + children[children.length - 1].z) / 2;
7371 if (w) {
7372 v.z = w.z + separation(v._, w._);
7373 v.m = v.z - midpoint;
7374 } else {
7375 v.z = midpoint;
7376 }
7377 } else if (w) {
7378 v.z = w.z + separation(v._, w._);
7379 }
7380 v.parent.A = apportion(v, w, v.parent.A || siblings[0]);
7381 }
7382 function secondWalk(v) {
7383 v._.x = v.z + v.parent.m;
7384 v.m += v.parent.m;
7385 }
7386 function apportion(v, w, ancestor) {
7387 if (w) {
7388 var vip = v, vop = v, vim = w, vom = vip.parent.children[0], sip = vip.m, sop = vop.m, sim = vim.m, som = vom.m, shift;
7389 while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) {
7390 vom = d3_layout_treeLeft(vom);
7391 vop = d3_layout_treeRight(vop);
7392 vop.a = v;
7393 shift = vim.z + sim - vip.z - sip + separation(vim._, vip._);
7394 if (shift > 0) {
7395 d3_layout_treeMove(d3_layout_treeAncestor(vim, v, ancestor), v, shift);
7396 sip += shift;
7397 sop += shift;
7398 }
7399 sim += vim.m;
7400 sip += vip.m;
7401 som += vom.m;
7402 sop += vop.m;
7403 }
7404 if (vim && !d3_layout_treeRight(vop)) {
7405 vop.t = vim;
7406 vop.m += sim - sop;
7407 }
7408 if (vip && !d3_layout_treeLeft(vom)) {
7409 vom.t = vip;
7410 vom.m += sip - som;
7411 ancestor = v;
7412 }
7413 }
7414 return ancestor;
7415 }
7416 function sizeNode(node) {
7417 node.x *= size[0];
7418 node.y = node.depth * size[1];
7419 }
7420 tree.separation = function(x) {
7421 if (!arguments.length) return separation;
7422 separation = x;
7423 return tree;
7424 };
7425 tree.size = function(x) {
7426 if (!arguments.length) return nodeSize ? null : size;
7427 nodeSize = (size = x) == null ? sizeNode : null;
7428 return tree;
7429 };
7430 tree.nodeSize = function(x) {
7431 if (!arguments.length) return nodeSize ? size : null;
7432 nodeSize = (size = x) == null ? null : sizeNode;
7433 return tree;
7434 };
7435 return d3_layout_hierarchyRebind(tree, hierarchy);
7436 };
7437 function d3_layout_treeSeparation(a, b) {
7438 return a.parent == b.parent ? 1 : 2;
7439 }
7440 function d3_layout_treeLeft(v) {
7441 var children = v.children;
7442 return children.length ? children[0] : v.t;
7443 }
7444 function d3_layout_treeRight(v) {
7445 var children = v.children, n;
7446 return (n = children.length) ? children[n - 1] : v.t;
7447 }
7448 function d3_layout_treeMove(wm, wp, shift) {
7449 var change = shift / (wp.i - wm.i);
7450 wp.c -= change;
7451 wp.s += shift;
7452 wm.c += change;
7453 wp.z += shift;
7454 wp.m += shift;
7455 }
7456 function d3_layout_treeShift(v) {
7457 var shift = 0, change = 0, children = v.children, i = children.length, w;
7458 while (--i >= 0) {
7459 w = children[i];
7460 w.z += shift;
7461 w.m += shift;
7462 shift += w.s + (change += w.c);
7463 }
7464 }
7465 function d3_layout_treeAncestor(vim, v, ancestor) {
7466 return vim.a.parent === v.parent ? vim.a : ancestor;
7467 }
7468 d3.layout.cluster = function() {
7469 var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false;
7470 function cluster(d, i) {
7471 var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0;
7472 d3_layout_hierarchyVisitAfter(root, function(node) {
7473 var children = node.children;
7474 if (children && children.length) {
7475 node.x = d3_layout_clusterX(children);
7476 node.y = d3_layout_clusterY(children);
7477 } else {
7478 node.x = previousNode ? x += separation(node, previousNode) : 0;
7479 node.y = 0;
7480 previousNode = node;
7481 }
7482 });
7483 var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2;
7484 d3_layout_hierarchyVisitAfter(root, nodeSize ? function(node) {
7485 node.x = (node.x - root.x) * size[0];
7486 node.y = (root.y - node.y) * size[1];
7487 } : function(node) {
7488 node.x = (node.x - x0) / (x1 - x0) * size[0];
7489 node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1];
7490 });
7491 return nodes;
7492 }
7493 cluster.separation = function(x) {
7494 if (!arguments.length) return separation;
7495 separation = x;
7496 return cluster;
7497 };
7498 cluster.size = function(x) {
7499 if (!arguments.length) return nodeSize ? null : size;
7500 nodeSize = (size = x) == null;
7501 return cluster;
7502 };
7503 cluster.nodeSize = function(x) {
7504 if (!arguments.length) return nodeSize ? size : null;
7505 nodeSize = (size = x) != null;
7506 return cluster;
7507 };
7508 return d3_layout_hierarchyRebind(cluster, hierarchy);
7509 };
7510 function d3_layout_clusterY(children) {
7511 return 1 + d3.max(children, function(child) {
7512 return child.y;
7513 });
7514 }
7515 function d3_layout_clusterX(children) {
7516 return children.reduce(function(x, child) {
7517 return x + child.x;
7518 }, 0) / children.length;
7519 }
7520 function d3_layout_clusterLeft(node) {
7521 var children = node.children;
7522 return children && children.length ? d3_layout_clusterLeft(children[0]) : node;
7523 }
7524 function d3_layout_clusterRight(node) {
7525 var children = node.children, n;
7526 return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node;
7527 }
7528 d3.layout.treemap = function() {
7529 var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode = "squarify", ratio = .5 * (1 + Math.sqrt(5));
7530 function scale(children, k) {
7531 var i = -1, n = children.length, child, area;
7532 while (++i < n) {
7533 area = (child = children[i]).value * (k < 0 ? 0 : k);
7534 child.area = isNaN(area) || area <= 0 ? 0 : area;
7535 }
7536 }
7537 function squarify(node) {
7538 var children = node.children;
7539 if (children && children.length) {
7540 var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ? rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx : Math.min(rect.dx, rect.dy), n;
7541 scale(remaining, rect.dx * rect.dy / node.value);
7542 row.area = 0;
7543 while ((n = remaining.length) > 0) {
7544 row.push(child = remaining[n - 1]);
7545 row.area += child.area;
7546 if (mode !== "squarify" || (score = worst(row, u)) <= best) {
7547 remaining.pop();
7548 best = score;
7549 } else {
7550 row.area -= row.pop().area;
7551 position(row, u, rect, false);
7552 u = Math.min(rect.dx, rect.dy);
7553 row.length = row.area = 0;
7554 best = Infinity;
7555 }
7556 }
7557 if (row.length) {
7558 position(row, u, rect, true);
7559 row.length = row.area = 0;
7560 }
7561 children.forEach(squarify);
7562 }
7563 }
7564 function stickify(node) {
7565 var children = node.children;
7566 if (children && children.length) {
7567 var rect = pad(node), remaining = children.slice(), child, row = [];
7568 scale(remaining, rect.dx * rect.dy / node.value);
7569 row.area = 0;
7570 while (child = remaining.pop()) {
7571 row.push(child);
7572 row.area += child.area;
7573 if (child.z != null) {
7574 position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length);
7575 row.length = row.area = 0;
7576 }
7577 }
7578 children.forEach(stickify);
7579 }
7580 }
7581 function worst(row, u) {
7582 var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length;
7583 while (++i < n) {
7584 if (!(r = row[i].area)) continue;
7585 if (r < rmin) rmin = r;
7586 if (r > rmax) rmax = r;
7587 }
7588 s *= s;
7589 u *= u;
7590 return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity;
7591 }
7592 function position(row, u, rect, flush) {
7593 var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o;
7594 if (u == rect.dx) {
7595 if (flush || v > rect.dy) v = rect.dy;
7596 while (++i < n) {
7597 o = row[i];
7598 o.x = x;
7599 o.y = y;
7600 o.dy = v;
7601 x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0);
7602 }
7603 o.z = true;
7604 o.dx += rect.x + rect.dx - x;
7605 rect.y += v;
7606 rect.dy -= v;
7607 } else {
7608 if (flush || v > rect.dx) v = rect.dx;
7609 while (++i < n) {
7610 o = row[i];
7611 o.x = x;
7612 o.y = y;
7613 o.dx = v;
7614 y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0);
7615 }
7616 o.z = false;
7617 o.dy += rect.y + rect.dy - y;
7618 rect.x += v;
7619 rect.dx -= v;
7620 }
7621 }
7622 function treemap(d) {
7623 var nodes = stickies || hierarchy(d), root = nodes[0];
7624 root.x = 0;
7625 root.y = 0;
7626 root.dx = size[0];
7627 root.dy = size[1];
7628 if (stickies) hierarchy.revalue(root);
7629 scale([ root ], root.dx * root.dy / root.value);
7630 (stickies ? stickify : squarify)(root);
7631 if (sticky) stickies = nodes;
7632 return nodes;
7633 }
7634 treemap.size = function(x) {
7635 if (!arguments.length) return size;
7636 size = x;
7637 return treemap;
7638 };
7639 treemap.padding = function(x) {
7640 if (!arguments.length) return padding;
7641 function padFunction(node) {
7642 var p = x.call(treemap, node, node.depth);
7643 return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p);
7644 }
7645 function padConstant(node) {
7646 return d3_layout_treemapPad(node, x);
7647 }
7648 var type;
7649 pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ],
7650 padConstant) : padConstant;
7651 return treemap;
7652 };
7653 treemap.round = function(x) {
7654 if (!arguments.length) return round != Number;
7655 round = x ? Math.round : Number;
7656 return treemap;
7657 };
7658 treemap.sticky = function(x) {
7659 if (!arguments.length) return sticky;
7660 sticky = x;
7661 stickies = null;
7662 return treemap;
7663 };
7664 treemap.ratio = function(x) {
7665 if (!arguments.length) return ratio;
7666 ratio = x;
7667 return treemap;
7668 };
7669 treemap.mode = function(x) {
7670 if (!arguments.length) return mode;
7671 mode = x + "";
7672 return treemap;
7673 };
7674 return d3_layout_hierarchyRebind(treemap, hierarchy);
7675 };
7676 function d3_layout_treemapPadNull(node) {
7677 return {
7678 x: node.x,
7679 y: node.y,
7680 dx: node.dx,
7681 dy: node.dy
7682 };
7683 }
7684 function d3_layout_treemapPad(node, padding) {
7685 var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2];
7686 if (dx < 0) {
7687 x += dx / 2;
7688 dx = 0;
7689 }
7690 if (dy < 0) {
7691 y += dy / 2;
7692 dy = 0;
7693 }
7694 return {
7695 x: x,
7696 y: y,
7697 dx: dx,
7698 dy: dy
7699 };
7700 }
7701 d3.random = {
7702 normal: function(µ, σ) {
7703 var n = arguments.length;
7704 if (n < 2) σ = 1;
7705 if (n < 1) µ = 0;
7706 return function() {
7707 var x, y, r;
7708 do {
7709 x = Math.random() * 2 - 1;
7710 y = Math.random() * 2 - 1;
7711 r = x * x + y * y;
7712 } while (!r || r > 1);
7713 return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r);
7714 };
7715 },
7716 logNormal: function() {
7717 var random = d3.random.normal.apply(d3, arguments);
7718 return function() {
7719 return Math.exp(random());
7720 };
7721 },
7722 bates: function(m) {
7723 var random = d3.random.irwinHall(m);
7724 return function() {
7725 return random() / m;
7726 };
7727 },
7728 irwinHall: function(m) {
7729 return function() {
7730 for (var s = 0, j = 0; j < m; j++) s += Math.random();
7731 return s;
7732 };
7733 }
7734 };
7735 d3.scale = {};
7736 function d3_scaleExtent(domain) {
7737 var start = domain[0], stop = domain[domain.length - 1];
7738 return start < stop ? [ start, stop ] : [ stop, start ];
7739 }
7740 function d3_scaleRange(scale) {
7741 return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range());
7742 }
7743 function d3_scale_bilinear(domain, range, uninterpolate, interpolate) {
7744 var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]);
7745 return function(x) {
7746 return i(u(x));
7747 };
7748 }
7749 function d3_scale_nice(domain, nice) {
7750 var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx;
7751 if (x1 < x0) {
7752 dx = i0, i0 = i1, i1 = dx;
7753 dx = x0, x0 = x1, x1 = dx;
7754 }
7755 domain[i0] = nice.floor(x0);
7756 domain[i1] = nice.ceil(x1);
7757 return domain;
7758 }
7759 function d3_scale_niceStep(step) {
7760 return step ? {
7761 floor: function(x) {
7762 return Math.floor(x / step) * step;
7763 },
7764 ceil: function(x) {
7765 return Math.ceil(x / step) * step;
7766 }
7767 } : d3_scale_niceIdentity;
7768 }
7769 var d3_scale_niceIdentity = {
7770 floor: d3_identity,
7771 ceil: d3_identity
7772 };
7773 function d3_scale_polylinear(domain, range, uninterpolate, interpolate) {
7774 var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1;
7775 if (domain[k] < domain[0]) {
7776 domain = domain.slice().reverse();
7777 range = range.slice().reverse();
7778 }
7779 while (++j <= k) {
7780 u.push(uninterpolate(domain[j - 1], domain[j]));
7781 i.push(interpolate(range[j - 1], range[j]));
7782 }
7783 return function(x) {
7784 var j = d3.bisect(domain, x, 1, k) - 1;
7785 return i[j](u[j](x));
7786 };
7787 }
7788 d3.scale.linear = function() {
7789 return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3_interpolate, false);
7790 };
7791 function d3_scale_linear(domain, range, interpolate, clamp) {
7792 var output, input;
7793 function rescale() {
7794 var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber;
7795 output = linear(domain, range, uninterpolate, interpolate);
7796 input = linear(range, domain, uninterpolate, d3_interpolate);
7797 return scale;
7798 }
7799 function scale(x) {
7800 return output(x);
7801 }
7802 scale.invert = function(y) {
7803 return input(y);
7804 };
7805 scale.domain = function(x) {
7806 if (!arguments.length) return domain;
7807 domain = x.map(Number);
7808 return rescale();
7809 };
7810 scale.range = function(x) {
7811 if (!arguments.length) return range;
7812 range = x;
7813 return rescale();
7814 };
7815 scale.rangeRound = function(x) {
7816 return scale.range(x).interpolate(d3_interpolateRound);
7817 };
7818 scale.clamp = function(x) {
7819 if (!arguments.length) return clamp;
7820 clamp = x;
7821 return rescale();
7822 };
7823 scale.interpolate = function(x) {
7824 if (!arguments.length) return interpolate;
7825 interpolate = x;
7826 return rescale();
7827 };
7828 scale.ticks = function(m) {
7829 return d3_scale_linearTicks(domain, m);
7830 };
7831 scale.tickFormat = function(m, format) {
7832 return d3_scale_linearTickFormat(domain, m, format);
7833 };
7834 scale.nice = function(m) {
7835 d3_scale_linearNice(domain, m);
7836 return rescale();
7837 };
7838 scale.copy = function() {
7839 return d3_scale_linear(domain, range, interpolate, clamp);
7840 };
7841 return rescale();
7842 }
7843 function d3_scale_linearRebind(scale, linear) {
7844 return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp");
7845 }
7846 function d3_scale_linearNice(domain, m) {
7847 return d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain, m)[2]));
7848 }
7849 function d3_scale_linearTickRange(domain, m) {
7850 if (m == null) m = 10;
7851 var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step;
7852 if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2;
7853 extent[0] = Math.ceil(extent[0] / step) * step;
7854 extent[1] = Math.floor(extent[1] / step) * step + step * .5;
7855 extent[2] = step;
7856 return extent;
7857 }
7858 function d3_scale_linearTicks(domain, m) {
7859 return d3.range.apply(d3, d3_scale_linearTickRange(domain, m));
7860 }
7861 function d3_scale_linearTickFormat(domain, m, format) {
7862 var range = d3_scale_linearTickRange(domain, m);
7863 if (format) {
7864 var match = d3_format_re.exec(format);
7865 match.shift();
7866 if (match[8] === "s") {
7867 var prefix = d3.formatPrefix(Math.max(abs(range[0]), abs(range[1])));
7868 if (!match[7]) match[7] = "." + d3_scale_linearPrecision(prefix.scale(range[2]));
7869 match[8] = "f";
7870 format = d3.format(match.join(""));
7871 return function(d) {
7872 return format(prefix.scale(d)) + prefix.symbol;
7873 };
7874 }
7875 if (!match[7]) match[7] = "." + d3_scale_linearFormatPrecision(match[8], range);
7876 format = match.join("");
7877 } else {
7878 format = ",." + d3_scale_linearPrecision(range[2]) + "f";
7879 }
7880 return d3.format(format);
7881 }
7882 var d3_scale_linearFormatSignificant = {
7883 s: 1,
7884 g: 1,
7885 p: 1,
7886 r: 1,
7887 e: 1
7888 };
7889 function d3_scale_linearPrecision(value) {
7890 return -Math.floor(Math.log(value) / Math.LN10 + .01);
7891 }
7892 function d3_scale_linearFormatPrecision(type, range) {
7893 var p = d3_scale_linearPrecision(range[2]);
7894 return type in d3_scale_linearFormatSignificant ? Math.abs(p - d3_scale_linearPrecision(Math.max(abs(range[0]), abs(range[1])))) + +(type !== "e") : p - (type === "%") * 2;
7895 }
7896 d3.scale.log = function() {
7897 return d3_scale_log(d3.scale.linear().domain([ 0, 1 ]), 10, true, [ 1, 10 ]);
7898 };
7899 function d3_scale_log(linear, base, positive, domain) {
7900 function log(x) {
7901 return (positive ? Math.log(x < 0 ? 0 : x) : -Math.log(x > 0 ? 0 : -x)) / Math.log(base);
7902 }
7903 function pow(x) {
7904 return positive ? Math.pow(base, x) : -Math.pow(base, -x);
7905 }
7906 function scale(x) {
7907 return linear(log(x));
7908 }
7909 scale.invert = function(x) {
7910 return pow(linear.invert(x));
7911 };
7912 scale.domain = function(x) {
7913 if (!arguments.length) return domain;
7914 positive = x[0] >= 0;
7915 linear.domain((domain = x.map(Number)).map(log));
7916 return scale;
7917 };
7918 scale.base = function(_) {
7919 if (!arguments.length) return base;
7920 base = +_;
7921 linear.domain(domain.map(log));
7922 return scale;
7923 };
7924 scale.nice = function() {
7925 var niced = d3_scale_nice(domain.map(log), positive ? Math : d3_scale_logNiceNegative);
7926 linear.domain(niced);
7927 domain = niced.map(pow);
7928 return scale;
7929 };
7930 scale.ticks = function() {
7931 var extent = d3_scaleExtent(domain), ticks = [], u = extent[0], v = extent[1], i = Math.floor(log(u)), j = Math.ceil(log(v)), n = base % 1 ? 2 : base;
7932 if (isFinite(j - i)) {
7933 if (positive) {
7934 for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(pow(i) * k);
7935 ticks.push(pow(i));
7936 } else {
7937 ticks.push(pow(i));
7938 for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(pow(i) * k);
7939 }
7940 for (i = 0; ticks[i] < u; i++) {}
7941 for (j = ticks.length; ticks[j - 1] > v; j--) {}
7942 ticks = ticks.slice(i, j);
7943 }
7944 return ticks;
7945 };
7946 scale.tickFormat = function(n, format) {
7947 if (!arguments.length) return d3_scale_logFormat;
7948 if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format !== "function") format = d3.format(format);
7949 var k = Math.max(.1, n / scale.ticks().length), f = positive ? (e = 1e-12, Math.ceil) : (e = -1e-12,
7950 Math.floor), e;
7951 return function(d) {
7952 return d / pow(f(log(d) + e)) <= k ? format(d) : "";
7953 };
7954 };
7955 scale.copy = function() {
7956 return d3_scale_log(linear.copy(), base, positive, domain);
7957 };
7958 return d3_scale_linearRebind(scale, linear);
7959 }
7960 var d3_scale_logFormat = d3.format(".0e"), d3_scale_logNiceNegative = {
7961 floor: function(x) {
7962 return -Math.ceil(-x);
7963 },
7964 ceil: function(x) {
7965 return -Math.floor(-x);
7966 }
7967 };
7968 d3.scale.pow = function() {
7969 return d3_scale_pow(d3.scale.linear(), 1, [ 0, 1 ]);
7970 };
7971 function d3_scale_pow(linear, exponent, domain) {
7972 var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent);
7973 function scale(x) {
7974 return linear(powp(x));
7975 }
7976 scale.invert = function(x) {
7977 return powb(linear.invert(x));
7978 };
7979 scale.domain = function(x) {
7980 if (!arguments.length) return domain;
7981 linear.domain((domain = x.map(Number)).map(powp));
7982 return scale;
7983 };
7984 scale.ticks = function(m) {
7985 return d3_scale_linearTicks(domain, m);
7986 };
7987 scale.tickFormat = function(m, format) {
7988 return d3_scale_linearTickFormat(domain, m, format);
7989 };
7990 scale.nice = function(m) {
7991 return scale.domain(d3_scale_linearNice(domain, m));
7992 };
7993 scale.exponent = function(x) {
7994 if (!arguments.length) return exponent;
7995 powp = d3_scale_powPow(exponent = x);
7996 powb = d3_scale_powPow(1 / exponent);
7997 linear.domain(domain.map(powp));
7998 return scale;
7999 };
8000 scale.copy = function() {
8001 return d3_scale_pow(linear.copy(), exponent, domain);
8002 };
8003 return d3_scale_linearRebind(scale, linear);
8004 }
8005 function d3_scale_powPow(e) {
8006 return function(x) {
8007 return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e);
8008 };
8009 }
8010 d3.scale.sqrt = function() {
8011 return d3.scale.pow().exponent(.5);
8012 };
8013 d3.scale.ordinal = function() {
8014 return d3_scale_ordinal([], {
8015 t: "range",
8016 a: [ [] ]
8017 });
8018 };
8019 function d3_scale_ordinal(domain, ranger) {
8020 var index, range, rangeBand;
8021 function scale(x) {
8022 return range[((index.get(x) || (ranger.t === "range" ? index.set(x, domain.push(x)) : NaN)) - 1) % range.length];
8023 }
8024 function steps(start, step) {
8025 return d3.range(domain.length).map(function(i) {
8026 return start + step * i;
8027 });
8028 }
8029 scale.domain = function(x) {
8030 if (!arguments.length) return domain;
8031 domain = [];
8032 index = new d3_Map();
8033 var i = -1, n = x.length, xi;
8034 while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi));
8035 return scale[ranger.t].apply(scale, ranger.a);
8036 };
8037 scale.range = function(x) {
8038 if (!arguments.length) return range;
8039 range = x;
8040 rangeBand = 0;
8041 ranger = {
8042 t: "range",
8043 a: arguments
8044 };
8045 return scale;
8046 };
8047 scale.rangePoints = function(x, padding) {
8048 if (arguments.length < 2) padding = 0;
8049 var start = x[0], stop = x[1], step = domain.length < 2 ? (start = (start + stop) / 2,
8050 0) : (stop - start) / (domain.length - 1 + padding);
8051 range = steps(start + step * padding / 2, step);
8052 rangeBand = 0;
8053 ranger = {
8054 t: "rangePoints",
8055 a: arguments
8056 };
8057 return scale;
8058 };
8059 scale.rangeRoundPoints = function(x, padding) {
8060 if (arguments.length < 2) padding = 0;
8061 var start = x[0], stop = x[1], step = domain.length < 2 ? (start = stop = Math.round((start + stop) / 2),
8062 0) : (stop - start) / (domain.length - 1 + padding) | 0;
8063 range = steps(start + Math.round(step * padding / 2 + (stop - start - (domain.length - 1 + padding) * step) / 2), step);
8064 rangeBand = 0;
8065 ranger = {
8066 t: "rangeRoundPoints",
8067 a: arguments
8068 };
8069 return scale;
8070 };
8071 scale.rangeBands = function(x, padding, outerPadding) {
8072 if (arguments.length < 2) padding = 0;
8073 if (arguments.length < 3) outerPadding = padding;
8074 var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding);
8075 range = steps(start + step * outerPadding, step);
8076 if (reverse) range.reverse();
8077 rangeBand = step * (1 - padding);
8078 ranger = {
8079 t: "rangeBands",
8080 a: arguments
8081 };
8082 return scale;
8083 };
8084 scale.rangeRoundBands = function(x, padding, outerPadding) {
8085 if (arguments.length < 2) padding = 0;
8086 if (arguments.length < 3) outerPadding = padding;
8087 var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding));
8088 range = steps(start + Math.round((stop - start - (domain.length - padding) * step) / 2), step);
8089 if (reverse) range.reverse();
8090 rangeBand = Math.round(step * (1 - padding));
8091 ranger = {
8092 t: "rangeRoundBands",
8093 a: arguments
8094 };
8095 return scale;
8096 };
8097 scale.rangeBand = function() {
8098 return rangeBand;
8099 };
8100 scale.rangeExtent = function() {
8101 return d3_scaleExtent(ranger.a[0]);
8102 };
8103 scale.copy = function() {
8104 return d3_scale_ordinal(domain, ranger);
8105 };
8106 return scale.domain(domain);
8107 }
8108 d3.scale.category10 = function() {
8109 return d3.scale.ordinal().range(d3_category10);
8110 };
8111 d3.scale.category20 = function() {
8112 return d3.scale.ordinal().range(d3_category20);
8113 };
8114 d3.scale.category20b = function() {
8115 return d3.scale.ordinal().range(d3_category20b);
8116 };
8117 d3.scale.category20c = function() {
8118 return d3.scale.ordinal().range(d3_category20c);
8119 };
8120 var d3_category10 = [ 2062260, 16744206, 2924588, 14034728, 9725885, 9197131, 14907330, 8355711, 12369186, 1556175 ].map(d3_rgbString);
8121 var d3_category20 = [ 2062260, 11454440, 16744206, 16759672, 2924588, 10018698, 14034728, 16750742, 9725885, 12955861, 9197131, 12885140, 14907330, 16234194, 8355711, 13092807, 12369186, 14408589, 1556175, 10410725 ].map(d3_rgbString);
8122 var d3_category20b = [ 3750777, 5395619, 7040719, 10264286, 6519097, 9216594, 11915115, 13556636, 9202993, 12426809, 15186514, 15190932, 8666169, 11356490, 14049643, 15177372, 8077683, 10834324, 13528509, 14589654 ].map(d3_rgbString);
8123 var d3_category20c = [ 3244733, 7057110, 10406625, 13032431, 15095053, 16616764, 16625259, 16634018, 3253076, 7652470, 10607003, 13101504, 7695281, 10394312, 12369372, 14342891, 6513507, 9868950, 12434877, 14277081 ].map(d3_rgbString);
8124 d3.scale.quantile = function() {
8125 return d3_scale_quantile([], []);
8126 };
8127 function d3_scale_quantile(domain, range) {
8128 var thresholds;
8129 function rescale() {
8130 var k = 0, q = range.length;
8131 thresholds = [];
8132 while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q);
8133 return scale;
8134 }
8135 function scale(x) {
8136 if (!isNaN(x = +x)) return range[d3.bisect(thresholds, x)];
8137 }
8138 scale.domain = function(x) {
8139 if (!arguments.length) return domain;
8140 domain = x.map(d3_number).filter(d3_numeric).sort(d3_ascending);
8141 return rescale();
8142 };
8143 scale.range = function(x) {
8144 if (!arguments.length) return range;
8145 range = x;
8146 return rescale();
8147 };
8148 scale.quantiles = function() {
8149 return thresholds;
8150 };
8151 scale.invertExtent = function(y) {
8152 y = range.indexOf(y);
8153 return y < 0 ? [ NaN, NaN ] : [ y > 0 ? thresholds[y - 1] : domain[0], y < thresholds.length ? thresholds[y] : domain[domain.length - 1] ];
8154 };
8155 scale.copy = function() {
8156 return d3_scale_quantile(domain, range);
8157 };
8158 return rescale();
8159 }
8160 d3.scale.quantize = function() {
8161 return d3_scale_quantize(0, 1, [ 0, 1 ]);
8162 };
8163 function d3_scale_quantize(x0, x1, range) {
8164 var kx, i;
8165 function scale(x) {
8166 return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))];
8167 }
8168 function rescale() {
8169 kx = range.length / (x1 - x0);
8170 i = range.length - 1;
8171 return scale;
8172 }
8173 scale.domain = function(x) {
8174 if (!arguments.length) return [ x0, x1 ];
8175 x0 = +x[0];
8176 x1 = +x[x.length - 1];
8177 return rescale();
8178 };
8179 scale.range = function(x) {
8180 if (!arguments.length) return range;
8181 range = x;
8182 return rescale();
8183 };
8184 scale.invertExtent = function(y) {
8185 y = range.indexOf(y);
8186 y = y < 0 ? NaN : y / kx + x0;
8187 return [ y, y + 1 / kx ];
8188 };
8189 scale.copy = function() {
8190 return d3_scale_quantize(x0, x1, range);
8191 };
8192 return rescale();
8193 }
8194 d3.scale.threshold = function() {
8195 return d3_scale_threshold([ .5 ], [ 0, 1 ]);
8196 };
8197 function d3_scale_threshold(domain, range) {
8198 function scale(x) {
8199 if (x <= x) return range[d3.bisect(domain, x)];
8200 }
8201 scale.domain = function(_) {
8202 if (!arguments.length) return domain;
8203 domain = _;
8204 return scale;
8205 };
8206 scale.range = function(_) {
8207 if (!arguments.length) return range;
8208 range = _;
8209 return scale;
8210 };
8211 scale.invertExtent = function(y) {
8212 y = range.indexOf(y);
8213 return [ domain[y - 1], domain[y] ];
8214 };
8215 scale.copy = function() {
8216 return d3_scale_threshold(domain, range);
8217 };
8218 return scale;
8219 }
8220 d3.scale.identity = function() {
8221 return d3_scale_identity([ 0, 1 ]);
8222 };
8223 function d3_scale_identity(domain) {
8224 function identity(x) {
8225 return +x;
8226 }
8227 identity.invert = identity;
8228 identity.domain = identity.range = function(x) {
8229 if (!arguments.length) return domain;
8230 domain = x.map(identity);
8231 return identity;
8232 };
8233 identity.ticks = function(m) {
8234 return d3_scale_linearTicks(domain, m);
8235 };
8236 identity.tickFormat = function(m, format) {
8237 return d3_scale_linearTickFormat(domain, m, format);
8238 };
8239 identity.copy = function() {
8240 return d3_scale_identity(domain);
8241 };
8242 return identity;
8243 }
8244 d3.svg = {};
8245 function d3_zero() {
8246 return 0;
8247 }
8248 d3.svg.arc = function() {
8249 var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, cornerRadius = d3_zero, padRadius = d3_svg_arcAuto, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle, padAngle = d3_svg_arcPadAngle;
8250 function arc() {
8251 var r0 = Math.max(0, +innerRadius.apply(this, arguments)), r1 = Math.max(0, +outerRadius.apply(this, arguments)), a0 = startAngle.apply(this, arguments) - halfπ, a1 = endAngle.apply(this, arguments) - halfπ, da = Math.abs(a1 - a0), cw = a0 > a1 ? 0 : 1;
8252 if (r1 < r0) rc = r1, r1 = r0, r0 = rc;
8253 if (da >= τε) return circleSegment(r1, cw) + (r0 ? circleSegment(r0, 1 - cw) : "") + "Z";
8254 var rc, cr, rp, ap, p0 = 0, p1 = 0, x0, y0, x1, y1, x2, y2, x3, y3, path = [];
8255 if (ap = (+padAngle.apply(this, arguments) || 0) / 2) {
8256 rp = padRadius === d3_svg_arcAuto ? Math.sqrt(r0 * r0 + r1 * r1) : +padRadius.apply(this, arguments);
8257 if (!cw) p1 *= -1;
8258 if (r1) p1 = d3_asin(rp / r1 * Math.sin(ap));
8259 if (r0) p0 = d3_asin(rp / r0 * Math.sin(ap));
8260 }
8261 if (r1) {
8262 x0 = r1 * Math.cos(a0 + p1);
8263 y0 = r1 * Math.sin(a0 + p1);
8264 x1 = r1 * Math.cos(a1 - p1);
8265 y1 = r1 * Math.sin(a1 - p1);
8266 var l1 = Math.abs(a1 - a0 - 2 * p1) <= π ? 0 : 1;
8267 if (p1 && d3_svg_arcSweep(x0, y0, x1, y1) === cw ^ l1) {
8268 var h1 = (a0 + a1) / 2;
8269 x0 = r1 * Math.cos(h1);
8270 y0 = r1 * Math.sin(h1);
8271 x1 = y1 = null;
8272 }
8273 } else {
8274 x0 = y0 = 0;
8275 }
8276 if (r0) {
8277 x2 = r0 * Math.cos(a1 - p0);
8278 y2 = r0 * Math.sin(a1 - p0);
8279 x3 = r0 * Math.cos(a0 + p0);
8280 y3 = r0 * Math.sin(a0 + p0);
8281 var l0 = Math.abs(a0 - a1 + 2 * p0) <= π ? 0 : 1;
8282 if (p0 && d3_svg_arcSweep(x2, y2, x3, y3) === 1 - cw ^ l0) {
8283 var h0 = (a0 + a1) / 2;
8284 x2 = r0 * Math.cos(h0);
8285 y2 = r0 * Math.sin(h0);
8286 x3 = y3 = null;
8287 }
8288 } else {
8289 x2 = y2 = 0;
8290 }
8291 if ((rc = Math.min(Math.abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments))) > .001) {
8292 cr = r0 < r1 ^ cw ? 0 : 1;
8293 var oc = x3 == null ? [ x2, y2 ] : x1 == null ? [ x0, y0 ] : d3_geom_polygonIntersect([ x0, y0 ], [ x3, y3 ], [ x1, y1 ], [ x2, y2 ]), ax = x0 - oc[0], ay = y0 - oc[1], bx = x1 - oc[0], by = y1 - oc[1], kc = 1 / Math.sin(Math.acos((ax * bx + ay * by) / (Math.sqrt(ax * ax + ay * ay) * Math.sqrt(bx * bx + by * by))) / 2), lc = Math.sqrt(oc[0] * oc[0] + oc[1] * oc[1]);
8294 if (x1 != null) {
8295 var rc1 = Math.min(rc, (r1 - lc) / (kc + 1)), t30 = d3_svg_arcCornerTangents(x3 == null ? [ x2, y2 ] : [ x3, y3 ], [ x0, y0 ], r1, rc1, cw), t12 = d3_svg_arcCornerTangents([ x1, y1 ], [ x2, y2 ], r1, rc1, cw);
8296 if (rc === rc1) {
8297 path.push("M", t30[0], "A", rc1, ",", rc1, " 0 0,", cr, " ", t30[1], "A", r1, ",", r1, " 0 ", 1 - cw ^ d3_svg_arcSweep(t30[1][0], t30[1][1], t12[1][0], t12[1][1]), ",", cw, " ", t12[1], "A", rc1, ",", rc1, " 0 0,", cr, " ", t12[0]);
8298 } else {
8299 path.push("M", t30[0], "A", rc1, ",", rc1, " 0 1,", cr, " ", t12[0]);
8300 }
8301 } else {
8302 path.push("M", x0, ",", y0);
8303 }
8304 if (x3 != null) {
8305 var rc0 = Math.min(rc, (r0 - lc) / (kc - 1)), t03 = d3_svg_arcCornerTangents([ x0, y0 ], [ x3, y3 ], r0, -rc0, cw), t21 = d3_svg_arcCornerTangents([ x2, y2 ], x1 == null ? [ x0, y0 ] : [ x1, y1 ], r0, -rc0, cw);
8306 if (rc === rc0) {
8307 path.push("L", t21[0], "A", rc0, ",", rc0, " 0 0,", cr, " ", t21[1], "A", r0, ",", r0, " 0 ", cw ^ d3_svg_arcSweep(t21[1][0], t21[1][1], t03[1][0], t03[1][1]), ",", 1 - cw, " ", t03[1], "A", rc0, ",", rc0, " 0 0,", cr, " ", t03[0]);
8308 } else {
8309 path.push("L", t21[0], "A", rc0, ",", rc0, " 0 0,", cr, " ", t03[0]);
8310 }
8311 } else {
8312 path.push("L", x2, ",", y2);
8313 }
8314 } else {
8315 path.push("M", x0, ",", y0);
8316 if (x1 != null) path.push("A", r1, ",", r1, " 0 ", l1, ",", cw, " ", x1, ",", y1);
8317 path.push("L", x2, ",", y2);
8318 if (x3 != null) path.push("A", r0, ",", r0, " 0 ", l0, ",", 1 - cw, " ", x3, ",", y3);
8319 }
8320 path.push("Z");
8321 return path.join("");
8322 }
8323 function circleSegment(r1, cw) {
8324 return "M0," + r1 + "A" + r1 + "," + r1 + " 0 1," + cw + " 0," + -r1 + "A" + r1 + "," + r1 + " 0 1," + cw + " 0," + r1;
8325 }
8326 arc.innerRadius = function(v) {
8327 if (!arguments.length) return innerRadius;
8328 innerRadius = d3_functor(v);
8329 return arc;
8330 };
8331 arc.outerRadius = function(v) {
8332 if (!arguments.length) return outerRadius;
8333 outerRadius = d3_functor(v);
8334 return arc;
8335 };
8336 arc.cornerRadius = function(v) {
8337 if (!arguments.length) return cornerRadius;
8338 cornerRadius = d3_functor(v);
8339 return arc;
8340 };
8341 arc.padRadius = function(v) {
8342 if (!arguments.length) return padRadius;
8343 padRadius = v == d3_svg_arcAuto ? d3_svg_arcAuto : d3_functor(v);
8344 return arc;
8345 };
8346 arc.startAngle = function(v) {
8347 if (!arguments.length) return startAngle;
8348 startAngle = d3_functor(v);
8349 return arc;
8350 };
8351 arc.endAngle = function(v) {
8352 if (!arguments.length) return endAngle;
8353 endAngle = d3_functor(v);
8354 return arc;
8355 };
8356 arc.padAngle = function(v) {
8357 if (!arguments.length) return padAngle;
8358 padAngle = d3_functor(v);
8359 return arc;
8360 };
8361 arc.centroid = function() {
8362 var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2, a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - halfπ;
8363 return [ Math.cos(a) * r, Math.sin(a) * r ];
8364 };
8365 return arc;
8366 };
8367 var d3_svg_arcAuto = "auto";
8368 function d3_svg_arcInnerRadius(d) {
8369 return d.innerRadius;
8370 }
8371 function d3_svg_arcOuterRadius(d) {
8372 return d.outerRadius;
8373 }
8374 function d3_svg_arcStartAngle(d) {
8375 return d.startAngle;
8376 }
8377 function d3_svg_arcEndAngle(d) {
8378 return d.endAngle;
8379 }
8380 function d3_svg_arcPadAngle(d) {
8381 return d && d.padAngle;
8382 }
8383 function d3_svg_arcSweep(x0, y0, x1, y1) {
8384 return (x0 - x1) * y0 - (y0 - y1) * x0 > 0 ? 0 : 1;
8385 }
8386 function d3_svg_arcCornerTangents(p0, p1, r1, rc, cw) {
8387 var x01 = p0[0] - p1[0], y01 = p0[1] - p1[1], lo = (cw ? rc : -rc) / Math.sqrt(x01 * x01 + y01 * y01), ox = lo * y01, oy = -lo * x01, x1 = p0[0] + ox, y1 = p0[1] + oy, x2 = p1[0] + ox, y2 = p1[1] + oy, x3 = (x1 + x2) / 2, y3 = (y1 + y2) / 2, dx = x2 - x1, dy = y2 - y1, d2 = dx * dx + dy * dy, r = r1 - rc, D = x1 * y2 - x2 * y1, d = (dy < 0 ? -1 : 1) * Math.sqrt(r * r * d2 - D * D), cx0 = (D * dy - dx * d) / d2, cy0 = (-D * dx - dy * d) / d2, cx1 = (D * dy + dx * d) / d2, cy1 = (-D * dx + dy * d) / d2, dx0 = cx0 - x3, dy0 = cy0 - y3, dx1 = cx1 - x3, dy1 = cy1 - y3;
8388 if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;
8389 return [ [ cx0 - ox, cy0 - oy ], [ cx0 * r1 / r, cy0 * r1 / r ] ];
8390 }
8391 function d3_svg_line(projection) {
8392 var x = d3_geom_pointX, y = d3_geom_pointY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7;
8393 function line(data) {
8394 var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y);
8395 function segment() {
8396 segments.push("M", interpolate(projection(points), tension));
8397 }
8398 while (++i < n) {
8399 if (defined.call(this, d = data[i], i)) {
8400 points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]);
8401 } else if (points.length) {
8402 segment();
8403 points = [];
8404 }
8405 }
8406 if (points.length) segment();
8407 return segments.length ? segments.join("") : null;
8408 }
8409 line.x = function(_) {
8410 if (!arguments.length) return x;
8411 x = _;
8412 return line;
8413 };
8414 line.y = function(_) {
8415 if (!arguments.length) return y;
8416 y = _;
8417 return line;
8418 };
8419 line.defined = function(_) {
8420 if (!arguments.length) return defined;
8421 defined = _;
8422 return line;
8423 };
8424 line.interpolate = function(_) {
8425 if (!arguments.length) return interpolateKey;
8426 if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;
8427 return line;
8428 };
8429 line.tension = function(_) {
8430 if (!arguments.length) return tension;
8431 tension = _;
8432 return line;
8433 };
8434 return line;
8435 }
8436 d3.svg.line = function() {
8437 return d3_svg_line(d3_identity);
8438 };
8439 var d3_svg_lineInterpolators = d3.map({
8440 linear: d3_svg_lineLinear,
8441 "linear-closed": d3_svg_lineLinearClosed,
8442 step: d3_svg_lineStep,
8443 "step-before": d3_svg_lineStepBefore,
8444 "step-after": d3_svg_lineStepAfter,
8445 basis: d3_svg_lineBasis,
8446 "basis-open": d3_svg_lineBasisOpen,
8447 "basis-closed": d3_svg_lineBasisClosed,
8448 bundle: d3_svg_lineBundle,
8449 cardinal: d3_svg_lineCardinal,
8450 "cardinal-open": d3_svg_lineCardinalOpen,
8451 "cardinal-closed": d3_svg_lineCardinalClosed,
8452 monotone: d3_svg_lineMonotone
8453 });
8454 d3_svg_lineInterpolators.forEach(function(key, value) {
8455 value.key = key;
8456 value.closed = /-closed$/.test(key);
8457 });
8458 function d3_svg_lineLinear(points) {
8459 return points.join("L");
8460 }
8461 function d3_svg_lineLinearClosed(points) {
8462 return d3_svg_lineLinear(points) + "Z";
8463 }
8464 function d3_svg_lineStep(points) {
8465 var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
8466 while (++i < n) path.push("H", (p[0] + (p = points[i])[0]) / 2, "V", p[1]);
8467 if (n > 1) path.push("H", p[0]);
8468 return path.join("");
8469 }
8470 function d3_svg_lineStepBefore(points) {
8471 var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
8472 while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]);
8473 return path.join("");
8474 }
8475 function d3_svg_lineStepAfter(points) {
8476 var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
8477 while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]);
8478 return path.join("");
8479 }
8480 function d3_svg_lineCardinalOpen(points, tension) {
8481 return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, -1), d3_svg_lineCardinalTangents(points, tension));
8482 }
8483 function d3_svg_lineCardinalClosed(points, tension) {
8484 return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]),
8485 points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension));
8486 }
8487 function d3_svg_lineCardinal(points, tension) {
8488 return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension));
8489 }
8490 function d3_svg_lineHermite(points, tangents) {
8491 if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) {
8492 return d3_svg_lineLinear(points);
8493 }
8494 var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1;
8495 if (quad) {
8496 path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1];
8497 p0 = points[1];
8498 pi = 2;
8499 }
8500 if (tangents.length > 1) {
8501 t = tangents[1];
8502 p = points[pi];
8503 pi++;
8504 path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1];
8505 for (var i = 2; i < tangents.length; i++, pi++) {
8506 p = points[pi];
8507 t = tangents[i];
8508 path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1];
8509 }
8510 }
8511 if (quad) {
8512 var lp = points[pi];
8513 path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1];
8514 }
8515 return path;
8516 }
8517 function d3_svg_lineCardinalTangents(points, tension) {
8518 var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length;
8519 while (++i < n) {
8520 p0 = p1;
8521 p1 = p2;
8522 p2 = points[i];
8523 tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]);
8524 }
8525 return tangents;
8526 }
8527 function d3_svg_lineBasis(points) {
8528 if (points.length < 3) return d3_svg_lineLinear(points);
8529 var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0, "L", d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ];
8530 points.push(points[n - 1]);
8531 while (++i <= n) {
8532 pi = points[i];
8533 px.shift();
8534 px.push(pi[0]);
8535 py.shift();
8536 py.push(pi[1]);
8537 d3_svg_lineBasisBezier(path, px, py);
8538 }
8539 points.pop();
8540 path.push("L", pi);
8541 return path.join("");
8542 }
8543 function d3_svg_lineBasisOpen(points) {
8544 if (points.length < 4) return d3_svg_lineLinear(points);
8545 var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ];
8546 while (++i < 3) {
8547 pi = points[i];
8548 px.push(pi[0]);
8549 py.push(pi[1]);
8550 }
8551 path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py));
8552 --i;
8553 while (++i < n) {
8554 pi = points[i];
8555 px.shift();
8556 px.push(pi[0]);
8557 py.shift();
8558 py.push(pi[1]);
8559 d3_svg_lineBasisBezier(path, px, py);
8560 }
8561 return path.join("");
8562 }
8563 function d3_svg_lineBasisClosed(points) {
8564 var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = [];
8565 while (++i < 4) {
8566 pi = points[i % n];
8567 px.push(pi[0]);
8568 py.push(pi[1]);
8569 }
8570 path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ];
8571 --i;
8572 while (++i < m) {
8573 pi = points[i % n];
8574 px.shift();
8575 px.push(pi[0]);
8576 py.shift();
8577 py.push(pi[1]);
8578 d3_svg_lineBasisBezier(path, px, py);
8579 }
8580 return path.join("");
8581 }
8582 function d3_svg_lineBundle(points, tension) {
8583 var n = points.length - 1;
8584 if (n) {
8585 var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t;
8586 while (++i <= n) {
8587 p = points[i];
8588 t = i / n;
8589 p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx);
8590 p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy);
8591 }
8592 }
8593 return d3_svg_lineBasis(points);
8594 }
8595 function d3_svg_lineDot4(a, b) {
8596 return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
8597 }
8598 var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ];
8599 function d3_svg_lineBasisBezier(path, x, y) {
8600 path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y));
8601 }
8602 function d3_svg_lineSlope(p0, p1) {
8603 return (p1[1] - p0[1]) / (p1[0] - p0[0]);
8604 }
8605 function d3_svg_lineFiniteDifferences(points) {
8606 var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1);
8607 while (++i < j) {
8608 m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2;
8609 }
8610 m[i] = d;
8611 return m;
8612 }
8613 function d3_svg_lineMonotoneTangents(points) {
8614 var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1;
8615 while (++i < j) {
8616 d = d3_svg_lineSlope(points[i], points[i + 1]);
8617 if (abs(d) < ε) {
8618 m[i] = m[i + 1] = 0;
8619 } else {
8620 a = m[i] / d;
8621 b = m[i + 1] / d;
8622 s = a * a + b * b;
8623 if (s > 9) {
8624 s = d * 3 / Math.sqrt(s);
8625 m[i] = s * a;
8626 m[i + 1] = s * b;
8627 }
8628 }
8629 }
8630 i = -1;
8631 while (++i <= j) {
8632 s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i]));
8633 tangents.push([ s || 0, m[i] * s || 0 ]);
8634 }
8635 return tangents;
8636 }
8637 function d3_svg_lineMonotone(points) {
8638 return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points));
8639 }
8640 d3.svg.line.radial = function() {
8641 var line = d3_svg_line(d3_svg_lineRadial);
8642 line.radius = line.x, delete line.x;
8643 line.angle = line.y, delete line.y;
8644 return line;
8645 };
8646 function d3_svg_lineRadial(points) {
8647 var point, i = -1, n = points.length, r, a;
8648 while (++i < n) {
8649 point = points[i];
8650 r = point[0];
8651 a = point[1] - halfπ;
8652 point[0] = r * Math.cos(a);
8653 point[1] = r * Math.sin(a);
8654 }
8655 return points;
8656 }
8657 function d3_svg_area(projection) {
8658 var x0 = d3_geom_pointX, x1 = d3_geom_pointX, y0 = 0, y1 = d3_geom_pointY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7;
8659 function area(data) {
8660 var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() {
8661 return x;
8662 } : d3_functor(x1), fy1 = y0 === y1 ? function() {
8663 return y;
8664 } : d3_functor(y1), x, y;
8665 function segment() {
8666 segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z");
8667 }
8668 while (++i < n) {
8669 if (defined.call(this, d = data[i], i)) {
8670 points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]);
8671 points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]);
8672 } else if (points0.length) {
8673 segment();
8674 points0 = [];
8675 points1 = [];
8676 }
8677 }
8678 if (points0.length) segment();
8679 return segments.length ? segments.join("") : null;
8680 }
8681 area.x = function(_) {
8682 if (!arguments.length) return x1;
8683 x0 = x1 = _;
8684 return area;
8685 };
8686 area.x0 = function(_) {
8687 if (!arguments.length) return x0;
8688 x0 = _;
8689 return area;
8690 };
8691 area.x1 = function(_) {
8692 if (!arguments.length) return x1;
8693 x1 = _;
8694 return area;
8695 };
8696 area.y = function(_) {
8697 if (!arguments.length) return y1;
8698 y0 = y1 = _;
8699 return area;
8700 };
8701 area.y0 = function(_) {
8702 if (!arguments.length) return y0;
8703 y0 = _;
8704 return area;
8705 };
8706 area.y1 = function(_) {
8707 if (!arguments.length) return y1;
8708 y1 = _;
8709 return area;
8710 };
8711 area.defined = function(_) {
8712 if (!arguments.length) return defined;
8713 defined = _;
8714 return area;
8715 };
8716 area.interpolate = function(_) {
8717 if (!arguments.length) return interpolateKey;
8718 if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;
8719 interpolateReverse = interpolate.reverse || interpolate;
8720 L = interpolate.closed ? "M" : "L";
8721 return area;
8722 };
8723 area.tension = function(_) {
8724 if (!arguments.length) return tension;
8725 tension = _;
8726 return area;
8727 };
8728 return area;
8729 }
8730 d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter;
8731 d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore;
8732 d3.svg.area = function() {
8733 return d3_svg_area(d3_identity);
8734 };
8735 d3.svg.area.radial = function() {
8736 var area = d3_svg_area(d3_svg_lineRadial);
8737 area.radius = area.x, delete area.x;
8738 area.innerRadius = area.x0, delete area.x0;
8739 area.outerRadius = area.x1, delete area.x1;
8740 area.angle = area.y, delete area.y;
8741 area.startAngle = area.y0, delete area.y0;
8742 area.endAngle = area.y1, delete area.y1;
8743 return area;
8744 };
8745 d3.svg.chord = function() {
8746 var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;
8747 function chord(d, i) {
8748 var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i);
8749 return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + "Z";
8750 }
8751 function subgroup(self, f, d, i) {
8752 var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) - halfπ, a1 = endAngle.call(self, subgroup, i) - halfπ;
8753 return {
8754 r: r,
8755 a0: a0,
8756 a1: a1,
8757 p0: [ r * Math.cos(a0), r * Math.sin(a0) ],
8758 p1: [ r * Math.cos(a1), r * Math.sin(a1) ]
8759 };
8760 }
8761 function equals(a, b) {
8762 return a.a0 == b.a0 && a.a1 == b.a1;
8763 }
8764 function arc(r, p, a) {
8765 return "A" + r + "," + r + " 0 " + +(a > π) + ",1 " + p;
8766 }
8767 function curve(r0, p0, r1, p1) {
8768 return "Q 0,0 " + p1;
8769 }
8770 chord.radius = function(v) {
8771 if (!arguments.length) return radius;
8772 radius = d3_functor(v);
8773 return chord;
8774 };
8775 chord.source = function(v) {
8776 if (!arguments.length) return source;
8777 source = d3_functor(v);
8778 return chord;
8779 };
8780 chord.target = function(v) {
8781 if (!arguments.length) return target;
8782 target = d3_functor(v);
8783 return chord;
8784 };
8785 chord.startAngle = function(v) {
8786 if (!arguments.length) return startAngle;
8787 startAngle = d3_functor(v);
8788 return chord;
8789 };
8790 chord.endAngle = function(v) {
8791 if (!arguments.length) return endAngle;
8792 endAngle = d3_functor(v);
8793 return chord;
8794 };
8795 return chord;
8796 };
8797 function d3_svg_chordRadius(d) {
8798 return d.radius;
8799 }
8800 d3.svg.diagonal = function() {
8801 var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection;
8802 function diagonal(d, i) {
8803 var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, {
8804 x: p0.x,
8805 y: m
8806 }, {
8807 x: p3.x,
8808 y: m
8809 }, p3 ];
8810 p = p.map(projection);
8811 return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3];
8812 }
8813 diagonal.source = function(x) {
8814 if (!arguments.length) return source;
8815 source = d3_functor(x);
8816 return diagonal;
8817 };
8818 diagonal.target = function(x) {
8819 if (!arguments.length) return target;
8820 target = d3_functor(x);
8821 return diagonal;
8822 };
8823 diagonal.projection = function(x) {
8824 if (!arguments.length) return projection;
8825 projection = x;
8826 return diagonal;
8827 };
8828 return diagonal;
8829 };
8830 function d3_svg_diagonalProjection(d) {
8831 return [ d.x, d.y ];
8832 }
8833 d3.svg.diagonal.radial = function() {
8834 var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection;
8835 diagonal.projection = function(x) {
8836 return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection;
8837 };
8838 return diagonal;
8839 };
8840 function d3_svg_diagonalRadialProjection(projection) {
8841 return function() {
8842 var d = projection.apply(this, arguments), r = d[0], a = d[1] - halfπ;
8843 return [ r * Math.cos(a), r * Math.sin(a) ];
8844 };
8845 }
8846 d3.svg.symbol = function() {
8847 var type = d3_svg_symbolType, size = d3_svg_symbolSize;
8848 function symbol(d, i) {
8849 return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i));
8850 }
8851 symbol.type = function(x) {
8852 if (!arguments.length) return type;
8853 type = d3_functor(x);
8854 return symbol;
8855 };
8856 symbol.size = function(x) {
8857 if (!arguments.length) return size;
8858 size = d3_functor(x);
8859 return symbol;
8860 };
8861 return symbol;
8862 };
8863 function d3_svg_symbolSize() {
8864 return 64;
8865 }
8866 function d3_svg_symbolType() {
8867 return "circle";
8868 }
8869 function d3_svg_symbolCircle(size) {
8870 var r = Math.sqrt(size / π);
8871 return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z";
8872 }
8873 var d3_svg_symbols = d3.map({
8874 circle: d3_svg_symbolCircle,
8875 cross: function(size) {
8876 var r = Math.sqrt(size / 5) / 2;
8877 return "M" + -3 * r + "," + -r + "H" + -r + "V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r + "V" + r + "H" + r + "V" + 3 * r + "H" + -r + "V" + r + "H" + -3 * r + "Z";
8878 },
8879 diamond: function(size) {
8880 var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30;
8881 return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z";
8882 },
8883 square: function(size) {
8884 var r = Math.sqrt(size) / 2;
8885 return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z";
8886 },
8887 "triangle-down": function(size) {
8888 var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
8889 return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z";
8890 },
8891 "triangle-up": function(size) {
8892 var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
8893 return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z";
8894 }
8895 });
8896 d3.svg.symbolTypes = d3_svg_symbols.keys();
8897 var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians);
8898 d3_selectionPrototype.transition = function(name) {
8899 var id = d3_transitionInheritId || ++d3_transitionId, ns = d3_transitionNamespace(name), subgroups = [], subgroup, node, transition = d3_transitionInherit || {
8900 time: Date.now(),
8901 ease: d3_ease_cubicInOut,
8902 delay: 0,
8903 duration: 250
8904 };
8905 for (var j = -1, m = this.length; ++j < m; ) {
8906 subgroups.push(subgroup = []);
8907 for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
8908 if (node = group[i]) d3_transitionNode(node, i, ns, id, transition);
8909 subgroup.push(node);
8910 }
8911 }
8912 return d3_transition(subgroups, ns, id);
8913 };
8914 d3_selectionPrototype.interrupt = function(name) {
8915 return this.each(name == null ? d3_selection_interrupt : d3_selection_interruptNS(d3_transitionNamespace(name)));
8916 };
8917 var d3_selection_interrupt = d3_selection_interruptNS(d3_transitionNamespace());
8918 function d3_selection_interruptNS(ns) {
8919 return function() {
8920 var lock, active;
8921 if ((lock = this[ns]) && (active = lock[lock.active])) {
8922 if (--lock.count) {
8923 delete lock[lock.active];
8924 lock.active += .5;
8925 } else {
8926 delete this[ns];
8927 }
8928 active.event && active.event.interrupt.call(this, this.__data__, active.index);
8929 }
8930 };
8931 }
8932 function d3_transition(groups, ns, id) {
8933 d3_subclass(groups, d3_transitionPrototype);
8934 groups.namespace = ns;
8935 groups.id = id;
8936 return groups;
8937 }
8938 var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit;
8939 d3_transitionPrototype.call = d3_selectionPrototype.call;
8940 d3_transitionPrototype.empty = d3_selectionPrototype.empty;
8941 d3_transitionPrototype.node = d3_selectionPrototype.node;
8942 d3_transitionPrototype.size = d3_selectionPrototype.size;
8943 d3.transition = function(selection, name) {
8944 return selection && selection.transition ? d3_transitionInheritId ? selection.transition(name) : selection : d3_selectionRoot.transition(selection);
8945 };
8946 d3.transition.prototype = d3_transitionPrototype;
8947 d3_transitionPrototype.select = function(selector) {
8948 var id = this.id, ns = this.namespace, subgroups = [], subgroup, subnode, node;
8949 selector = d3_selection_selector(selector);
8950 for (var j = -1, m = this.length; ++j < m; ) {
8951 subgroups.push(subgroup = []);
8952 for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
8953 if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) {
8954 if ("__data__" in node) subnode.__data__ = node.__data__;
8955 d3_transitionNode(subnode, i, ns, id, node[ns][id]);
8956 subgroup.push(subnode);
8957 } else {
8958 subgroup.push(null);
8959 }
8960 }
8961 }
8962 return d3_transition(subgroups, ns, id);
8963 };
8964 d3_transitionPrototype.selectAll = function(selector) {
8965 var id = this.id, ns = this.namespace, subgroups = [], subgroup, subnodes, node, subnode, transition;
8966 selector = d3_selection_selectorAll(selector);
8967 for (var j = -1, m = this.length; ++j < m; ) {
8968 for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
8969 if (node = group[i]) {
8970 transition = node[ns][id];
8971 subnodes = selector.call(node, node.__data__, i, j);
8972 subgroups.push(subgroup = []);
8973 for (var k = -1, o = subnodes.length; ++k < o; ) {
8974 if (subnode = subnodes[k]) d3_transitionNode(subnode, k, ns, id, transition);
8975 subgroup.push(subnode);
8976 }
8977 }
8978 }
8979 }
8980 return d3_transition(subgroups, ns, id);
8981 };
8982 d3_transitionPrototype.filter = function(filter) {
8983 var subgroups = [], subgroup, group, node;
8984 if (typeof filter !== "function") filter = d3_selection_filter(filter);
8985 for (var j = 0, m = this.length; j < m; j++) {
8986 subgroups.push(subgroup = []);
8987 for (var group = this[j], i = 0, n = group.length; i < n; i++) {
8988 if ((node = group[i]) && filter.call(node, node.__data__, i, j)) {
8989 subgroup.push(node);
8990 }
8991 }
8992 }
8993 return d3_transition(subgroups, this.namespace, this.id);
8994 };
8995 d3_transitionPrototype.tween = function(name, tween) {
8996 var id = this.id, ns = this.namespace;
8997 if (arguments.length < 2) return this.node()[ns][id].tween.get(name);
8998 return d3_selection_each(this, tween == null ? function(node) {
8999 node[ns][id].tween.remove(name);
9000 } : function(node) {
9001 node[ns][id].tween.set(name, tween);
9002 });
9003 };
9004 function d3_transition_tween(groups, name, value, tween) {
9005 var id = groups.id, ns = groups.namespace;
9006 return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) {
9007 node[ns][id].tween.set(name, tween(value.call(node, node.__data__, i, j)));
9008 } : (value = tween(value), function(node) {
9009 node[ns][id].tween.set(name, value);
9010 }));
9011 }
9012 d3_transitionPrototype.attr = function(nameNS, value) {
9013 if (arguments.length < 2) {
9014 for (value in nameNS) this.attr(value, nameNS[value]);
9015 return this;
9016 }
9017 var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate, name = d3.ns.qualify(nameNS);
9018 function attrNull() {
9019 this.removeAttribute(name);
9020 }
9021 function attrNullNS() {
9022 this.removeAttributeNS(name.space, name.local);
9023 }
9024 function attrTween(b) {
9025 return b == null ? attrNull : (b += "", function() {
9026 var a = this.getAttribute(name), i;
9027 return a !== b && (i = interpolate(a, b), function(t) {
9028 this.setAttribute(name, i(t));
9029 });
9030 });
9031 }
9032 function attrTweenNS(b) {
9033 return b == null ? attrNullNS : (b += "", function() {
9034 var a = this.getAttributeNS(name.space, name.local), i;
9035 return a !== b && (i = interpolate(a, b), function(t) {
9036 this.setAttributeNS(name.space, name.local, i(t));
9037 });
9038 });
9039 }
9040 return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween);
9041 };
9042 d3_transitionPrototype.attrTween = function(nameNS, tween) {
9043 var name = d3.ns.qualify(nameNS);
9044 function attrTween(d, i) {
9045 var f = tween.call(this, d, i, this.getAttribute(name));
9046 return f && function(t) {
9047 this.setAttribute(name, f(t));
9048 };
9049 }
9050 function attrTweenNS(d, i) {
9051 var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));
9052 return f && function(t) {
9053 this.setAttributeNS(name.space, name.local, f(t));
9054 };
9055 }
9056 return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween);
9057 };
9058 d3_transitionPrototype.style = function(name, value, priority) {
9059 var n = arguments.length;
9060 if (n < 3) {
9061 if (typeof name !== "string") {
9062 if (n < 2) value = "";
9063 for (priority in name) this.style(priority, name[priority], value);
9064 return this;
9065 }
9066 priority = "";
9067 }
9068 function styleNull() {
9069 this.style.removeProperty(name);
9070 }
9071 function styleString(b) {
9072 return b == null ? styleNull : (b += "", function() {
9073 var a = d3_window.getComputedStyle(this, null).getPropertyValue(name), i;
9074 return a !== b && (i = d3_interpolate(a, b), function(t) {
9075 this.style.setProperty(name, i(t), priority);
9076 });
9077 });
9078 }
9079 return d3_transition_tween(this, "style." + name, value, styleString);
9080 };
9081 d3_transitionPrototype.styleTween = function(name, tween, priority) {
9082 if (arguments.length < 3) priority = "";
9083 function styleTween(d, i) {
9084 var f = tween.call(this, d, i, d3_window.getComputedStyle(this, null).getPropertyValue(name));
9085 return f && function(t) {
9086 this.style.setProperty(name, f(t), priority);
9087 };
9088 }
9089 return this.tween("style." + name, styleTween);
9090 };
9091 d3_transitionPrototype.text = function(value) {
9092 return d3_transition_tween(this, "text", value, d3_transition_text);
9093 };
9094 function d3_transition_text(b) {
9095 if (b == null) b = "";
9096 return function() {
9097 this.textContent = b;
9098 };
9099 }
9100 d3_transitionPrototype.remove = function() {
9101 var ns = this.namespace;
9102 return this.each("end.transition", function() {
9103 var p;
9104 if (this[ns].count < 2 && (p = this.parentNode)) p.removeChild(this);
9105 });
9106 };
9107 d3_transitionPrototype.ease = function(value) {
9108 var id = this.id, ns = this.namespace;
9109 if (arguments.length < 1) return this.node()[ns][id].ease;
9110 if (typeof value !== "function") value = d3.ease.apply(d3, arguments);
9111 return d3_selection_each(this, function(node) {
9112 node[ns][id].ease = value;
9113 });
9114 };
9115 d3_transitionPrototype.delay = function(value) {
9116 var id = this.id, ns = this.namespace;
9117 if (arguments.length < 1) return this.node()[ns][id].delay;
9118 return d3_selection_each(this, typeof value === "function" ? function(node, i, j) {
9119 node[ns][id].delay = +value.call(node, node.__data__, i, j);
9120 } : (value = +value, function(node) {
9121 node[ns][id].delay = value;
9122 }));
9123 };
9124 d3_transitionPrototype.duration = function(value) {
9125 var id = this.id, ns = this.namespace;
9126 if (arguments.length < 1) return this.node()[ns][id].duration;
9127 return d3_selection_each(this, typeof value === "function" ? function(node, i, j) {
9128 node[ns][id].duration = Math.max(1, value.call(node, node.__data__, i, j));
9129 } : (value = Math.max(1, value), function(node) {
9130 node[ns][id].duration = value;
9131 }));
9132 };
9133 d3_transitionPrototype.each = function(type, listener) {
9134 var id = this.id, ns = this.namespace;
9135 if (arguments.length < 2) {
9136 var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId;
9137 try {
9138 d3_transitionInheritId = id;
9139 d3_selection_each(this, function(node, i, j) {
9140 d3_transitionInherit = node[ns][id];
9141 type.call(node, node.__data__, i, j);
9142 });
9143 } finally {
9144 d3_transitionInherit = inherit;
9145 d3_transitionInheritId = inheritId;
9146 }
9147 } else {
9148 d3_selection_each(this, function(node) {
9149 var transition = node[ns][id];
9150 (transition.event || (transition.event = d3.dispatch("start", "end", "interrupt"))).on(type, listener);
9151 });
9152 }
9153 return this;
9154 };
9155 d3_transitionPrototype.transition = function() {
9156 var id0 = this.id, id1 = ++d3_transitionId, ns = this.namespace, subgroups = [], subgroup, group, node, transition;
9157 for (var j = 0, m = this.length; j < m; j++) {
9158 subgroups.push(subgroup = []);
9159 for (var group = this[j], i = 0, n = group.length; i < n; i++) {
9160 if (node = group[i]) {
9161 transition = node[ns][id0];
9162 d3_transitionNode(node, i, ns, id1, {
9163 time: transition.time,
9164 ease: transition.ease,
9165 delay: transition.delay + transition.duration,
9166 duration: transition.duration
9167 });
9168 }
9169 subgroup.push(node);
9170 }
9171 }
9172 return d3_transition(subgroups, ns, id1);
9173 };
9174 function d3_transitionNamespace(name) {
9175 return name == null ? "__transition__" : "__transition_" + name + "__";
9176 }
9177 function d3_transitionNode(node, i, ns, id, inherit) {
9178 var lock = node[ns] || (node[ns] = {
9179 active: 0,
9180 count: 0
9181 }), transition = lock[id];
9182 if (!transition) {
9183 var time = inherit.time;
9184 transition = lock[id] = {
9185 tween: new d3_Map(),
9186 time: time,
9187 delay: inherit.delay,
9188 duration: inherit.duration,
9189 ease: inherit.ease,
9190 index: i
9191 };
9192 inherit = null;
9193 ++lock.count;
9194 d3.timer(function(elapsed) {
9195 var delay = transition.delay, duration, ease, timer = d3_timer_active, tweened = [];
9196 timer.t = delay + time;
9197 if (delay <= elapsed) return start(elapsed - delay);
9198 timer.c = start;
9199 function start(elapsed) {
9200 if (lock.active > id) return stop();
9201 var active = lock[lock.active];
9202 if (active) {
9203 --lock.count;
9204 delete lock[lock.active];
9205 active.event && active.event.interrupt.call(node, node.__data__, active.index);
9206 }
9207 lock.active = id;
9208 transition.event && transition.event.start.call(node, node.__data__, i);
9209 transition.tween.forEach(function(key, value) {
9210 if (value = value.call(node, node.__data__, i)) {
9211 tweened.push(value);
9212 }
9213 });
9214 ease = transition.ease;
9215 duration = transition.duration;
9216 d3.timer(function() {
9217 timer.c = tick(elapsed || 1) ? d3_true : tick;
9218 return 1;
9219 }, 0, time);
9220 }
9221 function tick(elapsed) {
9222 if (lock.active !== id) return 1;
9223 var t = elapsed / duration, e = ease(t), n = tweened.length;
9224 while (n > 0) {
9225 tweened[--n].call(node, e);
9226 }
9227 if (t >= 1) {
9228 transition.event && transition.event.end.call(node, node.__data__, i);
9229 return stop();
9230 }
9231 }
9232 function stop() {
9233 if (--lock.count) delete lock[id]; else delete node[ns];
9234 return 1;
9235 }
9236 }, 0, time);
9237 }
9238 }
9239 d3.svg.axis = function() {
9240 var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, innerTickSize = 6, outerTickSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_;
9241 function axis(g) {
9242 g.each(function() {
9243 var g = d3.select(this);
9244 var scale0 = this.__chart__ || scale, scale1 = this.__chart__ = scale.copy();
9245 var ticks = tickValues == null ? scale1.ticks ? scale1.ticks.apply(scale1, tickArguments_) : scale1.domain() : tickValues, tickFormat = tickFormat_ == null ? scale1.tickFormat ? scale1.tickFormat.apply(scale1, tickArguments_) : d3_identity : tickFormat_, tick = g.selectAll(".tick").data(ticks, scale1), tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick").style("opacity", ε), tickExit = d3.transition(tick.exit()).style("opacity", ε).remove(), tickUpdate = d3.transition(tick.order()).style("opacity", 1), tickSpacing = Math.max(innerTickSize, 0) + tickPadding, tickTransform;
9246 var range = d3_scaleRange(scale1), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"),
9247 d3.transition(path));
9248 tickEnter.append("line");
9249 tickEnter.append("text");
9250 var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text"), sign = orient === "top" || orient === "left" ? -1 : 1, x1, x2, y1, y2;
9251 if (orient === "bottom" || orient === "top") {
9252 tickTransform = d3_svg_axisX, x1 = "x", y1 = "y", x2 = "x2", y2 = "y2";
9253 text.attr("dy", sign < 0 ? "0em" : ".71em").style("text-anchor", "middle");
9254 pathUpdate.attr("d", "M" + range[0] + "," + sign * outerTickSize + "V0H" + range[1] + "V" + sign * outerTickSize);
9255 } else {
9256 tickTransform = d3_svg_axisY, x1 = "y", y1 = "x", x2 = "y2", y2 = "x2";
9257 text.attr("dy", ".32em").style("text-anchor", sign < 0 ? "end" : "start");
9258 pathUpdate.attr("d", "M" + sign * outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + sign * outerTickSize);
9259 }
9260 lineEnter.attr(y2, sign * innerTickSize);
9261 textEnter.attr(y1, sign * tickSpacing);
9262 lineUpdate.attr(x2, 0).attr(y2, sign * innerTickSize);
9263 textUpdate.attr(x1, 0).attr(y1, sign * tickSpacing);
9264 if (scale1.rangeBand) {
9265 var x = scale1, dx = x.rangeBand() / 2;
9266 scale0 = scale1 = function(d) {
9267 return x(d) + dx;
9268 };
9269 } else if (scale0.rangeBand) {
9270 scale0 = scale1;
9271 } else {
9272 tickExit.call(tickTransform, scale1, scale0);
9273 }
9274 tickEnter.call(tickTransform, scale0, scale1);
9275 tickUpdate.call(tickTransform, scale1, scale1);
9276 });
9277 }
9278 axis.scale = function(x) {
9279 if (!arguments.length) return scale;
9280 scale = x;
9281 return axis;
9282 };
9283 axis.orient = function(x) {
9284 if (!arguments.length) return orient;
9285 orient = x in d3_svg_axisOrients ? x + "" : d3_svg_axisDefaultOrient;
9286 return axis;
9287 };
9288 axis.ticks = function() {
9289 if (!arguments.length) return tickArguments_;
9290 tickArguments_ = arguments;
9291 return axis;
9292 };
9293 axis.tickValues = function(x) {
9294 if (!arguments.length) return tickValues;
9295 tickValues = x;
9296 return axis;
9297 };
9298 axis.tickFormat = function(x) {
9299 if (!arguments.length) return tickFormat_;
9300 tickFormat_ = x;
9301 return axis;
9302 };
9303 axis.tickSize = function(x) {
9304 var n = arguments.length;
9305 if (!n) return innerTickSize;
9306 innerTickSize = +x;
9307 outerTickSize = +arguments[n - 1];
9308 return axis;
9309 };
9310 axis.innerTickSize = function(x) {
9311 if (!arguments.length) return innerTickSize;
9312 innerTickSize = +x;
9313 return axis;
9314 };
9315 axis.outerTickSize = function(x) {
9316 if (!arguments.length) return outerTickSize;
9317 outerTickSize = +x;
9318 return axis;
9319 };
9320 axis.tickPadding = function(x) {
9321 if (!arguments.length) return tickPadding;
9322 tickPadding = +x;
9323 return axis;
9324 };
9325 axis.tickSubdivide = function() {
9326 return arguments.length && axis;
9327 };
9328 return axis;
9329 };
9330 var d3_svg_axisDefaultOrient = "bottom", d3_svg_axisOrients = {
9331 top: 1,
9332 right: 1,
9333 bottom: 1,
9334 left: 1
9335 };
9336 function d3_svg_axisX(selection, x0, x1) {
9337 selection.attr("transform", function(d) {
9338 var v0 = x0(d);
9339 return "translate(" + (isFinite(v0) ? v0 : x1(d)) + ",0)";
9340 });
9341 }
9342 function d3_svg_axisY(selection, y0, y1) {
9343 selection.attr("transform", function(d) {
9344 var v0 = y0(d);
9345 return "translate(0," + (isFinite(v0) ? v0 : y1(d)) + ")";
9346 });
9347 }
9348 d3.svg.brush = function() {
9349 var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, xExtent = [ 0, 0 ], yExtent = [ 0, 0 ], xExtentDomain, yExtentDomain, xClamp = true, yClamp = true, resizes = d3_svg_brushResizes[0];
9350 function brush(g) {
9351 g.each(function() {
9352 var g = d3.select(this).style("pointer-events", "all").style("-webkit-tap-highlight-color", "rgba(0,0,0,0)").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart);
9353 var background = g.selectAll(".background").data([ 0 ]);
9354 background.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair");
9355 g.selectAll(".extent").data([ 0 ]).enter().append("rect").attr("class", "extent").style("cursor", "move");
9356 var resize = g.selectAll(".resize").data(resizes, d3_identity);
9357 resize.exit().remove();
9358 resize.enter().append("g").attr("class", function(d) {
9359 return "resize " + d;
9360 }).style("cursor", function(d) {
9361 return d3_svg_brushCursor[d];
9362 }).append("rect").attr("x", function(d) {
9363 return /[ew]$/.test(d) ? -3 : null;
9364 }).attr("y", function(d) {
9365 return /^[ns]/.test(d) ? -3 : null;
9366 }).attr("width", 6).attr("height", 6).style("visibility", "hidden");
9367 resize.style("display", brush.empty() ? "none" : null);
9368 var gUpdate = d3.transition(g), backgroundUpdate = d3.transition(background), range;
9369 if (x) {
9370 range = d3_scaleRange(x);
9371 backgroundUpdate.attr("x", range[0]).attr("width", range[1] - range[0]);
9372 redrawX(gUpdate);
9373 }
9374 if (y) {
9375 range = d3_scaleRange(y);
9376 backgroundUpdate.attr("y", range[0]).attr("height", range[1] - range[0]);
9377 redrawY(gUpdate);
9378 }
9379 redraw(gUpdate);
9380 });
9381 }
9382 brush.event = function(g) {
9383 g.each(function() {
9384 var event_ = event.of(this, arguments), extent1 = {
9385 x: xExtent,
9386 y: yExtent,
9387 i: xExtentDomain,
9388 j: yExtentDomain
9389 }, extent0 = this.__chart__ || extent1;
9390 this.__chart__ = extent1;
9391 if (d3_transitionInheritId) {
9392 d3.select(this).transition().each("start.brush", function() {
9393 xExtentDomain = extent0.i;
9394 yExtentDomain = extent0.j;
9395 xExtent = extent0.x;
9396 yExtent = extent0.y;
9397 event_({
9398 type: "brushstart"
9399 });
9400 }).tween("brush:brush", function() {
9401 var xi = d3_interpolateArray(xExtent, extent1.x), yi = d3_interpolateArray(yExtent, extent1.y);
9402 xExtentDomain = yExtentDomain = null;
9403 return function(t) {
9404 xExtent = extent1.x = xi(t);
9405 yExtent = extent1.y = yi(t);
9406 event_({
9407 type: "brush",
9408 mode: "resize"
9409 });
9410 };
9411 }).each("end.brush", function() {
9412 xExtentDomain = extent1.i;
9413 yExtentDomain = extent1.j;
9414 event_({
9415 type: "brush",
9416 mode: "resize"
9417 });
9418 event_({
9419 type: "brushend"
9420 });
9421 });
9422 } else {
9423 event_({
9424 type: "brushstart"
9425 });
9426 event_({
9427 type: "brush",
9428 mode: "resize"
9429 });
9430 event_({
9431 type: "brushend"
9432 });
9433 }
9434 });
9435 };
9436 function redraw(g) {
9437 g.selectAll(".resize").attr("transform", function(d) {
9438 return "translate(" + xExtent[+/e$/.test(d)] + "," + yExtent[+/^s/.test(d)] + ")";
9439 });
9440 }
9441 function redrawX(g) {
9442 g.select(".extent").attr("x", xExtent[0]);
9443 g.selectAll(".extent,.n>rect,.s>rect").attr("width", xExtent[1] - xExtent[0]);
9444 }
9445 function redrawY(g) {
9446 g.select(".extent").attr("y", yExtent[0]);
9447 g.selectAll(".extent,.e>rect,.w>rect").attr("height", yExtent[1] - yExtent[0]);
9448 }
9449 function brushstart() {
9450 var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed("extent"), dragRestore = d3_event_dragSuppress(), center, origin = d3.mouse(target), offset;
9451 var w = d3.select(d3_window).on("keydown.brush", keydown).on("keyup.brush", keyup);
9452 if (d3.event.changedTouches) {
9453 w.on("touchmove.brush", brushmove).on("touchend.brush", brushend);
9454 } else {
9455 w.on("mousemove.brush", brushmove).on("mouseup.brush", brushend);
9456 }
9457 g.interrupt().selectAll("*").interrupt();
9458 if (dragging) {
9459 origin[0] = xExtent[0] - origin[0];
9460 origin[1] = yExtent[0] - origin[1];
9461 } else if (resizing) {
9462 var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing);
9463 offset = [ xExtent[1 - ex] - origin[0], yExtent[1 - ey] - origin[1] ];
9464 origin[0] = xExtent[ex];
9465 origin[1] = yExtent[ey];
9466 } else if (d3.event.altKey) center = origin.slice();
9467 g.style("pointer-events", "none").selectAll(".resize").style("display", null);
9468 d3.select("body").style("cursor", eventTarget.style("cursor"));
9469 event_({
9470 type: "brushstart"
9471 });
9472 brushmove();
9473 function keydown() {
9474 if (d3.event.keyCode == 32) {
9475 if (!dragging) {
9476 center = null;
9477 origin[0] -= xExtent[1];
9478 origin[1] -= yExtent[1];
9479 dragging = 2;
9480 }
9481 d3_eventPreventDefault();
9482 }
9483 }
9484 function keyup() {
9485 if (d3.event.keyCode == 32 && dragging == 2) {
9486 origin[0] += xExtent[1];
9487 origin[1] += yExtent[1];
9488 dragging = 0;
9489 d3_eventPreventDefault();
9490 }
9491 }
9492 function brushmove() {
9493 var point = d3.mouse(target), moved = false;
9494 if (offset) {
9495 point[0] += offset[0];
9496 point[1] += offset[1];
9497 }
9498 if (!dragging) {
9499 if (d3.event.altKey) {
9500 if (!center) center = [ (xExtent[0] + xExtent[1]) / 2, (yExtent[0] + yExtent[1]) / 2 ];
9501 origin[0] = xExtent[+(point[0] < center[0])];
9502 origin[1] = yExtent[+(point[1] < center[1])];
9503 } else center = null;
9504 }
9505 if (resizingX && move1(point, x, 0)) {
9506 redrawX(g);
9507 moved = true;
9508 }
9509 if (resizingY && move1(point, y, 1)) {
9510 redrawY(g);
9511 moved = true;
9512 }
9513 if (moved) {
9514 redraw(g);
9515 event_({
9516 type: "brush",
9517 mode: dragging ? "move" : "resize"
9518 });
9519 }
9520 }
9521 function move1(point, scale, i) {
9522 var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], extent = i ? yExtent : xExtent, size = extent[1] - extent[0], min, max;
9523 if (dragging) {
9524 r0 -= position;
9525 r1 -= size + position;
9526 }
9527 min = (i ? yClamp : xClamp) ? Math.max(r0, Math.min(r1, point[i])) : point[i];
9528 if (dragging) {
9529 max = (min += position) + size;
9530 } else {
9531 if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min));
9532 if (position < min) {
9533 max = min;
9534 min = position;
9535 } else {
9536 max = position;
9537 }
9538 }
9539 if (extent[0] != min || extent[1] != max) {
9540 if (i) yExtentDomain = null; else xExtentDomain = null;
9541 extent[0] = min;
9542 extent[1] = max;
9543 return true;
9544 }
9545 }
9546 function brushend() {
9547 brushmove();
9548 g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null);
9549 d3.select("body").style("cursor", null);
9550 w.on("mousemove.brush", null).on("mouseup.brush", null).on("touchmove.brush", null).on("touchend.brush", null).on("keydown.brush", null).on("keyup.brush", null);
9551 dragRestore();
9552 event_({
9553 type: "brushend"
9554 });
9555 }
9556 }
9557 brush.x = function(z) {
9558 if (!arguments.length) return x;
9559 x = z;
9560 resizes = d3_svg_brushResizes[!x << 1 | !y];
9561 return brush;
9562 };
9563 brush.y = function(z) {
9564 if (!arguments.length) return y;
9565 y = z;
9566 resizes = d3_svg_brushResizes[!x << 1 | !y];
9567 return brush;
9568 };
9569 brush.clamp = function(z) {
9570 if (!arguments.length) return x && y ? [ xClamp, yClamp ] : x ? xClamp : y ? yClamp : null;
9571 if (x && y) xClamp = !!z[0], yClamp = !!z[1]; else if (x) xClamp = !!z; else if (y) yClamp = !!z;
9572 return brush;
9573 };
9574 brush.extent = function(z) {
9575 var x0, x1, y0, y1, t;
9576 if (!arguments.length) {
9577 if (x) {
9578 if (xExtentDomain) {
9579 x0 = xExtentDomain[0], x1 = xExtentDomain[1];
9580 } else {
9581 x0 = xExtent[0], x1 = xExtent[1];
9582 if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1);
9583 if (x1 < x0) t = x0, x0 = x1, x1 = t;
9584 }
9585 }
9586 if (y) {
9587 if (yExtentDomain) {
9588 y0 = yExtentDomain[0], y1 = yExtentDomain[1];
9589 } else {
9590 y0 = yExtent[0], y1 = yExtent[1];
9591 if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1);
9592 if (y1 < y0) t = y0, y0 = y1, y1 = t;
9593 }
9594 }
9595 return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ];
9596 }
9597 if (x) {
9598 x0 = z[0], x1 = z[1];
9599 if (y) x0 = x0[0], x1 = x1[0];
9600 xExtentDomain = [ x0, x1 ];
9601 if (x.invert) x0 = x(x0), x1 = x(x1);
9602 if (x1 < x0) t = x0, x0 = x1, x1 = t;
9603 if (x0 != xExtent[0] || x1 != xExtent[1]) xExtent = [ x0, x1 ];
9604 }
9605 if (y) {
9606 y0 = z[0], y1 = z[1];
9607 if (x) y0 = y0[1], y1 = y1[1];
9608 yExtentDomain = [ y0, y1 ];
9609 if (y.invert) y0 = y(y0), y1 = y(y1);
9610 if (y1 < y0) t = y0, y0 = y1, y1 = t;
9611 if (y0 != yExtent[0] || y1 != yExtent[1]) yExtent = [ y0, y1 ];
9612 }
9613 return brush;
9614 };
9615 brush.clear = function() {
9616 if (!brush.empty()) {
9617 xExtent = [ 0, 0 ], yExtent = [ 0, 0 ];
9618 xExtentDomain = yExtentDomain = null;
9619 }
9620 return brush;
9621 };
9622 brush.empty = function() {
9623 return !!x && xExtent[0] == xExtent[1] || !!y && yExtent[0] == yExtent[1];
9624 };
9625 return d3.rebind(brush, event, "on");
9626 };
9627 var d3_svg_brushCursor = {
9628 n: "ns-resize",
9629 e: "ew-resize",
9630 s: "ns-resize",
9631 w: "ew-resize",
9632 nw: "nwse-resize",
9633 ne: "nesw-resize",
9634 se: "nwse-resize",
9635 sw: "nesw-resize"
9636 };
9637 var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ];
9638 var d3_time_format = d3_time.format = d3_locale_enUS.timeFormat;
9639 var d3_time_formatUtc = d3_time_format.utc;
9640 var d3_time_formatIso = d3_time_formatUtc("%Y-%m-%dT%H:%M:%S.%LZ");
9641 d3_time_format.iso = Date.prototype.toISOString && +new Date("2000-01-01T00:00:00.000Z") ? d3_time_formatIsoNative : d3_time_formatIso;
9642 function d3_time_formatIsoNative(date) {
9643 return date.toISOString();
9644 }
9645 d3_time_formatIsoNative.parse = function(string) {
9646 var date = new Date(string);
9647 return isNaN(date) ? null : date;
9648 };
9649 d3_time_formatIsoNative.toString = d3_time_formatIso.toString;
9650 d3_time.second = d3_time_interval(function(date) {
9651 return new d3_date(Math.floor(date / 1e3) * 1e3);
9652 }, function(date, offset) {
9653 date.setTime(date.getTime() + Math.floor(offset) * 1e3);
9654 }, function(date) {
9655 return date.getSeconds();
9656 });
9657 d3_time.seconds = d3_time.second.range;
9658 d3_time.seconds.utc = d3_time.second.utc.range;
9659 d3_time.minute = d3_time_interval(function(date) {
9660 return new d3_date(Math.floor(date / 6e4) * 6e4);
9661 }, function(date, offset) {
9662 date.setTime(date.getTime() + Math.floor(offset) * 6e4);
9663 }, function(date) {
9664 return date.getMinutes();
9665 });
9666 d3_time.minutes = d3_time.minute.range;
9667 d3_time.minutes.utc = d3_time.minute.utc.range;
9668 d3_time.hour = d3_time_interval(function(date) {
9669 var timezone = date.getTimezoneOffset() / 60;
9670 return new d3_date((Math.floor(date / 36e5 - timezone) + timezone) * 36e5);
9671 }, function(date, offset) {
9672 date.setTime(date.getTime() + Math.floor(offset) * 36e5);
9673 }, function(date) {
9674 return date.getHours();
9675 });
9676 d3_time.hours = d3_time.hour.range;
9677 d3_time.hours.utc = d3_time.hour.utc.range;
9678 d3_time.month = d3_time_interval(function(date) {
9679 date = d3_time.day(date);
9680 date.setDate(1);
9681 return date;
9682 }, function(date, offset) {
9683 date.setMonth(date.getMonth() + offset);
9684 }, function(date) {
9685 return date.getMonth();
9686 });
9687 d3_time.months = d3_time.month.range;
9688 d3_time.months.utc = d3_time.month.utc.range;
9689 function d3_time_scale(linear, methods, format) {
9690 function scale(x) {
9691 return linear(x);
9692 }
9693 scale.invert = function(x) {
9694 return d3_time_scaleDate(linear.invert(x));
9695 };
9696 scale.domain = function(x) {
9697 if (!arguments.length) return linear.domain().map(d3_time_scaleDate);
9698 linear.domain(x);
9699 return scale;
9700 };
9701 function tickMethod(extent, count) {
9702 var span = extent[1] - extent[0], target = span / count, i = d3.bisect(d3_time_scaleSteps, target);
9703 return i == d3_time_scaleSteps.length ? [ methods.year, d3_scale_linearTickRange(extent.map(function(d) {
9704 return d / 31536e6;
9705 }), count)[2] ] : !i ? [ d3_time_scaleMilliseconds, d3_scale_linearTickRange(extent, count)[2] ] : methods[target / d3_time_scaleSteps[i - 1] < d3_time_scaleSteps[i] / target ? i - 1 : i];
9706 }
9707 scale.nice = function(interval, skip) {
9708 var domain = scale.domain(), extent = d3_scaleExtent(domain), method = interval == null ? tickMethod(extent, 10) : typeof interval === "number" && tickMethod(extent, interval);
9709 if (method) interval = method[0], skip = method[1];
9710 function skipped(date) {
9711 return !isNaN(date) && !interval.range(date, d3_time_scaleDate(+date + 1), skip).length;
9712 }
9713 return scale.domain(d3_scale_nice(domain, skip > 1 ? {
9714 floor: function(date) {
9715 while (skipped(date = interval.floor(date))) date = d3_time_scaleDate(date - 1);
9716 return date;
9717 },
9718 ceil: function(date) {
9719 while (skipped(date = interval.ceil(date))) date = d3_time_scaleDate(+date + 1);
9720 return date;
9721 }
9722 } : interval));
9723 };
9724 scale.ticks = function(interval, skip) {
9725 var extent = d3_scaleExtent(scale.domain()), method = interval == null ? tickMethod(extent, 10) : typeof interval === "number" ? tickMethod(extent, interval) : !interval.range && [ {
9726 range: interval
9727 }, skip ];
9728 if (method) interval = method[0], skip = method[1];
9729 return interval.range(extent[0], d3_time_scaleDate(+extent[1] + 1), skip < 1 ? 1 : skip);
9730 };
9731 scale.tickFormat = function() {
9732 return format;
9733 };
9734 scale.copy = function() {
9735 return d3_time_scale(linear.copy(), methods, format);
9736 };
9737 return d3_scale_linearRebind(scale, linear);
9738 }
9739 function d3_time_scaleDate(t) {
9740 return new Date(t);
9741 }
9742 var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ];
9743 var d3_time_scaleLocalMethods = [ [ d3_time.second, 1 ], [ d3_time.second, 5 ], [ d3_time.second, 15 ], [ d3_time.second, 30 ], [ d3_time.minute, 1 ], [ d3_time.minute, 5 ], [ d3_time.minute, 15 ], [ d3_time.minute, 30 ], [ d3_time.hour, 1 ], [ d3_time.hour, 3 ], [ d3_time.hour, 6 ], [ d3_time.hour, 12 ], [ d3_time.day, 1 ], [ d3_time.day, 2 ], [ d3_time.week, 1 ], [ d3_time.month, 1 ], [ d3_time.month, 3 ], [ d3_time.year, 1 ] ];
9744 var d3_time_scaleLocalFormat = d3_time_format.multi([ [ ".%L", function(d) {
9745 return d.getMilliseconds();
9746 } ], [ ":%S", function(d) {
9747 return d.getSeconds();
9748 } ], [ "%I:%M", function(d) {
9749 return d.getMinutes();
9750 } ], [ "%I %p", function(d) {
9751 return d.getHours();
9752 } ], [ "%a %d", function(d) {
9753 return d.getDay() && d.getDate() != 1;
9754 } ], [ "%b %d", function(d) {
9755 return d.getDate() != 1;
9756 } ], [ "%B", function(d) {
9757 return d.getMonth();
9758 } ], [ "%Y", d3_true ] ]);
9759 var d3_time_scaleMilliseconds = {
9760 range: function(start, stop, step) {
9761 return d3.range(Math.ceil(start / step) * step, +stop, step).map(d3_time_scaleDate);
9762 },
9763 floor: d3_identity,
9764 ceil: d3_identity
9765 };
9766 d3_time_scaleLocalMethods.year = d3_time.year;
9767 d3_time.scale = function() {
9768 return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat);
9769 };
9770 var d3_time_scaleUtcMethods = d3_time_scaleLocalMethods.map(function(m) {
9771 return [ m[0].utc, m[1] ];
9772 });
9773 var d3_time_scaleUtcFormat = d3_time_formatUtc.multi([ [ ".%L", function(d) {
9774 return d.getUTCMilliseconds();
9775 } ], [ ":%S", function(d) {
9776 return d.getUTCSeconds();
9777 } ], [ "%I:%M", function(d) {
9778 return d.getUTCMinutes();
9779 } ], [ "%I %p", function(d) {
9780 return d.getUTCHours();
9781 } ], [ "%a %d", function(d) {
9782 return d.getUTCDay() && d.getUTCDate() != 1;
9783 } ], [ "%b %d", function(d) {
9784 return d.getUTCDate() != 1;
9785 } ], [ "%B", function(d) {
9786 return d.getUTCMonth();
9787 } ], [ "%Y", d3_true ] ]);
9788 d3_time_scaleUtcMethods.year = d3_time.year.utc;
9789 d3_time.scale.utc = function() {
9790 return d3_time_scale(d3.scale.linear(), d3_time_scaleUtcMethods, d3_time_scaleUtcFormat);
9791 };
9792 d3.text = d3_xhrType(function(request) {
9793 return request.responseText;
9794 });
9795 d3.json = function(url, callback) {
9796 return d3_xhr(url, "application/json", d3_json, callback);
9797 };
9798 function d3_json(request) {
9799 return JSON.parse(request.responseText);
9800 }
9801 d3.html = function(url, callback) {
9802 return d3_xhr(url, "text/html", d3_html, callback);
9803 };
9804 function d3_html(request) {
9805 var range = d3_document.createRange();
9806 range.selectNode(d3_document.body);
9807 return range.createContextualFragment(request.responseText);
9808 }
9809 d3.xml = d3_xhrType(function(request) {
9810 return request.responseXML;
9811 });
9812 if (typeof define === "function" && define.amd) define(d3); else if (typeof module === "object" && module.exports) module.exports = d3;
9813 this.d3 = d3;
9814 }();
9815 (function(exports){
9816 crossfilter.version = "1.3.11";
9817 function crossfilter_identity(d) {
9818 return d;
9819 }
9820 crossfilter.permute = permute;
9821
9822 function permute(array, index) {
9823 for (var i = 0, n = index.length, copy = new Array(n); i < n; ++i) {
9824 copy[i] = array[index[i]];
9825 }
9826 return copy;
9827 }
9828 var bisect = crossfilter.bisect = bisect_by(crossfilter_identity);
9829
9830 bisect.by = bisect_by;
9831
9832 function bisect_by(f) {
9833
9834 // Locate the insertion point for x in a to maintain sorted order. The
9835 // arguments lo and hi may be used to specify a subset of the array which
9836 // should be considered; by default the entire array is used. If x is already
9837 // present in a, the insertion point will be before (to the left of) any
9838 // existing entries. The return value is suitable for use as the first
9839 // argument to `array.splice` assuming that a is already sorted.
9840 //
9841 // The returned insertion point i partitions the array a into two halves so
9842 // that all v < x for v in a[lo:i] for the left side and all v >= x for v in
9843 // a[i:hi] for the right side.
9844 function bisectLeft(a, x, lo, hi) {
9845 while (lo < hi) {
9846 var mid = lo + hi >>> 1;
9847 if (f(a[mid]) < x) lo = mid + 1;
9848 else hi = mid;
9849 }
9850 return lo;
9851 }
9852
9853 // Similar to bisectLeft, but returns an insertion point which comes after (to
9854 // the right of) any existing entries of x in a.
9855 //
9856 // The returned insertion point i partitions the array into two halves so that
9857 // all v <= x for v in a[lo:i] for the left side and all v > x for v in
9858 // a[i:hi] for the right side.
9859 function bisectRight(a, x, lo, hi) {
9860 while (lo < hi) {
9861 var mid = lo + hi >>> 1;
9862 if (x < f(a[mid])) hi = mid;
9863 else lo = mid + 1;
9864 }
9865 return lo;
9866 }
9867
9868 bisectRight.right = bisectRight;
9869 bisectRight.left = bisectLeft;
9870 return bisectRight;
9871 }
9872 var heap = crossfilter.heap = heap_by(crossfilter_identity);
9873
9874 heap.by = heap_by;
9875
9876 function heap_by(f) {
9877
9878 // Builds a binary heap within the specified array a[lo:hi]. The heap has the
9879 // property such that the parent a[lo+i] is always less than or equal to its
9880 // two children: a[lo+2*i+1] and a[lo+2*i+2].
9881 function heap(a, lo, hi) {
9882 var n = hi - lo,
9883 i = (n >>> 1) + 1;
9884 while (--i > 0) sift(a, i, n, lo);
9885 return a;
9886 }
9887
9888 // Sorts the specified array a[lo:hi] in descending order, assuming it is
9889 // already a heap.
9890 function sort(a, lo, hi) {
9891 var n = hi - lo,
9892 t;
9893 while (--n > 0) t = a[lo], a[lo] = a[lo + n], a[lo + n] = t, sift(a, 1, n, lo);
9894 return a;
9895 }
9896
9897 // Sifts the element a[lo+i-1] down the heap, where the heap is the contiguous
9898 // slice of array a[lo:lo+n]. This method can also be used to update the heap
9899 // incrementally, without incurring the full cost of reconstructing the heap.
9900 function sift(a, i, n, lo) {
9901 var d = a[--lo + i],
9902 x = f(d),
9903 child;
9904 while ((child = i << 1) <= n) {
9905 if (child < n && f(a[lo + child]) > f(a[lo + child + 1])) child++;
9906 if (x <= f(a[lo + child])) break;
9907 a[lo + i] = a[lo + child];
9908 i = child;
9909 }
9910 a[lo + i] = d;
9911 }
9912
9913 heap.sort = sort;
9914 return heap;
9915 }
9916 var heapselect = crossfilter.heapselect = heapselect_by(crossfilter_identity);
9917
9918 heapselect.by = heapselect_by;
9919
9920 function heapselect_by(f) {
9921 var heap = heap_by(f);
9922
9923 // Returns a new array containing the top k elements in the array a[lo:hi].
9924 // The returned array is not sorted, but maintains the heap property. If k is
9925 // greater than hi - lo, then fewer than k elements will be returned. The
9926 // order of elements in a is unchanged by this operation.
9927 function heapselect(a, lo, hi, k) {
9928 var queue = new Array(k = Math.min(hi - lo, k)),
9929 min,
9930 i,
9931 x,
9932 d;
9933
9934 for (i = 0; i < k; ++i) queue[i] = a[lo++];
9935 heap(queue, 0, k);
9936
9937 if (lo < hi) {
9938 min = f(queue[0]);
9939 do {
9940 if (x = f(d = a[lo]) > min) {
9941 queue[0] = d;
9942 min = f(heap(queue, 0, k)[0]);
9943 }
9944 } while (++lo < hi);
9945 }
9946
9947 return queue;
9948 }
9949
9950 return heapselect;
9951 }
9952 var insertionsort = crossfilter.insertionsort = insertionsort_by(crossfilter_identity);
9953
9954 insertionsort.by = insertionsort_by;
9955
9956 function insertionsort_by(f) {
9957
9958 function insertionsort(a, lo, hi) {
9959 for (var i = lo + 1; i < hi; ++i) {
9960 for (var j = i, t = a[i], x = f(t); j > lo && f(a[j - 1]) > x; --j) {
9961 a[j] = a[j - 1];
9962 }
9963 a[j] = t;
9964 }
9965 return a;
9966 }
9967
9968 return insertionsort;
9969 }
9970 // Algorithm designed by Vladimir Yaroslavskiy.
9971 // Implementation based on the Dart project; see lib/dart/LICENSE for details.
9972
9973 var quicksort = crossfilter.quicksort = quicksort_by(crossfilter_identity);
9974
9975 quicksort.by = quicksort_by;
9976
9977 function quicksort_by(f) {
9978 var insertionsort = insertionsort_by(f);
9979
9980 function sort(a, lo, hi) {
9981 return (hi - lo < quicksort_sizeThreshold
9982 ? insertionsort
9983 : quicksort)(a, lo, hi);
9984 }
9985
9986 function quicksort(a, lo, hi) {
9987 // Compute the two pivots by looking at 5 elements.
9988 var sixth = (hi - lo) / 6 | 0,
9989 i1 = lo + sixth,
9990 i5 = hi - 1 - sixth,
9991 i3 = lo + hi - 1 >> 1, // The midpoint.
9992 i2 = i3 - sixth,
9993 i4 = i3 + sixth;
9994
9995 var e1 = a[i1], x1 = f(e1),
9996 e2 = a[i2], x2 = f(e2),
9997 e3 = a[i3], x3 = f(e3),
9998 e4 = a[i4], x4 = f(e4),
9999 e5 = a[i5], x5 = f(e5);
10000
10001 var t;
10002
10003 // Sort the selected 5 elements using a sorting network.
10004 if (x1 > x2) t = e1, e1 = e2, e2 = t, t = x1, x1 = x2, x2 = t;
10005 if (x4 > x5) t = e4, e4 = e5, e5 = t, t = x4, x4 = x5, x5 = t;
10006 if (x1 > x3) t = e1, e1 = e3, e3 = t, t = x1, x1 = x3, x3 = t;
10007 if (x2 > x3) t = e2, e2 = e3, e3 = t, t = x2, x2 = x3, x3 = t;
10008 if (x1 > x4) t = e1, e1 = e4, e4 = t, t = x1, x1 = x4, x4 = t;
10009 if (x3 > x4) t = e3, e3 = e4, e4 = t, t = x3, x3 = x4, x4 = t;
10010 if (x2 > x5) t = e2, e2 = e5, e5 = t, t = x2, x2 = x5, x5 = t;
10011 if (x2 > x3) t = e2, e2 = e3, e3 = t, t = x2, x2 = x3, x3 = t;
10012 if (x4 > x5) t = e4, e4 = e5, e5 = t, t = x4, x4 = x5, x5 = t;
10013
10014 var pivot1 = e2, pivotValue1 = x2,
10015 pivot2 = e4, pivotValue2 = x4;
10016
10017 // e2 and e4 have been saved in the pivot variables. They will be written
10018 // back, once the partitioning is finished.
10019 a[i1] = e1;
10020 a[i2] = a[lo];
10021 a[i3] = e3;
10022 a[i4] = a[hi - 1];
10023 a[i5] = e5;
10024
10025 var less = lo + 1, // First element in the middle partition.
10026 great = hi - 2; // Last element in the middle partition.
10027
10028 // Note that for value comparison, <, <=, >= and > coerce to a primitive via
10029 // Object.prototype.valueOf; == and === do not, so in order to be consistent
10030 // with natural order (such as for Date objects), we must do two compares.
10031 var pivotsEqual = pivotValue1 <= pivotValue2 && pivotValue1 >= pivotValue2;
10032 if (pivotsEqual) {
10033
10034 // Degenerated case where the partitioning becomes a dutch national flag
10035 // problem.
10036 //
10037 // [ | < pivot | == pivot | unpartitioned | > pivot | ]
10038 // ^ ^ ^ ^ ^
10039 // left less k great right
10040 //
10041 // a[left] and a[right] are undefined and are filled after the
10042 // partitioning.
10043 //
10044 // Invariants:
10045 // 1) for x in ]left, less[ : x < pivot.
10046 // 2) for x in [less, k[ : x == pivot.
10047 // 3) for x in ]great, right[ : x > pivot.
10048 for (var k = less; k <= great; ++k) {
10049 var ek = a[k], xk = f(ek);
10050 if (xk < pivotValue1) {
10051 if (k !== less) {
10052 a[k] = a[less];
10053 a[less] = ek;
10054 }
10055 ++less;
10056 } else if (xk > pivotValue1) {
10057
10058 // Find the first element <= pivot in the range [k - 1, great] and
10059 // put [:ek:] there. We know that such an element must exist:
10060 // When k == less, then el3 (which is equal to pivot) lies in the
10061 // interval. Otherwise a[k - 1] == pivot and the search stops at k-1.
10062 // Note that in the latter case invariant 2 will be violated for a
10063 // short amount of time. The invariant will be restored when the
10064 // pivots are put into their final positions.
10065 while (true) {
10066 var greatValue = f(a[great]);
10067 if (greatValue > pivotValue1) {
10068 great--;
10069 // This is the only location in the while-loop where a new
10070 // iteration is started.
10071 continue;
10072 } else if (greatValue < pivotValue1) {
10073 // Triple exchange.
10074 a[k] = a[less];
10075 a[less++] = a[great];
10076 a[great--] = ek;
10077 break;
10078 } else {
10079 a[k] = a[great];
10080 a[great--] = ek;
10081 // Note: if great < k then we will exit the outer loop and fix
10082 // invariant 2 (which we just violated).
10083 break;
10084 }
10085 }
10086 }
10087 }
10088 } else {
10089
10090 // We partition the list into three parts:
10091 // 1. < pivot1
10092 // 2. >= pivot1 && <= pivot2
10093 // 3. > pivot2
10094 //
10095 // During the loop we have:
10096 // [ | < pivot1 | >= pivot1 && <= pivot2 | unpartitioned | > pivot2 | ]
10097 // ^ ^ ^ ^ ^
10098 // left less k great right
10099 //
10100 // a[left] and a[right] are undefined and are filled after the
10101 // partitioning.
10102 //
10103 // Invariants:
10104 // 1. for x in ]left, less[ : x < pivot1
10105 // 2. for x in [less, k[ : pivot1 <= x && x <= pivot2
10106 // 3. for x in ]great, right[ : x > pivot2
10107 for (var k = less; k <= great; k++) {
10108 var ek = a[k], xk = f(ek);
10109 if (xk < pivotValue1) {
10110 if (k !== less) {
10111 a[k] = a[less];
10112 a[less] = ek;
10113 }
10114 ++less;
10115 } else {
10116 if (xk > pivotValue2) {
10117 while (true) {
10118 var greatValue = f(a[great]);
10119 if (greatValue > pivotValue2) {
10120 great--;
10121 if (great < k) break;
10122 // This is the only location inside the loop where a new
10123 // iteration is started.
10124 continue;
10125 } else {
10126 // a[great] <= pivot2.
10127 if (greatValue < pivotValue1) {
10128 // Triple exchange.
10129 a[k] = a[less];
10130 a[less++] = a[great];
10131 a[great--] = ek;
10132 } else {
10133 // a[great] >= pivot1.
10134 a[k] = a[great];
10135 a[great--] = ek;
10136 }
10137 break;
10138 }
10139 }
10140 }
10141 }
10142 }
10143 }
10144
10145 // Move pivots into their final positions.
10146 // We shrunk the list from both sides (a[left] and a[right] have
10147 // meaningless values in them) and now we move elements from the first
10148 // and third partition into these locations so that we can store the
10149 // pivots.
10150 a[lo] = a[less - 1];
10151 a[less - 1] = pivot1;
10152 a[hi - 1] = a[great + 1];
10153 a[great + 1] = pivot2;
10154
10155 // The list is now partitioned into three partitions:
10156 // [ < pivot1 | >= pivot1 && <= pivot2 | > pivot2 ]
10157 // ^ ^ ^ ^
10158 // left less great right
10159
10160 // Recursive descent. (Don't include the pivot values.)
10161 sort(a, lo, less - 1);
10162 sort(a, great + 2, hi);
10163
10164 if (pivotsEqual) {
10165 // All elements in the second partition are equal to the pivot. No
10166 // need to sort them.
10167 return a;
10168 }
10169
10170 // In theory it should be enough to call _doSort recursively on the second
10171 // partition.
10172 // The Android source however removes the pivot elements from the recursive
10173 // call if the second partition is too large (more than 2/3 of the list).
10174 if (less < i1 && great > i5) {
10175 var lessValue, greatValue;
10176 while ((lessValue = f(a[less])) <= pivotValue1 && lessValue >= pivotValue1) ++less;
10177 while ((greatValue = f(a[great])) <= pivotValue2 && greatValue >= pivotValue2) --great;
10178
10179 // Copy paste of the previous 3-way partitioning with adaptions.
10180 //
10181 // We partition the list into three parts:
10182 // 1. == pivot1
10183 // 2. > pivot1 && < pivot2
10184 // 3. == pivot2
10185 //
10186 // During the loop we have:
10187 // [ == pivot1 | > pivot1 && < pivot2 | unpartitioned | == pivot2 ]
10188 // ^ ^ ^
10189 // less k great
10190 //
10191 // Invariants:
10192 // 1. for x in [ *, less[ : x == pivot1
10193 // 2. for x in [less, k[ : pivot1 < x && x < pivot2
10194 // 3. for x in ]great, * ] : x == pivot2
10195 for (var k = less; k <= great; k++) {
10196 var ek = a[k], xk = f(ek);
10197 if (xk <= pivotValue1 && xk >= pivotValue1) {
10198 if (k !== less) {
10199 a[k] = a[less];
10200 a[less] = ek;
10201 }
10202 less++;
10203 } else {
10204 if (xk <= pivotValue2 && xk >= pivotValue2) {
10205 while (true) {
10206 var greatValue = f(a[great]);
10207 if (greatValue <= pivotValue2 && greatValue >= pivotValue2) {
10208 great--;
10209 if (great < k) break;
10210 // This is the only location inside the loop where a new
10211 // iteration is started.
10212 continue;
10213 } else {
10214 // a[great] < pivot2.
10215 if (greatValue < pivotValue1) {
10216 // Triple exchange.
10217 a[k] = a[less];
10218 a[less++] = a[great];
10219 a[great--] = ek;
10220 } else {
10221 // a[great] == pivot1.
10222 a[k] = a[great];
10223 a[great--] = ek;
10224 }
10225 break;
10226 }
10227 }
10228 }
10229 }
10230 }
10231 }
10232
10233 // The second partition has now been cleared of pivot elements and looks
10234 // as follows:
10235 // [ * | > pivot1 && < pivot2 | * ]
10236 // ^ ^
10237 // less great
10238 // Sort the second partition using recursive descent.
10239
10240 // The second partition looks as follows:
10241 // [ * | >= pivot1 && <= pivot2 | * ]
10242 // ^ ^
10243 // less great
10244 // Simply sort it by recursive descent.
10245
10246 return sort(a, less, great + 1);
10247 }
10248
10249 return sort;
10250 }
10251
10252 var quicksort_sizeThreshold = 32;
10253 var crossfilter_array8 = crossfilter_arrayUntyped,
10254 crossfilter_array16 = crossfilter_arrayUntyped,
10255 crossfilter_array32 = crossfilter_arrayUntyped,
10256 crossfilter_arrayLengthen = crossfilter_arrayLengthenUntyped,
10257 crossfilter_arrayWiden = crossfilter_arrayWidenUntyped;
10258
10259 if (typeof Uint8Array !== "undefined") {
10260 crossfilter_array8 = function(n) { return new Uint8Array(n); };
10261 crossfilter_array16 = function(n) { return new Uint16Array(n); };
10262 crossfilter_array32 = function(n) { return new Uint32Array(n); };
10263
10264 crossfilter_arrayLengthen = function(array, length) {
10265 if (array.length >= length) return array;
10266 var copy = new array.constructor(length);
10267 copy.set(array);
10268 return copy;
10269 };
10270
10271 crossfilter_arrayWiden = function(array, width) {
10272 var copy;
10273 switch (width) {
10274 case 16: copy = crossfilter_array16(array.length); break;
10275 case 32: copy = crossfilter_array32(array.length); break;
10276 default: throw new Error("invalid array width!");
10277 }
10278 copy.set(array);
10279 return copy;
10280 };
10281 }
10282
10283 function crossfilter_arrayUntyped(n) {
10284 var array = new Array(n), i = -1;
10285 while (++i < n) array[i] = 0;
10286 return array;
10287 }
10288
10289 function crossfilter_arrayLengthenUntyped(array, length) {
10290 var n = array.length;
10291 while (n < length) array[n++] = 0;
10292 return array;
10293 }
10294
10295 function crossfilter_arrayWidenUntyped(array, width) {
10296 if (width > 32) throw new Error("invalid array width!");
10297 return array;
10298 }
10299 function crossfilter_filterExact(bisect, value) {
10300 return function(values) {
10301 var n = values.length;
10302 return [bisect.left(values, value, 0, n), bisect.right(values, value, 0, n)];
10303 };
10304 }
10305
10306 function crossfilter_filterRange(bisect, range) {
10307 var min = range[0],
10308 max = range[1];
10309 return function(values) {
10310 var n = values.length;
10311 return [bisect.left(values, min, 0, n), bisect.left(values, max, 0, n)];
10312 };
10313 }
10314
10315 function crossfilter_filterAll(values) {
10316 return [0, values.length];
10317 }
10318 function crossfilter_null() {
10319 return null;
10320 }
10321 function crossfilter_zero() {
10322 return 0;
10323 }
10324 function crossfilter_reduceIncrement(p) {
10325 return p + 1;
10326 }
10327
10328 function crossfilter_reduceDecrement(p) {
10329 return p - 1;
10330 }
10331
10332 function crossfilter_reduceAdd(f) {
10333 return function(p, v) {
10334 return p + +f(v);
10335 };
10336 }
10337
10338 function crossfilter_reduceSubtract(f) {
10339 return function(p, v) {
10340 return p - f(v);
10341 };
10342 }
10343 exports.crossfilter = crossfilter;
10344
10345 function crossfilter() {
10346 var crossfilter = {
10347 add: add,
10348 remove: removeData,
10349 dimension: dimension,
10350 groupAll: groupAll,
10351 size: size
10352 };
10353
10354 var data = [], // the records
10355 n = 0, // the number of records; data.length
10356 m = 0, // a bit mask representing which dimensions are in use
10357 M = 8, // number of dimensions that can fit in `filters`
10358 filters = crossfilter_array8(0), // M bits per record; 1 is filtered out
10359 filterListeners = [], // when the filters change
10360 dataListeners = [], // when data is added
10361 removeDataListeners = []; // when data is removed
10362
10363 // Adds the specified new records to this crossfilter.
10364 function add(newData) {
10365 var n0 = n,
10366 n1 = newData.length;
10367
10368 // If there's actually new data to add…
10369 // Merge the new data into the existing data.
10370 // Lengthen the filter bitset to handle the new records.
10371 // Notify listeners (dimensions and groups) that new data is available.
10372 if (n1) {
10373 data = data.concat(newData);
10374 filters = crossfilter_arrayLengthen(filters, n += n1);
10375 dataListeners.forEach(function(l) { l(newData, n0, n1); });
10376 }
10377
10378 return crossfilter;
10379 }
10380
10381 // Removes all records that match the current filters.
10382 function removeData() {
10383 var newIndex = crossfilter_index(n, n),
10384 removed = [];
10385 for (var i = 0, j = 0; i < n; ++i) {
10386 if (filters[i]) newIndex[i] = j++;
10387 else removed.push(i);
10388 }
10389
10390 // Remove all matching records from groups.
10391 filterListeners.forEach(function(l) { l(0, [], removed); });
10392
10393 // Update indexes.
10394 removeDataListeners.forEach(function(l) { l(newIndex); });
10395
10396 // Remove old filters and data by overwriting.
10397 for (var i = 0, j = 0, k; i < n; ++i) {
10398 if (k = filters[i]) {
10399 if (i !== j) filters[j] = k, data[j] = data[i];
10400 ++j;
10401 }
10402 }
10403 data.length = j;
10404 while (n > j) filters[--n] = 0;
10405 }
10406
10407 // Adds a new dimension with the specified value accessor function.
10408 function dimension(value) {
10409 var dimension = {
10410 filter: filter,
10411 filterExact: filterExact,
10412 filterRange: filterRange,
10413 filterFunction: filterFunction,
10414 filterAll: filterAll,
10415 top: top,
10416 bottom: bottom,
10417 group: group,
10418 groupAll: groupAll,
10419 dispose: dispose,
10420 remove: dispose // for backwards-compatibility
10421 };
10422
10423 var one = ~m & -~m, // lowest unset bit as mask, e.g., 00001000
10424 zero = ~one, // inverted one, e.g., 11110111
10425 values, // sorted, cached array
10426 index, // value rank ↦ object id
10427 newValues, // temporary array storing newly-added values
10428 newIndex, // temporary array storing newly-added index
10429 sort = quicksort_by(function(i) { return newValues[i]; }),
10430 refilter = crossfilter_filterAll, // for recomputing filter
10431 refilterFunction, // the custom filter function in use
10432 indexListeners = [], // when data is added
10433 dimensionGroups = [],
10434 lo0 = 0,
10435 hi0 = 0;
10436
10437 // Updating a dimension is a two-stage process. First, we must update the
10438 // associated filters for the newly-added records. Once all dimensions have
10439 // updated their filters, the groups are notified to update.
10440 dataListeners.unshift(preAdd);
10441 dataListeners.push(postAdd);
10442
10443 removeDataListeners.push(removeData);
10444
10445 // Incorporate any existing data into this dimension, and make sure that the
10446 // filter bitset is wide enough to handle the new dimension.
10447 m |= one;
10448 if (M >= 32 ? !one : m & (1 << M) - 1) {
10449 filters = crossfilter_arrayWiden(filters, M <<= 1);
10450 }
10451 preAdd(data, 0, n);
10452 postAdd(data, 0, n);
10453
10454 // Incorporates the specified new records into this dimension.
10455 // This function is responsible for updating filters, values, and index.
10456 function preAdd(newData, n0, n1) {
10457
10458 // Permute new values into natural order using a sorted index.
10459 newValues = newData.map(value);
10460 newIndex = sort(crossfilter_range(n1), 0, n1);
10461 newValues = permute(newValues, newIndex);
10462
10463 // Bisect newValues to determine which new records are selected.
10464 var bounds = refilter(newValues), lo1 = bounds[0], hi1 = bounds[1], i;
10465 if (refilterFunction) {
10466 for (i = 0; i < n1; ++i) {
10467 if (!refilterFunction(newValues[i], i)) filters[newIndex[i] + n0] |= one;
10468 }
10469 } else {
10470 for (i = 0; i < lo1; ++i) filters[newIndex[i] + n0] |= one;
10471 for (i = hi1; i < n1; ++i) filters[newIndex[i] + n0] |= one;
10472 }
10473
10474 // If this dimension previously had no data, then we don't need to do the
10475 // more expensive merge operation; use the new values and index as-is.
10476 if (!n0) {
10477 values = newValues;
10478 index = newIndex;
10479 lo0 = lo1;
10480 hi0 = hi1;
10481 return;
10482 }
10483
10484 var oldValues = values,
10485 oldIndex = index,
10486 i0 = 0,
10487 i1 = 0;
10488
10489 // Otherwise, create new arrays into which to merge new and old.
10490 values = new Array(n);
10491 index = crossfilter_index(n, n);
10492
10493 // Merge the old and new sorted values, and old and new index.
10494 for (i = 0; i0 < n0 && i1 < n1; ++i) {
10495 if (oldValues[i0] < newValues[i1]) {
10496 values[i] = oldValues[i0];
10497 index[i] = oldIndex[i0++];
10498 } else {
10499 values[i] = newValues[i1];
10500 index[i] = newIndex[i1++] + n0;
10501 }
10502 }
10503
10504 // Add any remaining old values.
10505 for (; i0 < n0; ++i0, ++i) {
10506 values[i] = oldValues[i0];
10507 index[i] = oldIndex[i0];
10508 }
10509
10510 // Add any remaining new values.
10511 for (; i1 < n1; ++i1, ++i) {
10512 values[i] = newValues[i1];
10513 index[i] = newIndex[i1] + n0;
10514 }
10515
10516 // Bisect again to recompute lo0 and hi0.
10517 bounds = refilter(values), lo0 = bounds[0], hi0 = bounds[1];
10518 }
10519
10520 // When all filters have updated, notify index listeners of the new values.
10521 function postAdd(newData, n0, n1) {
10522 indexListeners.forEach(function(l) { l(newValues, newIndex, n0, n1); });
10523 newValues = newIndex = null;
10524 }
10525
10526 function removeData(reIndex) {
10527 for (var i = 0, j = 0, k; i < n; ++i) {
10528 if (filters[k = index[i]]) {
10529 if (i !== j) values[j] = values[i];
10530 index[j] = reIndex[k];
10531 ++j;
10532 }
10533 }
10534 values.length = j;
10535 while (j < n) index[j++] = 0;
10536
10537 // Bisect again to recompute lo0 and hi0.
10538 var bounds = refilter(values);
10539 lo0 = bounds[0], hi0 = bounds[1];
10540 }
10541
10542 // Updates the selected values based on the specified bounds [lo, hi].
10543 // This implementation is used by all the public filter methods.
10544 function filterIndexBounds(bounds) {
10545 var lo1 = bounds[0],
10546 hi1 = bounds[1];
10547
10548 if (refilterFunction) {
10549 refilterFunction = null;
10550 filterIndexFunction(function(d, i) { return lo1 <= i && i < hi1; });
10551 lo0 = lo1;
10552 hi0 = hi1;
10553 return dimension;
10554 }
10555
10556 var i,
10557 j,
10558 k,
10559 added = [],
10560 removed = [];
10561
10562 // Fast incremental update based on previous lo index.
10563 if (lo1 < lo0) {
10564 for (i = lo1, j = Math.min(lo0, hi1); i < j; ++i) {
10565 filters[k = index[i]] ^= one;
10566 added.push(k);
10567 }
10568 } else if (lo1 > lo0) {
10569 for (i = lo0, j = Math.min(lo1, hi0); i < j; ++i) {
10570 filters[k = index[i]] ^= one;
10571 removed.push(k);
10572 }
10573 }
10574
10575 // Fast incremental update based on previous hi index.
10576 if (hi1 > hi0) {
10577 for (i = Math.max(lo1, hi0), j = hi1; i < j; ++i) {
10578 filters[k = index[i]] ^= one;
10579 added.push(k);
10580 }
10581 } else if (hi1 < hi0) {
10582 for (i = Math.max(lo0, hi1), j = hi0; i < j; ++i) {
10583 filters[k = index[i]] ^= one;
10584 removed.push(k);
10585 }
10586 }
10587
10588 lo0 = lo1;
10589 hi0 = hi1;
10590 filterListeners.forEach(function(l) { l(one, added, removed); });
10591 return dimension;
10592 }
10593
10594 // Filters this dimension using the specified range, value, or null.
10595 // If the range is null, this is equivalent to filterAll.
10596 // If the range is an array, this is equivalent to filterRange.
10597 // Otherwise, this is equivalent to filterExact.
10598 function filter(range) {
10599 return range == null
10600 ? filterAll() : Array.isArray(range)
10601 ? filterRange(range) : typeof range === "function"
10602 ? filterFunction(range)
10603 : filterExact(range);
10604 }
10605
10606 // Filters this dimension to select the exact value.
10607 function filterExact(value) {
10608 return filterIndexBounds((refilter = crossfilter_filterExact(bisect, value))(values));
10609 }
10610
10611 // Filters this dimension to select the specified range [lo, hi].
10612 // The lower bound is inclusive, and the upper bound is exclusive.
10613 function filterRange(range) {
10614 return filterIndexBounds((refilter = crossfilter_filterRange(bisect, range))(values));
10615 }
10616
10617 // Clears any filters on this dimension.
10618 function filterAll() {
10619 return filterIndexBounds((refilter = crossfilter_filterAll)(values));
10620 }
10621
10622 // Filters this dimension using an arbitrary function.
10623 function filterFunction(f) {
10624 refilter = crossfilter_filterAll;
10625
10626 filterIndexFunction(refilterFunction = f);
10627
10628 lo0 = 0;
10629 hi0 = n;
10630
10631 return dimension;
10632 }
10633
10634 function filterIndexFunction(f) {
10635 var i,
10636 k,
10637 x,
10638 added = [],
10639 removed = [];
10640
10641 for (i = 0; i < n; ++i) {
10642 if (!(filters[k = index[i]] & one) ^ !!(x = f(values[i], i))) {
10643 if (x) filters[k] &= zero, added.push(k);
10644 else filters[k] |= one, removed.push(k);
10645 }
10646 }
10647 filterListeners.forEach(function(l) { l(one, added, removed); });
10648 }
10649
10650 // Returns the top K selected records based on this dimension's order.
10651 // Note: observes this dimension's filter, unlike group and groupAll.
10652 function top(k) {
10653 var array = [],
10654 i = hi0,
10655 j;
10656
10657 while (--i >= lo0 && k > 0) {
10658 if (!filters[j = index[i]]) {
10659 array.push(data[j]);
10660 --k;
10661 }
10662 }
10663
10664 return array;
10665 }
10666
10667 // Returns the bottom K selected records based on this dimension's order.
10668 // Note: observes this dimension's filter, unlike group and groupAll.
10669 function bottom(k) {
10670 var array = [],
10671 i = lo0,
10672 j;
10673
10674 while (i < hi0 && k > 0) {
10675 if (!filters[j = index[i]]) {
10676 array.push(data[j]);
10677 --k;
10678 }
10679 i++;
10680 }
10681
10682 return array;
10683 }
10684
10685 // Adds a new group to this dimension, using the specified key function.
10686 function group(key) {
10687 var group = {
10688 top: top,
10689 all: all,
10690 reduce: reduce,
10691 reduceCount: reduceCount,
10692 reduceSum: reduceSum,
10693 order: order,
10694 orderNatural: orderNatural,
10695 size: size,
10696 dispose: dispose,
10697 remove: dispose // for backwards-compatibility
10698 };
10699
10700 // Ensure that this group will be removed when the dimension is removed.
10701 dimensionGroups.push(group);
10702
10703 var groups, // array of {key, value}
10704 groupIndex, // object id ↦ group id
10705 groupWidth = 8,
10706 groupCapacity = crossfilter_capacity(groupWidth),
10707 k = 0, // cardinality
10708 select,
10709 heap,
10710 reduceAdd,
10711 reduceRemove,
10712 reduceInitial,
10713 update = crossfilter_null,
10714 reset = crossfilter_null,
10715 resetNeeded = true,
10716 groupAll = key === crossfilter_null;
10717
10718 if (arguments.length < 1) key = crossfilter_identity;
10719
10720 // The group listens to the crossfilter for when any dimension changes, so
10721 // that it can update the associated reduce values. It must also listen to
10722 // the parent dimension for when data is added, and compute new keys.
10723 filterListeners.push(update);
10724 indexListeners.push(add);
10725 removeDataListeners.push(removeData);
10726
10727 // Incorporate any existing data into the grouping.
10728 add(values, index, 0, n);
10729
10730 // Incorporates the specified new values into this group.
10731 // This function is responsible for updating groups and groupIndex.
10732 function add(newValues, newIndex, n0, n1) {
10733 var oldGroups = groups,
10734 reIndex = crossfilter_index(k, groupCapacity),
10735 add = reduceAdd,
10736 initial = reduceInitial,
10737 k0 = k, // old cardinality
10738 i0 = 0, // index of old group
10739 i1 = 0, // index of new record
10740 j, // object id
10741 g0, // old group
10742 x0, // old key
10743 x1, // new key
10744 g, // group to add
10745 x; // key of group to add
10746
10747 // If a reset is needed, we don't need to update the reduce values.
10748 if (resetNeeded) add = initial = crossfilter_null;
10749
10750 // Reset the new groups (k is a lower bound).
10751 // Also, make sure that groupIndex exists and is long enough.
10752 groups = new Array(k), k = 0;
10753 groupIndex = k0 > 1 ? crossfilter_arrayLengthen(groupIndex, n) : crossfilter_index(n, groupCapacity);
10754
10755 // Get the first old key (x0 of g0), if it exists.
10756 if (k0) x0 = (g0 = oldGroups[0]).key;
10757
10758 // Find the first new key (x1), skipping NaN keys.
10759 while (i1 < n1 && !((x1 = key(newValues[i1])) >= x1)) ++i1;
10760
10761 // While new keys remain…
10762 while (i1 < n1) {
10763
10764 // Determine the lesser of the two current keys; new and old.
10765 // If there are no old keys remaining, then always add the new key.
10766 if (g0 && x0 <= x1) {
10767 g = g0, x = x0;
10768
10769 // Record the new index of the old group.
10770 reIndex[i0] = k;
10771
10772 // Retrieve the next old key.
10773 if (g0 = oldGroups[++i0]) x0 = g0.key;
10774 } else {
10775 g = {key: x1, value: initial()}, x = x1;
10776 }
10777
10778 // Add the lesser group.
10779 groups[k] = g;
10780
10781 // Add any selected records belonging to the added group, while
10782 // advancing the new key and populating the associated group index.
10783 while (!(x1 > x)) {
10784 groupIndex[j = newIndex[i1] + n0] = k;
10785 if (!(filters[j] & zero)) g.value = add(g.value, data[j]);
10786 if (++i1 >= n1) break;
10787 x1 = key(newValues[i1]);
10788 }
10789
10790 groupIncrement();
10791 }
10792
10793 // Add any remaining old groups that were greater than all new keys.
10794 // No incremental reduce is needed; these groups have no new records.
10795 // Also record the new index of the old group.
10796 while (i0 < k0) {
10797 groups[reIndex[i0] = k] = oldGroups[i0++];
10798 groupIncrement();
10799 }
10800
10801 // If we added any new groups before any old groups,
10802 // update the group index of all the old records.
10803 if (k > i0) for (i0 = 0; i0 < n0; ++i0) {
10804 groupIndex[i0] = reIndex[groupIndex[i0]];
10805 }
10806
10807 // Modify the update and reset behavior based on the cardinality.
10808 // If the cardinality is less than or equal to one, then the groupIndex
10809 // is not needed. If the cardinality is zero, then there are no records
10810 // and therefore no groups to update or reset. Note that we also must
10811 // change the registered listener to point to the new method.
10812 j = filterListeners.indexOf(update);
10813 if (k > 1) {
10814 update = updateMany;
10815 reset = resetMany;
10816 } else {
10817 if (!k && groupAll) {
10818 k = 1;
10819 groups = [{key: null, value: initial()}];
10820 }
10821 if (k === 1) {
10822 update = updateOne;
10823 reset = resetOne;
10824 } else {
10825 update = crossfilter_null;
10826 reset = crossfilter_null;
10827 }
10828 groupIndex = null;
10829 }
10830 filterListeners[j] = update;
10831
10832 // Count the number of added groups,
10833 // and widen the group index as needed.
10834 function groupIncrement() {
10835 if (++k === groupCapacity) {
10836 reIndex = crossfilter_arrayWiden(reIndex, groupWidth <<= 1);
10837 groupIndex = crossfilter_arrayWiden(groupIndex, groupWidth);
10838 groupCapacity = crossfilter_capacity(groupWidth);
10839 }
10840 }
10841 }
10842
10843 function removeData() {
10844 if (k > 1) {
10845 var oldK = k,
10846 oldGroups = groups,
10847 seenGroups = crossfilter_index(oldK, oldK);
10848
10849 // Filter out non-matches by copying matching group index entries to
10850 // the beginning of the array.
10851 for (var i = 0, j = 0; i < n; ++i) {
10852 if (filters[i]) {
10853 seenGroups[groupIndex[j] = groupIndex[i]] = 1;
10854 ++j;
10855 }
10856 }
10857
10858 // Reassemble groups including only those groups that were referred
10859 // to by matching group index entries. Note the new group index in
10860 // seenGroups.
10861 groups = [], k = 0;
10862 for (i = 0; i < oldK; ++i) {
10863 if (seenGroups[i]) {
10864 seenGroups[i] = k++;
10865 groups.push(oldGroups[i]);
10866 }
10867 }
10868
10869 if (k > 1) {
10870 // Reindex the group index using seenGroups to find the new index.
10871 for (var i = 0; i < j; ++i) groupIndex[i] = seenGroups[groupIndex[i]];
10872 } else {
10873 groupIndex = null;
10874 }
10875 filterListeners[filterListeners.indexOf(update)] = k > 1
10876 ? (reset = resetMany, update = updateMany)
10877 : k === 1 ? (reset = resetOne, update = updateOne)
10878 : reset = update = crossfilter_null;
10879 } else if (k === 1) {
10880 if (groupAll) return;
10881 for (var i = 0; i < n; ++i) if (filters[i]) return;
10882 groups = [], k = 0;
10883 filterListeners[filterListeners.indexOf(update)] =
10884 update = reset = crossfilter_null;
10885 }
10886 }
10887
10888 // Reduces the specified selected or deselected records.
10889 // This function is only used when the cardinality is greater than 1.
10890 function updateMany(filterOne, added, removed) {
10891 if (filterOne === one || resetNeeded) return;
10892
10893 var i,
10894 k,
10895 n,
10896 g;
10897
10898 // Add the added values.
10899 for (i = 0, n = added.length; i < n; ++i) {
10900 if (!(filters[k = added[i]] & zero)) {
10901 g = groups[groupIndex[k]];
10902 g.value = reduceAdd(g.value, data[k]);
10903 }
10904 }
10905
10906 // Remove the removed values.
10907 for (i = 0, n = removed.length; i < n; ++i) {
10908 if ((filters[k = removed[i]] & zero) === filterOne) {
10909 g = groups[groupIndex[k]];
10910 g.value = reduceRemove(g.value, data[k]);
10911 }
10912 }
10913 }
10914
10915 // Reduces the specified selected or deselected records.
10916 // This function is only used when the cardinality is 1.
10917 function updateOne(filterOne, added, removed) {
10918 if (filterOne === one || resetNeeded) return;
10919
10920 var i,
10921 k,
10922 n,
10923 g = groups[0];
10924
10925 // Add the added values.
10926 for (i = 0, n = added.length; i < n; ++i) {
10927 if (!(filters[k = added[i]] & zero)) {
10928 g.value = reduceAdd(g.value, data[k]);
10929 }
10930 }
10931
10932 // Remove the removed values.
10933 for (i = 0, n = removed.length; i < n; ++i) {
10934 if ((filters[k = removed[i]] & zero) === filterOne) {
10935 g.value = reduceRemove(g.value, data[k]);
10936 }
10937 }
10938 }
10939
10940 // Recomputes the group reduce values from scratch.
10941 // This function is only used when the cardinality is greater than 1.
10942 function resetMany() {
10943 var i,
10944 g;
10945
10946 // Reset all group values.
10947 for (i = 0; i < k; ++i) {
10948 groups[i].value = reduceInitial();
10949 }
10950
10951 // Add any selected records.
10952 for (i = 0; i < n; ++i) {
10953 if (!(filters[i] & zero)) {
10954 g = groups[groupIndex[i]];
10955 g.value = reduceAdd(g.value, data[i]);
10956 }
10957 }
10958 }
10959
10960 // Recomputes the group reduce values from scratch.
10961 // This function is only used when the cardinality is 1.
10962 function resetOne() {
10963 var i,
10964 g = groups[0];
10965
10966 // Reset the singleton group values.
10967 g.value = reduceInitial();
10968
10969 // Add any selected records.
10970 for (i = 0; i < n; ++i) {
10971 if (!(filters[i] & zero)) {
10972 g.value = reduceAdd(g.value, data[i]);
10973 }
10974 }
10975 }
10976
10977 // Returns the array of group values, in the dimension's natural order.
10978 function all() {
10979 if (resetNeeded) reset(), resetNeeded = false;
10980 return groups;
10981 }
10982
10983 // Returns a new array containing the top K group values, in reduce order.
10984 function top(k) {
10985 var top = select(all(), 0, groups.length, k);
10986 return heap.sort(top, 0, top.length);
10987 }
10988
10989 // Sets the reduce behavior for this group to use the specified functions.
10990 // This method lazily recomputes the reduce values, waiting until needed.
10991 function reduce(add, remove, initial) {
10992 reduceAdd = add;
10993 reduceRemove = remove;
10994 reduceInitial = initial;
10995 resetNeeded = true;
10996 return group;
10997 }
10998
10999 // A convenience method for reducing by count.
11000 function reduceCount() {
11001 return reduce(crossfilter_reduceIncrement, crossfilter_reduceDecrement, crossfilter_zero);
11002 }
11003
11004 // A convenience method for reducing by sum(value).
11005 function reduceSum(value) {
11006 return reduce(crossfilter_reduceAdd(value), crossfilter_reduceSubtract(value), crossfilter_zero);
11007 }
11008
11009 // Sets the reduce order, using the specified accessor.
11010 function order(value) {
11011 select = heapselect_by(valueOf);
11012 heap = heap_by(valueOf);
11013 function valueOf(d) { return value(d.value); }
11014 return group;
11015 }
11016
11017 // A convenience method for natural ordering by reduce value.
11018 function orderNatural() {
11019 return order(crossfilter_identity);
11020 }
11021
11022 // Returns the cardinality of this group, irrespective of any filters.
11023 function size() {
11024 return k;
11025 }
11026
11027 // Removes this group and associated event listeners.
11028 function dispose() {
11029 var i = filterListeners.indexOf(update);
11030 if (i >= 0) filterListeners.splice(i, 1);
11031 i = indexListeners.indexOf(add);
11032 if (i >= 0) indexListeners.splice(i, 1);
11033 i = removeDataListeners.indexOf(removeData);
11034 if (i >= 0) removeDataListeners.splice(i, 1);
11035 return group;
11036 }
11037
11038 return reduceCount().orderNatural();
11039 }
11040
11041 // A convenience function for generating a singleton group.
11042 function groupAll() {
11043 var g = group(crossfilter_null), all = g.all;
11044 delete g.all;
11045 delete g.top;
11046 delete g.order;
11047 delete g.orderNatural;
11048 delete g.size;
11049 g.value = function() { return all()[0].value; };
11050 return g;
11051 }
11052
11053 // Removes this dimension and associated groups and event listeners.
11054 function dispose() {
11055 dimensionGroups.forEach(function(group) { group.dispose(); });
11056 var i = dataListeners.indexOf(preAdd);
11057 if (i >= 0) dataListeners.splice(i, 1);
11058 i = dataListeners.indexOf(postAdd);
11059 if (i >= 0) dataListeners.splice(i, 1);
11060 i = removeDataListeners.indexOf(removeData);
11061 if (i >= 0) removeDataListeners.splice(i, 1);
11062 m &= zero;
11063 return filterAll();
11064 }
11065
11066 return dimension;
11067 }
11068
11069 // A convenience method for groupAll on a dummy dimension.
11070 // This implementation can be optimized since it always has cardinality 1.
11071 function groupAll() {
11072 var group = {
11073 reduce: reduce,
11074 reduceCount: reduceCount,
11075 reduceSum: reduceSum,
11076 value: value,
11077 dispose: dispose,
11078 remove: dispose // for backwards-compatibility
11079 };
11080
11081 var reduceValue,
11082 reduceAdd,
11083 reduceRemove,
11084 reduceInitial,
11085 resetNeeded = true;
11086
11087 // The group listens to the crossfilter for when any dimension changes, so
11088 // that it can update the reduce value. It must also listen to the parent
11089 // dimension for when data is added.
11090 filterListeners.push(update);
11091 dataListeners.push(add);
11092
11093 // For consistency; actually a no-op since resetNeeded is true.
11094 add(data, 0, n);
11095
11096 // Incorporates the specified new values into this group.
11097 function add(newData, n0) {
11098 var i;
11099
11100 if (resetNeeded) return;
11101
11102 // Add the added values.
11103 for (i = n0; i < n; ++i) {
11104 if (!filters[i]) {
11105 reduceValue = reduceAdd(reduceValue, data[i]);
11106 }
11107 }
11108 }
11109
11110 // Reduces the specified selected or deselected records.
11111 function update(filterOne, added, removed) {
11112 var i,
11113 k,
11114 n;
11115
11116 if (resetNeeded) return;
11117
11118 // Add the added values.
11119 for (i = 0, n = added.length; i < n; ++i) {
11120 if (!filters[k = added[i]]) {
11121 reduceValue = reduceAdd(reduceValue, data[k]);
11122 }
11123 }
11124
11125 // Remove the removed values.
11126 for (i = 0, n = removed.length; i < n; ++i) {
11127 if (filters[k = removed[i]] === filterOne) {
11128 reduceValue = reduceRemove(reduceValue, data[k]);
11129 }
11130 }
11131 }
11132
11133 // Recomputes the group reduce value from scratch.
11134 function reset() {
11135 var i;
11136
11137 reduceValue = reduceInitial();
11138
11139 for (i = 0; i < n; ++i) {
11140 if (!filters[i]) {
11141 reduceValue = reduceAdd(reduceValue, data[i]);
11142 }
11143 }
11144 }
11145
11146 // Sets the reduce behavior for this group to use the specified functions.
11147 // This method lazily recomputes the reduce value, waiting until needed.
11148 function reduce(add, remove, initial) {
11149 reduceAdd = add;
11150 reduceRemove = remove;
11151 reduceInitial = initial;
11152 resetNeeded = true;
11153 return group;
11154 }
11155
11156 // A convenience method for reducing by count.
11157 function reduceCount() {
11158 return reduce(crossfilter_reduceIncrement, crossfilter_reduceDecrement, crossfilter_zero);
11159 }
11160
11161 // A convenience method for reducing by sum(value).
11162 function reduceSum(value) {
11163 return reduce(crossfilter_reduceAdd(value), crossfilter_reduceSubtract(value), crossfilter_zero);
11164 }
11165
11166 // Returns the computed reduce value.
11167 function value() {
11168 if (resetNeeded) reset(), resetNeeded = false;
11169 return reduceValue;
11170 }
11171
11172 // Removes this group and associated event listeners.
11173 function dispose() {
11174 var i = filterListeners.indexOf(update);
11175 if (i >= 0) filterListeners.splice(i);
11176 i = dataListeners.indexOf(add);
11177 if (i >= 0) dataListeners.splice(i);
11178 return group;
11179 }
11180
11181 return reduceCount();
11182 }
11183
11184 // Returns the number of records in this crossfilter, irrespective of any filters.
11185 function size() {
11186 return n;
11187 }
11188
11189 return arguments.length
11190 ? add(arguments[0])
11191 : crossfilter;
11192 }
11193
11194 // Returns an array of size n, big enough to store ids up to m.
11195 function crossfilter_index(n, m) {
11196 return (m < 0x101
11197 ? crossfilter_array8 : m < 0x10001
11198 ? crossfilter_array16
11199 : crossfilter_array32)(n);
11200 }
11201
11202 // Constructs a new array of size n, with sequential values from 0 to n - 1.
11203 function crossfilter_range(n) {
11204 var range = crossfilter_index(n, n);
11205 for (var i = -1; ++i < n;) range[i] = i;
11206 return range;
11207 }
11208
11209 function crossfilter_capacity(w) {
11210 return w === 8
11211 ? 0x100 : w === 16
11212 ? 0x10000
11213 : 0x100000000;
11214 }
11215 })(typeof exports !== 'undefined' && exports || this);
11216 /*!
11217 * dc 2.0.0-alpha.5
11218 * http://dc-js.github.io/dc.js/
11219 * Copyright 2012 Nick Zhu and other contributors
11220 *
11221 * Licensed under the Apache License, Version 2.0 (the "License");
11222 * you may not use this file except in compliance with the License.
11223 * You may obtain a copy of the License at
11224 *
11225 * http://www.apache.org/licenses/LICENSE-2.0
11226 *
11227 * Unless required by applicable law or agreed to in writing, software
11228 * distributed under the License is distributed on an "AS IS" BASIS,
11229 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11230 * See the License for the specific language governing permissions and
11231 * limitations under the License.
11232 */
11233
11234 (function() { function _dc(d3, crossfilter) {
11235 'use strict';
11236
11237 /**
11238 #### Version 2.0.0-alpha.5
11239 The entire dc.js library is scoped under the **dc** name space. It does not introduce anything else
11240 into the global name space.
11241 #### Function Chaining
11242 Most dc functions are designed to allow function chaining, meaning they return the current chart
11243 instance whenever it is appropriate. This way chart configuration can be written in the following
11244 style:
11245 ```js
11246 chart.width(300)
11247 .height(300)
11248 .filter('sunday')
11249 ```
11250 The getter forms of functions do not participate in function chaining because they necessarily
11251 return values that are not the chart. (Although some, such as `.svg` and `.xAxis`, return values
11252 that are chainable d3 objects.)
11253
11254 **/
11255
11256 /*jshint -W062*/
11257 /*jshint -W079*/
11258 var dc = {
11259 version: '2.0.0-alpha.5',
11260 constants: {
11261 CHART_CLASS: 'dc-chart',
11262 DEBUG_GROUP_CLASS: 'debug',
11263 STACK_CLASS: 'stack',
11264 DESELECTED_CLASS: 'deselected',
11265 SELECTED_CLASS: 'selected',
11266 NODE_INDEX_NAME: '__index__',
11267 GROUP_INDEX_NAME: '__group_index__',
11268 DEFAULT_CHART_GROUP: '__default_chart_group__',
11269 EVENT_DELAY: 40,
11270 NEGLIGIBLE_NUMBER: 1e-10
11271 },
11272 _renderlet: null
11273 };
11274
11275 dc.chartRegistry = function () {
11276 // chartGroup:string => charts:array
11277 var _chartMap = {};
11278
11279 function initializeChartGroup(group) {
11280 if (!group) {
11281 group = dc.constants.DEFAULT_CHART_GROUP;
11282 }
11283
11284 if (!_chartMap[group]) {
11285 _chartMap[group] = [];
11286 }
11287
11288 return group;
11289 }
11290
11291 return {
11292 has: function (chart) {
11293 for (var e in _chartMap) {
11294 if (_chartMap[e].indexOf(chart) >= 0) {
11295 return true;
11296 }
11297 }
11298 return false;
11299 },
11300
11301 register: function (chart, group) {
11302 group = initializeChartGroup(group);
11303 _chartMap[group].push(chart);
11304 },
11305
11306 deregister: function (chart, group) {
11307 group = initializeChartGroup(group);
11308 for (var i = 0; i < _chartMap[group].length; i++) {
11309 if (_chartMap[group][i].anchorName() === chart.anchorName()) {
11310 _chartMap[group].splice(i, 1);
11311 break;
11312 }
11313 }
11314 },
11315
11316 clear: function (group) {
11317 if (group) {
11318 delete _chartMap[group];
11319 } else {
11320 _chartMap = {};
11321 }
11322 },
11323
11324 list: function (group) {
11325 group = initializeChartGroup(group);
11326 return _chartMap[group];
11327 }
11328 };
11329 }();
11330 /*jshint +W062 */
11331 /*jshint +W079*/
11332
11333 dc.registerChart = function (chart, group) {
11334 dc.chartRegistry.register(chart, group);
11335 };
11336
11337 dc.deregisterChart = function (chart, group) {
11338 dc.chartRegistry.deregister(chart, group);
11339 };
11340
11341 dc.hasChart = function (chart) {
11342 return dc.chartRegistry.has(chart);
11343 };
11344
11345 dc.deregisterAllCharts = function (group) {
11346 dc.chartRegistry.clear(group);
11347 };
11348
11349 /**
11350 ## Utilities
11351 **/
11352
11353 /**
11354 #### dc.filterAll([chartGroup])
11355 Clear all filters on all charts within the given chart group. If the chart group is not given then
11356 only charts that belong to the default chart group will be reset.
11357 **/
11358 dc.filterAll = function (group) {
11359 var charts = dc.chartRegistry.list(group);
11360 for (var i = 0; i < charts.length; ++i) {
11361 charts[i].filterAll();
11362 }
11363 };
11364
11365 /**
11366 #### dc.refocusAll([chartGroup])
11367 Reset zoom level / focus on all charts that belong to the given chart group. If the chart group is
11368 not given then only charts that belong to the default chart group will be reset.
11369 **/
11370 dc.refocusAll = function (group) {
11371 var charts = dc.chartRegistry.list(group);
11372 for (var i = 0; i < charts.length; ++i) {
11373 if (charts[i].focus) {
11374 charts[i].focus();
11375 }
11376 }
11377 };
11378
11379 /**
11380 #### dc.renderAll([chartGroup])
11381 Re-render all charts belong to the given chart group. If the chart group is not given then only
11382 charts that belong to the default chart group will be re-rendered.
11383 **/
11384 dc.renderAll = function (group) {
11385 var charts = dc.chartRegistry.list(group);
11386 for (var i = 0; i < charts.length; ++i) {
11387 charts[i].render();
11388 }
11389
11390 if (dc._renderlet !== null) {
11391 dc._renderlet(group);
11392 }
11393 };
11394
11395 /**
11396 #### dc.redrawAll([chartGroup])
11397 Redraw all charts belong to the given chart group. If the chart group is not given then only charts
11398 that belong to the default chart group will be re-drawn. Redraw is different from re-render since
11399 when redrawing dc tries to update the graphic incrementally, using transitions, instead of starting
11400 from scratch.
11401 **/
11402 dc.redrawAll = function (group) {
11403 var charts = dc.chartRegistry.list(group);
11404 for (var i = 0; i < charts.length; ++i) {
11405 charts[i].redraw();
11406 }
11407
11408 if (dc._renderlet !== null) {
11409 dc._renderlet(group);
11410 }
11411 };
11412
11413 /**
11414 #### dc.disableTransitions
11415 If this boolean is set truthy, all transitions will be disabled, and changes to the charts will happen
11416 immediately. Default: false
11417 **/
11418 dc.disableTransitions = false;
11419
11420 dc.transition = function (selections, duration, callback) {
11421 if (duration <= 0 || duration === undefined || dc.disableTransitions) {
11422 return selections;
11423 }
11424
11425 var s = selections
11426 .transition()
11427 .duration(duration);
11428
11429 if (typeof(callback) === 'function') {
11430 callback(s);
11431 }
11432
11433 return s;
11434 };
11435
11436 dc.units = {};
11437
11438 /**
11439 #### dc.units.integers
11440 `dc.units.integers` is the default value for `xUnits` for the [Coordinate Grid
11441 Chart](#coordinate-grid-chart) and should be used when the x values are a sequence of integers.
11442
11443 It is a function that counts the number of integers in the range supplied in its start and end parameters.
11444
11445 ```js
11446 chart.xUnits(dc.units.integers) // already the default
11447 ```
11448
11449 **/
11450 dc.units.integers = function (s, e) {
11451 return Math.abs(e - s);
11452 };
11453
11454 /**
11455 #### dc.units.ordinal
11456 This argument can be passed to the `xUnits` function of the to specify ordinal units for the x
11457 axis. Usually this parameter is used in combination with passing `d3.scale.ordinal()` to `.x`.
11458
11459 It just returns the domain passed to it, which for ordinal charts is an array of all values.
11460
11461 ```js
11462 chart.xUnits(dc.units.ordinal)
11463 .x(d3.scale.ordinal())
11464 ```
11465
11466 **/
11467 dc.units.ordinal = function (s, e, domain) {
11468 return domain;
11469 };
11470
11471 /**
11472 #### dc.units.fp.precision(precision)
11473 This function generates an argument for the [Coordinate Grid Chart's](#coordinate-grid-chart)
11474 `xUnits` function specifying that the x values are floating-point numbers with the given
11475 precision.
11476
11477 The returned function determines how many values at the given precision will fit into the range
11478 supplied in its start and end parameters.
11479
11480 ```js
11481 // specify values (and ticks) every 0.1 units
11482 chart.xUnits(dc.units.fp.precision(0.1)
11483 // there are 500 units between 0.5 and 1 if the precision is 0.001
11484 var thousandths = dc.units.fp.precision(0.001);
11485 thousandths(0.5, 1.0) // returns 500
11486 ```
11487 **/
11488 dc.units.fp = {};
11489 dc.units.fp.precision = function (precision) {
11490 var _f = function (s, e) {
11491 var d = Math.abs((e - s) / _f.resolution);
11492 if (dc.utils.isNegligible(d - Math.floor(d))) {
11493 return Math.floor(d);
11494 } else {
11495 return Math.ceil(d);
11496 }
11497 };
11498 _f.resolution = precision;
11499 return _f;
11500 };
11501
11502 dc.round = {};
11503 dc.round.floor = function (n) {
11504 return Math.floor(n);
11505 };
11506 dc.round.ceil = function (n) {
11507 return Math.ceil(n);
11508 };
11509 dc.round.round = function (n) {
11510 return Math.round(n);
11511 };
11512
11513 dc.override = function (obj, functionName, newFunction) {
11514 var existingFunction = obj[functionName];
11515 obj['_' + functionName] = existingFunction;
11516 obj[functionName] = newFunction;
11517 };
11518
11519 dc.renderlet = function (_) {
11520 if (!arguments.length) {
11521 return dc._renderlet;
11522 }
11523 dc._renderlet = _;
11524 return dc;
11525 };
11526
11527 dc.instanceOfChart = function (o) {
11528 return o instanceof Object && o.__dcFlag__ && true;
11529 };
11530
11531 dc.errors = {};
11532
11533 dc.errors.Exception = function (msg) {
11534 var _msg = msg || 'Unexpected internal error';
11535
11536 this.message = _msg;
11537
11538 this.toString = function () {
11539 return _msg;
11540 };
11541 };
11542
11543 dc.errors.InvalidStateException = function () {
11544 dc.errors.Exception.apply(this, arguments);
11545 };
11546
11547 dc.dateFormat = d3.time.format('%m/%d/%Y');
11548
11549 dc.printers = {};
11550
11551 dc.printers.filters = function (filters) {
11552 var s = '';
11553
11554 for (var i = 0; i < filters.length; ++i) {
11555 if (i > 0) {
11556 s += ', ';
11557 }
11558 s += dc.printers.filter(filters[i]);
11559 }
11560
11561 return s;
11562 };
11563
11564 dc.printers.filter = function (filter) {
11565 var s = '';
11566
11567 if (typeof filter !== 'undefined' && filter !== null) {
11568 if (filter instanceof Array) {
11569 if (filter.length >= 2) {
11570 s = '[' + dc.utils.printSingleValue(filter[0]) + ' -> ' + dc.utils.printSingleValue(filter[1]) + ']';
11571 } else if (filter.length >= 1) {
11572 s = dc.utils.printSingleValue(filter[0]);
11573 }
11574 } else {
11575 s = dc.utils.printSingleValue(filter);
11576 }
11577 }
11578
11579 return s;
11580 };
11581
11582 dc.pluck = function (n, f) {
11583 if (!f) {
11584 return function (d) { return d[n]; };
11585 }
11586 return function (d, i) { return f.call(d, d[n], i); };
11587 };
11588
11589 dc.utils = {};
11590
11591 dc.utils.printSingleValue = function (filter) {
11592 var s = '' + filter;
11593
11594 if (filter instanceof Date) {
11595 s = dc.dateFormat(filter);
11596 } else if (typeof(filter) === 'string') {
11597 s = filter;
11598 } else if (dc.utils.isFloat(filter)) {
11599 s = dc.utils.printSingleValue.fformat(filter);
11600 } else if (dc.utils.isInteger(filter)) {
11601 s = Math.round(filter);
11602 }
11603
11604 return s;
11605 };
11606 dc.utils.printSingleValue.fformat = d3.format('.2f');
11607
11608 // FIXME: these assume than any string r is a percentage (whether or not it
11609 // includes %). They also generate strange results if l is a string.
11610 dc.utils.add = function (l, r) {
11611 if (typeof r === 'string') {
11612 r = r.replace('%', '');
11613 }
11614
11615 if (l instanceof Date) {
11616 if (typeof r === 'string') {
11617 r = +r;
11618 }
11619 var d = new Date();
11620 d.setTime(l.getTime());
11621 d.setDate(l.getDate() + r);
11622 return d;
11623 } else if (typeof r === 'string') {
11624 var percentage = (+r / 100);
11625 return l > 0 ? l * (1 + percentage) : l * (1 - percentage);
11626 } else {
11627 return l + r;
11628 }
11629 };
11630
11631 dc.utils.subtract = function (l, r) {
11632 if (typeof r === 'string') {
11633 r = r.replace('%', '');
11634 }
11635
11636 if (l instanceof Date) {
11637 if (typeof r === 'string') {
11638 r = +r;
11639 }
11640 var d = new Date();
11641 d.setTime(l.getTime());
11642 d.setDate(l.getDate() - r);
11643 return d;
11644 } else if (typeof r === 'string') {
11645 var percentage = (+r / 100);
11646 return l < 0 ? l * (1 + percentage) : l * (1 - percentage);
11647 } else {
11648 return l - r;
11649 }
11650 };
11651
11652 dc.utils.isNumber = function (n) {
11653 return n === +n;
11654 };
11655
11656 dc.utils.isFloat = function (n) {
11657 return n === +n && n !== (n | 0);
11658 };
11659
11660 dc.utils.isInteger = function (n) {
11661 return n === +n && n === (n | 0);
11662 };
11663
11664 dc.utils.isNegligible = function (n) {
11665 return !dc.utils.isNumber(n) || (n < dc.constants.NEGLIGIBLE_NUMBER && n > -dc.constants.NEGLIGIBLE_NUMBER);
11666 };
11667
11668 dc.utils.clamp = function (val, min, max) {
11669 return val < min ? min : (val > max ? max : val);
11670 };
11671
11672 var _idCounter = 0;
11673 dc.utils.uniqueId = function () {
11674 return ++_idCounter;
11675 };
11676
11677 dc.utils.nameToId = function (name) {
11678 return name.toLowerCase().replace(/[\s]/g, '_').replace(/[\.']/g, '');
11679 };
11680
11681 dc.utils.appendOrSelect = function (parent, selector, tag) {
11682 tag = tag || selector;
11683 var element = parent.select(selector);
11684 if (element.empty()) {
11685 element = parent.append(tag);
11686 }
11687 return element;
11688 };
11689
11690 dc.utils.safeNumber = function (n) { return dc.utils.isNumber(+n) ? +n : 0;};
11691
11692 dc.logger = {};
11693
11694 dc.logger.enableDebugLog = false;
11695
11696 dc.logger.warn = function (msg) {
11697 if (console) {
11698 if (console.warn) {
11699 console.warn(msg);
11700 } else if (console.log) {
11701 console.log(msg);
11702 }
11703 }
11704
11705 return dc.logger;
11706 };
11707
11708 dc.logger.debug = function (msg) {
11709 if (dc.logger.enableDebugLog && console) {
11710 if (console.debug) {
11711 console.debug(msg);
11712 } else if (console.log) {
11713 console.log(msg);
11714 }
11715 }
11716
11717 return dc.logger;
11718 };
11719
11720 dc.events = {
11721 current: null
11722 };
11723
11724 /**
11725 #### dc.events.trigger(function[, delay])
11726 This function triggers a throttled event function with a specified delay (in milli-seconds). Events
11727 that are triggered repetitively due to user interaction such brush dragging might flood the library
11728 and invoke more renders than can be executed in time. Using this function to wrap your event
11729 function allows the library to smooth out the rendering by throttling events and only responding to
11730 the most recent event.
11731
11732 ```js
11733 chart.renderlet(function(chart){
11734 // smooth the rendering through event throttling
11735 dc.events.trigger(function(){
11736 // focus some other chart to the range selected by user on this chart
11737 someOtherChart.focus(chart.filter());
11738 });
11739 })
11740 ```
11741 **/
11742 dc.events.trigger = function (closure, delay) {
11743 if (!delay) {
11744 closure();
11745 return;
11746 }
11747
11748 dc.events.current = closure;
11749
11750 setTimeout(function () {
11751 if (closure === dc.events.current) {
11752 closure();
11753 }
11754 }, delay);
11755 };
11756
11757 dc.filters = {};
11758
11759 /**
11760 ## Filters
11761 The dc.js filters are functions which are passed into crossfilter to chose which records will be
11762 accumulated to produce values for the charts. In the crossfilter model, any filters applied on one
11763 dimension will affect all the other dimensions but not that one. dc always applies a filter
11764 function to the dimension; the function combines multiple filters and if any of them accept a
11765 record, it is filtered in.
11766
11767 These filter constructors are used as appropriate by the various charts to implement brushing. We
11768 mention below which chart uses which filter. In some cases, many instances of a filter will be added.
11769
11770 **/
11771
11772 /**
11773 #### dc.filters.RangedFilter(low, high)
11774 RangedFilter is a filter which accepts keys between `low` and `high`. It is used to implement X
11775 axis brushing for the [coordinate grid charts](#coordinate-grid-mixin).
11776 **/
11777 dc.filters.RangedFilter = function (low, high) {
11778 var range = new Array(low, high);
11779 range.isFiltered = function (value) {
11780 return value >= this[0] && value < this[1];
11781 };
11782
11783 return range;
11784 };
11785
11786 /**
11787 #### dc.filters.TwoDimensionalFilter(array)
11788 TwoDimensionalFilter is a filter which accepts a single two-dimensional value. It is used by the
11789 [heat map chart](#heat-map) to include particular cells as they are clicked. (Rows and columns are
11790 filtered by filtering all the cells in the row or column.)
11791 **/
11792 dc.filters.TwoDimensionalFilter = function (array) {
11793 if (array === null) { return null; }
11794
11795 var filter = array;
11796 filter.isFiltered = function (value) {
11797 return value.length && value.length === filter.length &&
11798 value[0] === filter[0] && value[1] === filter[1];
11799 };
11800
11801 return filter;
11802 };
11803
11804 /**
11805 #### dc.filters.RangedTwoDimensionalFilter(array)
11806 The RangedTwoDimensionalFilter allows filtering all values which fit within a rectangular
11807 region. It is used by the [scatter plot](#scatter-plot) to implement rectangular brushing.
11808
11809 It takes two two-dimensional points in the form `[[x1,y1],[x2,y2]]`, and normalizes them so that
11810 `x1 <= x2` and `y1 <- y2`. It then returns a filter which accepts any points which are in the
11811 rectangular range including the lower values but excluding the higher values.
11812
11813 If an array of two values are given to the RangedTwoDimensionalFilter, it interprets the values as
11814 two x coordinates `x1` and `x2` and returns a filter which accepts any points for which `x1 <= x <
11815 x2`.
11816 **/
11817 dc.filters.RangedTwoDimensionalFilter = function (array) {
11818 if (array === null) { return null; }
11819
11820 var filter = array;
11821 var fromBottomLeft;
11822
11823 if (filter[0] instanceof Array) {
11824 fromBottomLeft = [
11825 [Math.min(array[0][0], array[1][0]), Math.min(array[0][1], array[1][1])],
11826 [Math.max(array[0][0], array[1][0]), Math.max(array[0][1], array[1][1])]
11827 ];
11828 } else {
11829 fromBottomLeft = [[array[0], -Infinity], [array[1], Infinity]];
11830 }
11831
11832 filter.isFiltered = function (value) {
11833 var x, y;
11834
11835 if (value instanceof Array) {
11836 if (value.length !== 2) {
11837 return false;
11838 }
11839 x = value[0];
11840 y = value[1];
11841 } else {
11842 x = value;
11843 y = fromBottomLeft[0][1];
11844 }
11845
11846 return x >= fromBottomLeft[0][0] && x < fromBottomLeft[1][0] &&
11847 y >= fromBottomLeft[0][1] && y < fromBottomLeft[1][1];
11848 };
11849
11850 return filter;
11851 };
11852
11853 /**
11854 ## Base Mixin
11855 Base Mixin is an abstract functional object representing a basic dc chart object
11856 for all chart and widget implementations. Methods from the Base Mixin are inherited
11857 and available on all chart implementation in the DC library.
11858 **/
11859 dc.baseMixin = function (_chart) {
11860 _chart.__dcFlag__ = dc.utils.uniqueId();
11861
11862 var _dimension;
11863 var _group;
11864
11865 var _anchor;
11866 var _root;
11867 var _svg;
11868
11869 var _minWidth = 200;
11870 var _defaultWidth = function (element) {
11871 var width = element && element.getBoundingClientRect && element.getBoundingClientRect().width;
11872 return (width && width > _minWidth) ? width : _minWidth;
11873 };
11874 var _width = _defaultWidth;
11875
11876 var _minHeight = 200;
11877 var _defaultHeight = function (element) {
11878 var height = element && element.getBoundingClientRect && element.getBoundingClientRect().height;
11879 return (height && height > _minHeight) ? height : _minHeight;
11880 };
11881 var _height = _defaultHeight;
11882
11883 var _keyAccessor = dc.pluck('key');
11884 var _valueAccessor = dc.pluck('value');
11885 var _label = dc.pluck('key');
11886
11887 var _ordering = dc.pluck('key');
11888 var _orderSort;
11889
11890 var _renderLabel = false;
11891
11892 var _title = function (d) {
11893 return _chart.keyAccessor()(d) + ': ' + _chart.valueAccessor()(d);
11894 };
11895 var _renderTitle = true;
11896
11897 var _transitionDuration = 750;
11898
11899 var _filterPrinter = dc.printers.filters;
11900
11901 var _renderlets = [];
11902 var _mandatoryAttributes = ['dimension', 'group'];
11903
11904 var _chartGroup = dc.constants.DEFAULT_CHART_GROUP;
11905
11906 var _listeners = d3.dispatch(
11907 'preRender',
11908 'postRender',
11909 'preRedraw',
11910 'postRedraw',
11911 'filtered',
11912 'zoomed');
11913
11914 var _legend;
11915
11916 var _filters = [];
11917 var _filterHandler = function (dimension, filters) {
11918 dimension.filter(null);
11919
11920 if (filters.length === 0) {
11921 dimension.filter(null);
11922 } else {
11923 dimension.filterFunction(function (d) {
11924 for (var i = 0; i < filters.length; i++) {
11925 var filter = filters[i];
11926 if (filter.isFiltered && filter.isFiltered(d)) {
11927 return true;
11928 } else if (filter <= d && filter >= d) {
11929 return true;
11930 }
11931 }
11932 return false;
11933 });
11934 }
11935 return filters;
11936 };
11937
11938 var _data = function (group) {
11939 return group.all();
11940 };
11941
11942 /**
11943 #### .width([value])
11944 Set or get the width attribute of a chart. See `.height` below for further description of the
11945 behavior.
11946
11947 **/
11948 _chart.width = function (w) {
11949 if (!arguments.length) {
11950 return _width(_root.node());
11951 }
11952 _width = d3.functor(w || _defaultWidth);
11953 return _chart;
11954 };
11955
11956 /**
11957 #### .height([value])
11958 Set or get the height attribute of a chart. The height is applied to the SVG element generated by
11959 the chart when rendered (or rerendered). If a value is given, then it will be used to calculate
11960 the new height and the chart returned for method chaining. The value can either be a numeric, a
11961 function, or falsy. If no value is specified then the value of the current height attribute will
11962 be returned.
11963
11964 By default, without an explicit height being given, the chart will select the width of its
11965 anchor element. If that isn't possible it defaults to 200. Setting the value falsy will return
11966 the chart to the default behavior
11967
11968 Examples:
11969
11970 ```js
11971 chart.height(250); // Set the chart's height to 250px;
11972 chart.height(function(anchor) { return doSomethingWith(anchor); }); // set the chart's height with a function
11973 chart.height(null); // reset the height to the default auto calculation
11974 ```
11975
11976 **/
11977 _chart.height = function (h) {
11978 if (!arguments.length) {
11979 return _height(_root.node());
11980 }
11981 _height = d3.functor(h || _defaultHeight);
11982 return _chart;
11983 };
11984
11985 /**
11986 #### .minWidth([value])
11987 Set or get the minimum width attribute of a chart. This only applicable if the width is
11988 calculated by dc.
11989
11990 **/
11991 _chart.minWidth = function (w) {
11992 if (!arguments.length) {
11993 return _minWidth;
11994 }
11995 _minWidth = w;
11996 return _chart;
11997 };
11998
11999 /**
12000 #### .minHeight([value])
12001 Set or get the minimum height attribute of a chart. This only applicable if the height is
12002 calculated by dc.
12003
12004 **/
12005 _chart.minHeight = function (w) {
12006 if (!arguments.length) {
12007 return _minHeight;
12008 }
12009 _minHeight = w;
12010 return _chart;
12011 };
12012
12013 /**
12014 #### .dimension([value]) - **mandatory**
12015 Set or get the dimension attribute of a chart. In dc a dimension can be any valid [crossfilter
12016 dimension](https://github.com/square/crossfilter/wiki/API-Reference#wiki-dimension).
12017
12018 If a value is given, then it will be used as the new dimension. If no value is specified then
12019 the current dimension will be returned.
12020
12021 **/
12022 _chart.dimension = function (d) {
12023 if (!arguments.length) {
12024 return _dimension;
12025 }
12026 _dimension = d;
12027 _chart.expireCache();
12028 return _chart;
12029 };
12030
12031 /**
12032 #### .data([callback])
12033 Set the data callback or retrieve the chart's data set. The data callback is passed the chart's
12034 group and by default will return `group.all()`. This behavior may be modified to, for instance,
12035 return only the top 5 groups:
12036 ```
12037 chart.data(function(group) {
12038 return group.top(5);
12039 });
12040 ```
12041 **/
12042 _chart.data = function (d) {
12043 if (!arguments.length) {
12044 return _data.call(_chart, _group);
12045 }
12046 _data = d3.functor(d);
12047 _chart.expireCache();
12048 return _chart;
12049 };
12050
12051 /**
12052 #### .group([value, [name]]) - **mandatory**
12053 Set or get the group attribute of a chart. In dc a group is a [crossfilter
12054 group](https://github.com/square/crossfilter/wiki/API-Reference#wiki-group). Usually the group
12055 should be created from the particular dimension associated with the same chart. If a value is
12056 given, then it will be used as the new group.
12057
12058 If no value specified then the current group will be returned.
12059 If `name` is specified then it will be used to generate legend label.
12060
12061 **/
12062 _chart.group = function (g, name) {
12063 if (!arguments.length) {
12064 return _group;
12065 }
12066 _group = g;
12067 _chart._groupName = name;
12068 _chart.expireCache();
12069 return _chart;
12070 };
12071
12072 /**
12073 #### .ordering([orderFunction])
12074 Get or set an accessor to order ordinal charts
12075 **/
12076 _chart.ordering = function (o) {
12077 if (!arguments.length) {
12078 return _ordering;
12079 }
12080 _ordering = o;
12081 _orderSort = crossfilter.quicksort.by(_ordering);
12082 _chart.expireCache();
12083 return _chart;
12084 };
12085
12086 _chart._computeOrderedGroups = function (data) {
12087 var dataCopy = data.slice(0);
12088
12089 if (dataCopy.length <= 1) {
12090 return dataCopy;
12091 }
12092
12093 if (!_orderSort) {
12094 _orderSort = crossfilter.quicksort.by(_ordering);
12095 }
12096
12097 return _orderSort(dataCopy, 0, dataCopy.length);
12098 };
12099
12100 /**
12101 #### .filterAll()
12102 Clear all filters associated with this chart.
12103
12104 **/
12105 _chart.filterAll = function () {
12106 return _chart.filter(null);
12107 };
12108
12109 /**
12110 #### .select(selector)
12111 Execute d3 single selection in the chart's scope using the given selector and return the d3
12112 selection. Roughly the same as:
12113 ```js
12114 d3.select('#chart-id').select(selector);
12115 ```
12116 This function is **not chainable** since it does not return a chart instance; however the d3
12117 selection result can be chained to d3 function calls.
12118
12119 **/
12120 _chart.select = function (s) {
12121 return _root.select(s);
12122 };
12123
12124 /**
12125 #### .selectAll(selector)
12126 Execute in scope d3 selectAll using the given selector and return d3 selection result. Roughly
12127 the same as:
12128 ```js
12129 d3.select('#chart-id').selectAll(selector);
12130 ```
12131 This function is **not chainable** since it does not return a chart instance; however the d3
12132 selection result can be chained to d3 function calls.
12133
12134 **/
12135 _chart.selectAll = function (s) {
12136 return _root ? _root.selectAll(s) : null;
12137 };
12138
12139 /**
12140 #### .anchor([anchorChart|anchorSelector|anchorNode], [chartGroup])
12141 Set the svg root to either be an existing chart's root; or any valid [d3 single
12142 selector](https://github.com/mbostock/d3/wiki/Selections#selecting-elements) specifying a dom
12143 block element such as a div; or a dom element or d3 selection. Optionally registers the chart
12144 within the chartGroup. This class is called internally on chart initialization, but be called
12145 again to relocate the chart. However, it will orphan any previously created SVG elements.
12146 **/
12147 _chart.anchor = function (a, chartGroup) {
12148 if (!arguments.length) {
12149 return _anchor;
12150 }
12151 if (dc.instanceOfChart(a)) {
12152 _anchor = a.anchor();
12153 _root = a.root();
12154 } else {
12155 _anchor = a;
12156 _root = d3.select(_anchor);
12157 _root.classed(dc.constants.CHART_CLASS, true);
12158 dc.registerChart(_chart, chartGroup);
12159 }
12160 _chartGroup = chartGroup;
12161 return _chart;
12162 };
12163
12164 /**
12165 #### .anchorName()
12166 Returns the dom id for the chart's anchored location.
12167
12168 **/
12169 _chart.anchorName = function () {
12170 var a = _chart.anchor();
12171 if (a && a.id) {
12172 return a.id;
12173 }
12174 if (a && a.replace) {
12175 return a.replace('#', '');
12176 }
12177 return '' + _chart.chartID();
12178 };
12179
12180 /**
12181 #### .root([rootElement])
12182 Returns the root element where a chart resides. Usually it will be the parent div element where
12183 the svg was created. You can also pass in a new root element however this is usually handled by
12184 dc internally. Resetting the root element on a chart outside of dc internals may have
12185 unexpected consequences.
12186
12187 **/
12188 _chart.root = function (r) {
12189 if (!arguments.length) {
12190 return _root;
12191 }
12192 _root = r;
12193 return _chart;
12194 };
12195
12196 /**
12197 #### .svg([svgElement])
12198 Returns the top svg element for this specific chart. You can also pass in a new svg element,
12199 however this is usually handled by dc internally. Resetting the svg element on a chart outside
12200 of dc internals may have unexpected consequences.
12201
12202 **/
12203 _chart.svg = function (_) {
12204 if (!arguments.length) {
12205 return _svg;
12206 }
12207 _svg = _;
12208 return _chart;
12209 };
12210
12211 /**
12212 #### .resetSvg()
12213 Remove the chart's SVG elements from the dom and recreate the container SVG element.
12214 **/
12215 _chart.resetSvg = function () {
12216 _chart.select('svg').remove();
12217 return generateSvg();
12218 };
12219
12220 function generateSvg() {
12221 _svg = _chart.root().append('svg')
12222 .attr('width', _chart.width())
12223 .attr('height', _chart.height());
12224 return _svg;
12225 }
12226
12227 /**
12228 #### .filterPrinter([filterPrinterFunction])
12229 Set or get the filter printer function. The filter printer function is used to generate human
12230 friendly text for filter value(s) associated with the chart instance. By default dc charts use a
12231 default filter printer `dc.printers.filter` that provides simple printing support for both
12232 single value and ranged filters.
12233
12234 **/
12235 _chart.filterPrinter = function (_) {
12236 if (!arguments.length) {
12237 return _filterPrinter;
12238 }
12239 _filterPrinter = _;
12240 return _chart;
12241 };
12242
12243 /**
12244 #### .turnOnControls() & .turnOffControls()
12245 Turn on/off optional control elements within the root element. dc currently supports the
12246 following html control elements.
12247
12248 * root.selectAll('.reset') - elements are turned on if the chart has an active filter. This type
12249 of control element is usually used to store a reset link to allow user to reset filter on a
12250 certain chart. This element will be turned off automatically if the filter is cleared.
12251 * root.selectAll('.filter') elements are turned on if the chart has an active filter. The text
12252 content of this element is then replaced with the current filter value using the filter printer
12253 function. This type of element will be turned off automatically if the filter is cleared.
12254
12255 **/
12256 _chart.turnOnControls = function () {
12257 if (_root) {
12258 _chart.selectAll('.reset').style('display', null);
12259 _chart.selectAll('.filter').text(_filterPrinter(_chart.filters())).style('display', null);
12260 }
12261 return _chart;
12262 };
12263
12264 _chart.turnOffControls = function () {
12265 if (_root) {
12266 _chart.selectAll('.reset').style('display', 'none');
12267 _chart.selectAll('.filter').style('display', 'none').text(_chart.filter());
12268 }
12269 return _chart;
12270 };
12271
12272 /**
12273 #### .transitionDuration([duration])
12274 Set or get the animation transition duration(in milliseconds) for this chart instance. Default
12275 duration is 750ms.
12276
12277 **/
12278 _chart.transitionDuration = function (d) {
12279 if (!arguments.length) {
12280 return _transitionDuration;
12281 }
12282 _transitionDuration = d;
12283 return _chart;
12284 };
12285
12286 _chart._mandatoryAttributes = function (_) {
12287 if (!arguments.length) {
12288 return _mandatoryAttributes;
12289 }
12290 _mandatoryAttributes = _;
12291 return _chart;
12292 };
12293
12294 function checkForMandatoryAttributes(a) {
12295 if (!_chart[a] || !_chart[a]()) {
12296 throw new dc.errors.InvalidStateException('Mandatory attribute chart.' + a +
12297 ' is missing on chart[#' + _chart.anchorName() + ']');
12298 }
12299 }
12300
12301 /**
12302 #### .render()
12303 Invoking this method will force the chart to re-render everything from scratch. Generally it
12304 should only be used to render the chart for the first time on the page or if you want to make
12305 sure everything is redrawn from scratch instead of relying on the default incremental redrawing
12306 behaviour.
12307
12308 **/
12309 _chart.render = function () {
12310 _listeners.preRender(_chart);
12311
12312 if (_mandatoryAttributes) {
12313 _mandatoryAttributes.forEach(checkForMandatoryAttributes);
12314 }
12315
12316 var result = _chart._doRender();
12317
12318 if (_legend) {
12319 _legend.render();
12320 }
12321
12322 _chart._activateRenderlets('postRender');
12323
12324 return result;
12325 };
12326
12327 _chart._activateRenderlets = function (event) {
12328 if (_chart.transitionDuration() > 0 && _svg) {
12329 _svg.transition().duration(_chart.transitionDuration())
12330 .each('end', function () {
12331 runAllRenderlets();
12332 if (event) {
12333 _listeners[event](_chart);
12334 }
12335 });
12336 } else {
12337 runAllRenderlets();
12338 if (event) {
12339 _listeners[event](_chart);
12340 }
12341 }
12342 };
12343
12344 /**
12345 #### .redraw()
12346 Calling redraw will cause the chart to re-render data changes incrementally. If there is no
12347 change in the underlying data dimension then calling this method will have no effect on the
12348 chart. Most chart interaction in dc will automatically trigger this method through internal
12349 events (in particular [dc.redrawAll](#dcredrawallchartgroup)); therefore, you only need to
12350 manually invoke this function if data is manipulated outside of dc's control (for example if
12351 data is loaded in the background using `crossfilter.add()`).
12352
12353 **/
12354 _chart.redraw = function () {
12355 _listeners.preRedraw(_chart);
12356
12357 var result = _chart._doRedraw();
12358
12359 if (_legend) {
12360 _legend.render();
12361 }
12362
12363 _chart._activateRenderlets('postRedraw');
12364
12365 return result;
12366 };
12367
12368 _chart.redrawGroup = function () {
12369 dc.redrawAll(_chart.chartGroup());
12370 };
12371
12372 _chart.renderGroup = function () {
12373 dc.renderAll(_chart.chartGroup());
12374 };
12375
12376 _chart._invokeFilteredListener = function (f) {
12377 if (f !== undefined) {
12378 _listeners.filtered(_chart, f);
12379 }
12380 };
12381
12382 _chart._invokeZoomedListener = function () {
12383 _listeners.zoomed(_chart);
12384 };
12385
12386 var _hasFilterHandler = function (filters, filter) {
12387 if (filter === null || typeof(filter) === 'undefined') {
12388 return filters.length > 0;
12389 }
12390 return filters.some(function (f) {
12391 return filter <= f && filter >= f;
12392 });
12393 };
12394
12395 /**
12396 #### .hasFilterHandler([function])
12397 Set or get the has filter handler. The has filter handler is a function that checks to see if
12398 the chart's current filters include a specific filter. Using a custom has filter handler allows
12399 you to change the way filters are checked for and replaced.
12400
12401 ```js
12402 // default has filter handler
12403 function (filters, filter) {
12404 if (filter === null || typeof(filter) === 'undefined') {
12405 return filters.length > 0;
12406 }
12407 return filters.some(function (f) {
12408 return filter <= f && filter >= f;
12409 });
12410 }
12411
12412 // custom filter handler (no-op)
12413 chart.hasFilterHandler(function(filters, filter) {
12414 return false;
12415 });
12416 ```
12417 **/
12418 _chart.hasFilterHandler = function (_) {
12419 if (!arguments.length) {
12420 return _hasFilterHandler;
12421 }
12422 _hasFilterHandler = _;
12423 return _chart;
12424 };
12425
12426 /**
12427 #### .hasFilter([filter])
12428 Check whether any active filter or a specific filter is associated with particular chart instance.
12429 This function is **not chainable**.
12430
12431 **/
12432 _chart.hasFilter = function (filter) {
12433 return _hasFilterHandler(_filters, filter);
12434 };
12435
12436 var _removeFilterHandler = function (filters, filter) {
12437 for (var i = 0; i < filters.length; i++) {
12438 if (filters[i] <= filter && filters[i] >= filter) {
12439 filters.splice(i, 1);
12440 break;
12441 }
12442 }
12443 return filters;
12444 };
12445
12446 /**
12447 #### .removeFilterHandler([function])
12448 Set or get the remove filter handler. The remove filter handler is a function that removes a
12449 filter from the chart's current filters. Using a custom remove filter handler allows you to
12450 change how filters are removed or perform additional work when removing a filter, e.g. when
12451 using a filter server other than crossfilter.
12452
12453 Any changes should modify the `filters` array argument and return that array.
12454
12455 ```js
12456 // default remove filter handler
12457 function (filters, filter) {
12458 for (var i = 0; i < filters.length; i++) {
12459 if (filters[i] <= filter && filters[i] >= filter) {
12460 filters.splice(i, 1);
12461 break;
12462 }
12463 }
12464 return filters;
12465 }
12466
12467 // custom filter handler (no-op)
12468 chart.removeFilterHandler(function(filters, filter) {
12469 return filters;
12470 });
12471 ```
12472 **/
12473 _chart.removeFilterHandler = function (_) {
12474 if (!arguments.length) {
12475 return _removeFilterHandler;
12476 }
12477 _removeFilterHandler = _;
12478 return _chart;
12479 };
12480
12481 var _addFilterHandler = function (filters, filter) {
12482 filters.push(filter);
12483 return filters;
12484 };
12485
12486 /**
12487 #### .addFilterHandler([function])
12488 Set or get the add filter handler. The add filter handler is a function that adds a filter to
12489 the chart's filter list. Using a custom add filter handler allows you to change the way filters
12490 are added or perform additional work when adding a filter, e.g. when using a filter server other
12491 than crossfilter.
12492
12493 Any changes should modify the `filters` array argument and return that array.
12494
12495 ```js
12496 // default add filter handler
12497 function (filters, filter) {
12498 filters.push(filter);
12499 return filters;
12500 }
12501
12502 // custom filter handler (no-op)
12503 chart.addFilterHandler(function(filters, filter) {
12504 return filters;
12505 });
12506 ```
12507 **/
12508 _chart.addFilterHandler = function (_) {
12509 if (!arguments.length) {
12510 return _addFilterHandler;
12511 }
12512 _addFilterHandler = _;
12513 return _chart;
12514 };
12515
12516 var _resetFilterHandler = function (filters) {
12517 return [];
12518 };
12519
12520 /**
12521 #### .resetFilterHandler([function])
12522 Set or get the reset filter handler. The reset filter handler is a function that resets the
12523 chart's filter list by returning a new list. Using a custom reset filter handler allows you to
12524 change the way filters are reset, or perform additional work when resetting the filters,
12525 e.g. when using a filter server other than crossfilter.
12526
12527 This function should return an array.
12528
12529 ```js
12530 // default remove filter handler
12531 function (filters) {
12532 return [];
12533 }
12534
12535 // custom filter handler (no-op)
12536 chart.resetFilterHandler(function(filters) {
12537 return filters;
12538 });
12539 ```
12540 **/
12541 _chart.resetFilterHandler = function (_) {
12542 if (!arguments.length) {
12543 return _resetFilterHandler;
12544 }
12545 _resetFilterHandler = _;
12546 return _chart;
12547 };
12548
12549 function applyFilters() {
12550 if (_chart.dimension() && _chart.dimension().filter) {
12551 var fs = _filterHandler(_chart.dimension(), _filters);
12552 _filters = fs ? fs : _filters;
12553 }
12554 }
12555
12556 _chart.replaceFilter = function (_) {
12557 _filters = [];
12558 _chart.filter(_);
12559 };
12560
12561 /**
12562 #### .filter([filterValue])
12563 Filter the chart by the given value or return the current filter if the input parameter is missing.
12564 ```js
12565 // filter by a single string
12566 chart.filter('Sunday');
12567 // filter by a single age
12568 chart.filter(18);
12569 ```
12570 **/
12571 _chart.filter = function (_) {
12572 if (!arguments.length) {
12573 return _filters.length > 0 ? _filters[0] : null;
12574 }
12575 if (_ instanceof Array && _[0] instanceof Array && !_.isFiltered) {
12576 _[0].forEach(function (d) {
12577 if (_chart.hasFilter(d)) {
12578 _removeFilterHandler(_filters, d);
12579 } else {
12580 _addFilterHandler(_filters, d);
12581 }
12582 });
12583 } else if (_ === null) {
12584 _filters = _resetFilterHandler(_filters);
12585 } else {
12586 if (_chart.hasFilter(_)) {
12587 _removeFilterHandler(_filters, _);
12588 } else {
12589 _addFilterHandler(_filters, _);
12590 }
12591 }
12592 applyFilters();
12593 _chart._invokeFilteredListener(_);
12594
12595 if (_root !== null && _chart.hasFilter()) {
12596 _chart.turnOnControls();
12597 } else {
12598 _chart.turnOffControls();
12599 }
12600
12601 return _chart;
12602 };
12603
12604 /**
12605 #### .filters()
12606 Returns all current filters. This method does not perform defensive cloning of the internal
12607 filter array before returning, therefore any modification of the returned array will effect the
12608 chart's internal filter storage.
12609
12610 **/
12611 _chart.filters = function () {
12612 return _filters;
12613 };
12614
12615 _chart.highlightSelected = function (e) {
12616 d3.select(e).classed(dc.constants.SELECTED_CLASS, true);
12617 d3.select(e).classed(dc.constants.DESELECTED_CLASS, false);
12618 };
12619
12620 _chart.fadeDeselected = function (e) {
12621 d3.select(e).classed(dc.constants.SELECTED_CLASS, false);
12622 d3.select(e).classed(dc.constants.DESELECTED_CLASS, true);
12623 };
12624
12625 _chart.resetHighlight = function (e) {
12626 d3.select(e).classed(dc.constants.SELECTED_CLASS, false);
12627 d3.select(e).classed(dc.constants.DESELECTED_CLASS, false);
12628 };
12629
12630 /**
12631 #### .onClick(datum)
12632 This function is passed to d3 as the onClick handler for each chart. The default behavior is to
12633 filter on the clicked datum (passed to the callback) and redraw the chart group.
12634 **/
12635 _chart.onClick = function (d) {
12636 var filter = _chart.keyAccessor()(d);
12637 dc.events.trigger(function () {
12638 _chart.filter(filter);
12639 _chart.redrawGroup();
12640 });
12641 };
12642
12643 /**
12644 #### .filterHandler([function])
12645 Set or get the filter handler. The filter handler is a function that performs the filter action
12646 on a specific dimension. Using a custom filter handler allows you to perform additional logic
12647 before or after filtering.
12648
12649 ```js
12650 // default filter handler
12651 function(dimension, filter){
12652 dimension.filter(filter); // perform filtering
12653 return filter; // return the actual filter value
12654 }
12655
12656 // custom filter handler
12657 chart.filterHandler(function(dimension, filter){
12658 var newFilter = filter + 10;
12659 dimension.filter(newFilter);
12660 return newFilter; // set the actual filter value to the new value
12661 });
12662 ```
12663
12664 **/
12665 _chart.filterHandler = function (_) {
12666 if (!arguments.length) {
12667 return _filterHandler;
12668 }
12669 _filterHandler = _;
12670 return _chart;
12671 };
12672
12673 // abstract function stub
12674 _chart._doRender = function () {
12675 // do nothing in base, should be overridden by sub-function
12676 return _chart;
12677 };
12678
12679 _chart._doRedraw = function () {
12680 // do nothing in base, should be overridden by sub-function
12681 return _chart;
12682 };
12683
12684 _chart.legendables = function () {
12685 // do nothing in base, should be overridden by sub-function
12686 return [];
12687 };
12688
12689 _chart.legendHighlight = function () {
12690 // do nothing in base, should be overridden by sub-function
12691 };
12692
12693 _chart.legendReset = function () {
12694 // do nothing in base, should be overridden by sub-function
12695 };
12696
12697 _chart.legendToggle = function () {
12698 // do nothing in base, should be overriden by sub-function
12699 };
12700
12701 _chart.isLegendableHidden = function () {
12702 // do nothing in base, should be overridden by sub-function
12703 return false;
12704 };
12705
12706 /**
12707 #### .keyAccessor([keyAccessorFunction])
12708 Set or get the key accessor function. The key accessor function is used to retrieve the key
12709 value from the crossfilter group. Key values are used differently in different charts, for
12710 example keys correspond to slices in a pie chart and x axis positions in a grid coordinate chart.
12711 ```js
12712 // default key accessor
12713 chart.keyAccessor(function(d) { return d.key; });
12714 // custom key accessor for a multi-value crossfilter reduction
12715 chart.keyAccessor(function(p) { return p.value.absGain; });
12716 ```
12717
12718 **/
12719 _chart.keyAccessor = function (_) {
12720 if (!arguments.length) {
12721 return _keyAccessor;
12722 }
12723 _keyAccessor = _;
12724 return _chart;
12725 };
12726
12727 /**
12728 #### .valueAccessor([valueAccessorFunction])
12729 Set or get the value accessor function. The value accessor function is used to retrieve the
12730 value from the crossfilter group. Group values are used differently in different charts, for
12731 example values correspond to slice sizes in a pie chart and y axis positions in a grid
12732 coordinate chart.
12733 ```js
12734 // default value accessor
12735 chart.valueAccessor(function(d) { return d.value; });
12736 // custom value accessor for a multi-value crossfilter reduction
12737 chart.valueAccessor(function(p) { return p.value.percentageGain; });
12738 ```
12739
12740 **/
12741 _chart.valueAccessor = function (_) {
12742 if (!arguments.length) {
12743 return _valueAccessor;
12744 }
12745 _valueAccessor = _;
12746 return _chart;
12747 };
12748
12749 /**
12750 #### .label([labelFunction])
12751 Set or get the label function. The chart class will use this function to render labels for each
12752 child element in the chart, e.g. slices in a pie chart or bubbles in a bubble chart. Not every
12753 chart supports the label function for example bar chart and line chart do not use this function
12754 at all.
12755 ```js
12756 // default label function just return the key
12757 chart.label(function(d) { return d.key; });
12758 // label function has access to the standard d3 data binding and can get quite complicated
12759 chart.label(function(d) { return d.data.key + '(' + Math.floor(d.data.value / all.value() * 100) + '%)'; });
12760 ```
12761
12762 **/
12763 _chart.label = function (_) {
12764 if (!arguments.length) {
12765 return _label;
12766 }
12767 _label = _;
12768 _renderLabel = true;
12769 return _chart;
12770 };
12771
12772 /**
12773 #### .renderLabel(boolean)
12774 Turn on/off label rendering
12775
12776 **/
12777 _chart.renderLabel = function (_) {
12778 if (!arguments.length) {
12779 return _renderLabel;
12780 }
12781 _renderLabel = _;
12782 return _chart;
12783 };
12784
12785 /**
12786 #### .title([titleFunction])
12787 Set or get the title function. The chart class will use this function to render the svg title
12788 (usually interpreted by browser as tooltips) for each child element in the chart, e.g. a slice
12789 in a pie chart or a bubble in a bubble chart. Almost every chart supports the title function;
12790 however in grid coordinate charts you need to turn off the brush in order to see titles, because
12791 otherwise the brush layer will block tooltip triggering.
12792 ```js
12793 // default title function just return the key
12794 chart.title(function(d) { return d.key + ': ' + d.value; });
12795 // title function has access to the standard d3 data binding and can get quite complicated
12796 chart.title(function(p) {
12797 return p.key.getFullYear()
12798 + '\n'
12799 + 'Index Gain: ' + numberFormat(p.value.absGain) + '\n'
12800 + 'Index Gain in Percentage: ' + numberFormat(p.value.percentageGain) + '%\n'
12801 + 'Fluctuation / Index Ratio: ' + numberFormat(p.value.fluctuationPercentage) + '%';
12802 });
12803 ```
12804
12805 **/
12806 _chart.title = function (_) {
12807 if (!arguments.length) {
12808 return _title;
12809 }
12810 _title = _;
12811 return _chart;
12812 };
12813
12814 /**
12815 #### .renderTitle(boolean)
12816 Turn on/off title rendering, or return the state of the render title flag if no arguments are
12817 given.
12818
12819 **/
12820 _chart.renderTitle = function (_) {
12821 if (!arguments.length) {
12822 return _renderTitle;
12823 }
12824 _renderTitle = _;
12825 return _chart;
12826 };
12827
12828 /**
12829 #### .renderlet(renderletFunction)
12830 A renderlet is similar to an event listener on rendering event. Multiple renderlets can be added
12831 to an individual chart. Each time a chart is rerendered or redrawn the renderlets are invoked
12832 right after the chart finishes its own drawing routine, giving you a way to modify the svg
12833 elements. Renderlet functions take the chart instance as the only input parameter and you can
12834 use the dc API or use raw d3 to achieve pretty much any effect.
12835 ```js
12836 // renderlet function
12837 chart.renderlet(function(chart){
12838 // mix of dc API and d3 manipulation
12839 chart.select('g.y').style('display', 'none');
12840 // its a closure so you can also access other chart variable available in the closure scope
12841 moveChart.filter(chart.filter());
12842 });
12843 ```
12844
12845 **/
12846 _chart.renderlet = function (_) {
12847 _renderlets.push(_);
12848 return _chart;
12849 };
12850
12851 function runAllRenderlets() {
12852 for (var i = 0; i < _renderlets.length; ++i) {
12853 _renderlets[i](_chart);
12854 }
12855 }
12856
12857 /**
12858 #### .chartGroup([group])
12859 Get or set the chart group to which this chart belongs. Chart groups are rendered or redrawn
12860 together since it is expected they share the same underlying crossfilter data set.
12861 **/
12862 _chart.chartGroup = function (_) {
12863 if (!arguments.length) {
12864 return _chartGroup;
12865 }
12866 _chartGroup = _;
12867 return _chart;
12868 };
12869
12870 /**
12871 #### .expireCache()
12872 Expire the internal chart cache. dc charts cache some data internally on a per chart basis to
12873 speed up rendering and avoid unnecessary calculation; however it might be useful to clear the
12874 cache if you have changed state which will affect rendering. For example if you invoke the
12875 `crossfilter.add` function or reset group or dimension after rendering it is a good idea to
12876 clear the cache to make sure charts are rendered properly.
12877
12878 **/
12879 _chart.expireCache = function () {
12880 // do nothing in base, should be overridden by sub-function
12881 return _chart;
12882 };
12883
12884 /**
12885 #### .legend([dc.legend])
12886 Attach a dc.legend widget to this chart. The legend widget will automatically draw legend labels
12887 based on the color setting and names associated with each group.
12888
12889 ```js
12890 chart.legend(dc.legend().x(400).y(10).itemHeight(13).gap(5))
12891 ```
12892
12893 **/
12894 _chart.legend = function (l) {
12895 if (!arguments.length) {
12896 return _legend;
12897 }
12898 _legend = l;
12899 _legend.parent(_chart);
12900 return _chart;
12901 };
12902
12903 /**
12904 #### .chartID()
12905 Returns the internal numeric ID of the chart.
12906 **/
12907 _chart.chartID = function () {
12908 return _chart.__dcFlag__;
12909 };
12910
12911 /**
12912 #### .options(optionsObject)
12913 Set chart options using a configuration object. Each key in the object will cause the method of
12914 the same name to be called with the value to set that attribute for the chart.
12915
12916 Example:
12917 ```
12918 chart.options({dimension: myDimension, group: myGroup});
12919 ```
12920 **/
12921 _chart.options = function (opts) {
12922 for (var o in opts) {
12923 if (typeof(_chart[o]) === 'function') {
12924 _chart[o].call(_chart, opts[o]);
12925 } else {
12926 dc.logger.debug('Not a valid option setter name: ' + o);
12927 }
12928 }
12929 return _chart;
12930 };
12931
12932 /**
12933 ## Listeners
12934 All dc chart instance supports the following listeners.
12935
12936 #### .on('preRender', function(chart){...})
12937 This listener function will be invoked before chart rendering.
12938
12939 #### .on('postRender', function(chart){...})
12940 This listener function will be invoked after chart finish rendering including all renderlets' logic.
12941
12942 #### .on('preRedraw', function(chart){...})
12943 This listener function will be invoked before chart redrawing.
12944
12945 #### .on('postRedraw', function(chart){...})
12946 This listener function will be invoked after chart finish redrawing including all renderlets' logic.
12947
12948 #### .on('filtered', function(chart, filter){...})
12949 This listener function will be invoked after a filter is applied, added or removed.
12950
12951 #### .on('zoomed', function(chart, filter){...})
12952 This listener function will be invoked after a zoom is triggered.
12953
12954 **/
12955 _chart.on = function (event, listener) {
12956 _listeners.on(event, listener);
12957 return _chart;
12958 };
12959
12960 return _chart;
12961 };
12962
12963 /**
12964 ## Margin Mixin
12965 Margin is a mixin that provides margin utility functions for both the Row Chart and Coordinate Grid
12966 Charts.
12967
12968 **/
12969 dc.marginMixin = function (_chart) {
12970 var _margin = {top: 10, right: 50, bottom: 30, left: 30};
12971
12972 /**
12973 #### .margins([margins])
12974 Get or set the margins for a particular coordinate grid chart instance. The margins is stored as
12975 an associative Javascript array. Default margins: {top: 10, right: 50, bottom: 30, left: 30}.
12976
12977 The margins can be accessed directly from the getter.
12978 ```js
12979 var leftMargin = chart.margins().left; // 30 by default
12980 chart.margins().left = 50;
12981 leftMargin = chart.margins().left; // now 50
12982 ```
12983
12984 **/
12985 _chart.margins = function (m) {
12986 if (!arguments.length) {
12987 return _margin;
12988 }
12989 _margin = m;
12990 return _chart;
12991 };
12992
12993 _chart.effectiveWidth = function () {
12994 return _chart.width() - _chart.margins().left - _chart.margins().right;
12995 };
12996
12997 _chart.effectiveHeight = function () {
12998 return _chart.height() - _chart.margins().top - _chart.margins().bottom;
12999 };
13000
13001 return _chart;
13002 };
13003
13004 /**
13005 ## Color Mixin
13006 The Color Mixin is an abstract chart functional class providing universal coloring support
13007 as a mix-in for any concrete chart implementation.
13008
13009 **/
13010
13011 dc.colorMixin = function (_chart) {
13012 var _colors = d3.scale.category20c();
13013 var _defaultAccessor = true;
13014
13015 var _colorAccessor = function (d) { return _chart.keyAccessor()(d); };
13016
13017 /**
13018 #### .colors([colorScale])
13019 Retrieve current color scale or set a new color scale. This methods accepts any function that
13020 operates like a d3 scale. If not set the default is
13021 `d3.scale.category20c()`.
13022 ```js
13023 // alternate categorical scale
13024 chart.colors(d3.scale.category20b());
13025
13026 // ordinal scale
13027 chart.colors(d3.scale.ordinal().range(['red','green','blue']));
13028 // convenience method, the same as above
13029 chart.ordinalColors(['red','green','blue']);
13030
13031 // set a linear scale
13032 chart.linearColors(["#4575b4", "#ffffbf", "#a50026"]);
13033 ```
13034 **/
13035 _chart.colors = function (_) {
13036 if (!arguments.length) {
13037 return _colors;
13038 }
13039 if (_ instanceof Array) {
13040 _colors = d3.scale.quantize().range(_); // deprecated legacy support, note: this fails for ordinal domains
13041 } else {
13042 _colors = d3.functor(_);
13043 }
13044 return _chart;
13045 };
13046
13047 /**
13048 #### .ordinalColors(r)
13049 Convenience method to set the color scale to d3.scale.ordinal with range `r`.
13050
13051 **/
13052 _chart.ordinalColors = function (r) {
13053 return _chart.colors(d3.scale.ordinal().range(r));
13054 };
13055
13056 /**
13057 #### .linearColors(r)
13058 Convenience method to set the color scale to an Hcl interpolated linear scale with range `r`.
13059
13060 **/
13061 _chart.linearColors = function (r) {
13062 return _chart.colors(d3.scale.linear()
13063 .range(r)
13064 .interpolate(d3.interpolateHcl));
13065 };
13066
13067 /**
13068 #### .colorAccessor([colorAccessorFunction])
13069 Set or the get color accessor function. This function will be used to map a data point in a
13070 crossfilter group to a color value on the color scale. The default function uses the key
13071 accessor.
13072 ```js
13073 // default index based color accessor
13074 .colorAccessor(function (d, i){return i;})
13075 // color accessor for a multi-value crossfilter reduction
13076 .colorAccessor(function (d){return d.value.absGain;})
13077 ```
13078 **/
13079 _chart.colorAccessor = function (_) {
13080 if (!arguments.length) {
13081 return _colorAccessor;
13082 }
13083 _colorAccessor = _;
13084 _defaultAccessor = false;
13085 return _chart;
13086 };
13087
13088 // what is this?
13089 _chart.defaultColorAccessor = function () {
13090 return _defaultAccessor;
13091 };
13092
13093 /**
13094 #### .colorDomain([domain])
13095 Set or get the current domain for the color mapping function. The domain must be supplied as an
13096 array.
13097
13098 Note: previously this method accepted a callback function. Instead you may use a custom scale
13099 set by `.colors`.
13100
13101 **/
13102 _chart.colorDomain = function (_) {
13103 if (!arguments.length) {
13104 return _colors.domain();
13105 }
13106 _colors.domain(_);
13107 return _chart;
13108 };
13109
13110 /**
13111 #### .calculateColorDomain()
13112 Set the domain by determining the min and max values as retrieved by `.colorAccessor` over the
13113 chart's dataset.
13114
13115 **/
13116 _chart.calculateColorDomain = function () {
13117 var newDomain = [d3.min(_chart.data(), _chart.colorAccessor()),
13118 d3.max(_chart.data(), _chart.colorAccessor())];
13119 _colors.domain(newDomain);
13120 };
13121
13122 /**
13123 #### .getColor(d [, i])
13124 Get the color for the datum d and counter i. This is used internally by charts to retrieve a color.
13125
13126 **/
13127 _chart.getColor = function (d, i) {
13128 return _colors(_colorAccessor.call(this, d, i));
13129 };
13130
13131 /**
13132 #### .colorCalculator([value])
13133 Gets or sets chart.getColor.
13134 **/
13135 _chart.colorCalculator = function (_) {
13136 if (!arguments.length) {
13137 return _chart.getColor;
13138 }
13139 _chart.getColor = _;
13140 return _chart;
13141 };
13142
13143 return _chart;
13144 };
13145
13146 /**
13147 ## Coordinate Grid Mixin
13148 Includes: [Color Mixin](#color-mixin), [Margin Mixin](#margin-mixin), [Base Mixin](#base-mixin)
13149
13150 Coordinate Grid is an abstract base chart designed to support a number of coordinate grid based
13151 concrete chart types, e.g. bar chart, line chart, and bubble chart.
13152
13153 **/
13154 dc.coordinateGridMixin = function (_chart) {
13155 var GRID_LINE_CLASS = 'grid-line';
13156 var HORIZONTAL_CLASS = 'horizontal';
13157 var VERTICAL_CLASS = 'vertical';
13158 var Y_AXIS_LABEL_CLASS = 'y-axis-label';
13159 var X_AXIS_LABEL_CLASS = 'x-axis-label';
13160 var DEFAULT_AXIS_LABEL_PADDING = 12;
13161
13162 _chart = dc.colorMixin(dc.marginMixin(dc.baseMixin(_chart)));
13163
13164 _chart.colors(d3.scale.category10());
13165 _chart._mandatoryAttributes().push('x');
13166
13167 function zoomHandler () {
13168 _refocused = true;
13169 if (_zoomOutRestrict) {
13170 _chart.x().domain(constrainRange(_chart.x().domain(), _xOriginalDomain));
13171 if (_rangeChart) {
13172 _chart.x().domain(constrainRange(_chart.x().domain(), _rangeChart.x().domain()));
13173 }
13174 }
13175
13176 var domain = _chart.x().domain();
13177 var domFilter = dc.filters.RangedFilter(domain[0], domain[1]);
13178
13179 _chart.replaceFilter(domFilter);
13180 _chart.rescale();
13181 _chart.redraw();
13182
13183 if (_rangeChart && !rangesEqual(_chart.filter(), _rangeChart.filter())) {
13184 dc.events.trigger(function () {
13185 _rangeChart.replaceFilter(domFilter);
13186 _rangeChart.redraw();
13187 });
13188 }
13189
13190 _chart._invokeZoomedListener();
13191
13192 dc.events.trigger(function () {
13193 _chart.redrawGroup();
13194 }, dc.constants.EVENT_DELAY);
13195
13196 _refocused = !rangesEqual(domain, _xOriginalDomain);
13197 }
13198
13199 var _parent;
13200 var _g;
13201 var _chartBodyG;
13202
13203 var _x;
13204 var _xOriginalDomain;
13205 var _xAxis = d3.svg.axis().orient('bottom');
13206 var _xUnits = dc.units.integers;
13207 var _xAxisPadding = 0;
13208 var _xElasticity = false;
13209 var _xAxisLabel;
13210 var _xAxisLabelPadding = 0;
13211 var _lastXDomain;
13212
13213 var _y;
13214 var _yAxis = d3.svg.axis().orient('left');
13215 var _yAxisPadding = 0;
13216 var _yElasticity = false;
13217 var _yAxisLabel;
13218 var _yAxisLabelPadding = 0;
13219
13220 var _brush = d3.svg.brush();
13221 var _brushOn = true;
13222 var _round;
13223
13224 var _renderHorizontalGridLine = false;
13225 var _renderVerticalGridLine = false;
13226
13227 var _refocused = false;
13228 var _unitCount;
13229
13230 var _zoomScale = [1, Infinity];
13231 var _zoomOutRestrict = true;
13232
13233 var _zoom = d3.behavior.zoom().on('zoom', zoomHandler);
13234 var _nullZoom = d3.behavior.zoom().on('zoom', null);
13235 var _hasBeenMouseZoomable = false;
13236
13237 var _rangeChart;
13238 var _focusChart;
13239
13240 var _mouseZoomable = false;
13241 var _clipPadding = 0;
13242
13243 var _outerRangeBandPadding = 0.5;
13244 var _rangeBandPadding = 0;
13245
13246 var _useRightYAxis = false;
13247
13248 _chart.rescale = function () {
13249 _unitCount = undefined;
13250 };
13251
13252 /**
13253 #### .rangeChart([chart])
13254 Get or set the range selection chart associated with this instance. Setting the range selection
13255 chart using this function will automatically update its selection brush when the current chart
13256 zooms in. In return the given range chart will also automatically attach this chart as its focus
13257 chart hence zoom in when range brush updates. See the [Nasdaq 100
13258 Index](http://dc-js.github.com/dc.js/) example for this effect in action.
13259
13260 **/
13261 _chart.rangeChart = function (_) {
13262 if (!arguments.length) {
13263 return _rangeChart;
13264 }
13265 _rangeChart = _;
13266 _rangeChart.focusChart(_chart);
13267 return _chart;
13268 };
13269
13270 /**
13271 #### .zoomScale([extent])
13272 Get or set the scale extent for mouse zooms.
13273
13274 **/
13275 _chart.zoomScale = function (_) {
13276 if (!arguments.length) {
13277 return _zoomScale;
13278 }
13279 _zoomScale = _;
13280 return _chart;
13281 };
13282
13283 /**
13284 #### .zoomOutRestrict([true/false])
13285 Get or set the zoom restriction for the chart. If true limits the zoom to origional domain of the chart.
13286 **/
13287 _chart.zoomOutRestrict = function (r) {
13288 if (!arguments.length) {
13289 return _zoomOutRestrict;
13290 }
13291 _zoomScale[0] = r ? 1 : 0;
13292 _zoomOutRestrict = r;
13293 return _chart;
13294 };
13295
13296 _chart._generateG = function (parent) {
13297 if (parent === undefined) {
13298 _parent = _chart.svg();
13299 } else {
13300 _parent = parent;
13301 }
13302
13303 _g = _parent.append('g');
13304
13305 _chartBodyG = _g.append('g').attr('class', 'chart-body')
13306 .attr('transform', 'translate(' + _chart.margins().left + ', ' + _chart.margins().top + ')')
13307 .attr('clip-path', 'url(#' + getClipPathId() + ')');
13308
13309 return _g;
13310 };
13311
13312 /**
13313 #### .g([gElement])
13314 Get or set the root g element. This method is usually used to retrieve the g element in order to
13315 overlay custom svg drawing programatically. **Caution**: The root g element is usually generated
13316 by dc.js internals, and resetting it might produce unpredictable result.
13317
13318 **/
13319 _chart.g = function (_) {
13320 if (!arguments.length) {
13321 return _g;
13322 }
13323 _g = _;
13324 return _chart;
13325 };
13326
13327 /**
13328 #### .mouseZoomable([boolean])
13329 Set or get mouse zoom capability flag (default: false). When turned on the chart will be
13330 zoomable using the mouse wheel. If the range selector chart is attached zooming will also update
13331 the range selection brush on the associated range selector chart.
13332
13333 **/
13334 _chart.mouseZoomable = function (z) {
13335 if (!arguments.length) {
13336 return _mouseZoomable;
13337 }
13338 _mouseZoomable = z;
13339 return _chart;
13340 };
13341
13342 /**
13343 #### .chartBodyG()
13344 Retrieve the svg group for the chart body.
13345 **/
13346 _chart.chartBodyG = function (_) {
13347 if (!arguments.length) {
13348 return _chartBodyG;
13349 }
13350 _chartBodyG = _;
13351 return _chart;
13352 };
13353
13354 /**
13355 #### .x([xScale]) - **mandatory**
13356 Get or set the x scale. The x scale can be any d3
13357 [quantitive scale](https://github.com/mbostock/d3/wiki/Quantitative-Scales) or
13358 [ordinal scale](https://github.com/mbostock/d3/wiki/Ordinal-Scales).
13359 ```js
13360 // set x to a linear scale
13361 chart.x(d3.scale.linear().domain([-2500, 2500]))
13362 // set x to a time scale to generate histogram
13363 chart.x(d3.time.scale().domain([new Date(1985, 0, 1), new Date(2012, 11, 31)]))
13364 ```
13365
13366 **/
13367 _chart.x = function (_) {
13368 if (!arguments.length) {
13369 return _x;
13370 }
13371 _x = _;
13372 _xOriginalDomain = _x.domain();
13373 return _chart;
13374 };
13375
13376 _chart.xOriginalDomain = function () {
13377 return _xOriginalDomain;
13378 };
13379
13380 /**
13381 #### .xUnits([xUnits function])
13382 Set or get the xUnits function. The coordinate grid chart uses the xUnits function to calculate
13383 the number of data projections on x axis such as the number of bars for a bar chart or the
13384 number of dots for a line chart. This function is expected to return a Javascript array of all
13385 data points on x axis, or the number of points on the axis. [d3 time range functions
13386 d3.time.days, d3.time.months, and
13387 d3.time.years](https://github.com/mbostock/d3/wiki/Time-Intervals#aliases) are all valid xUnits
13388 function. dc.js also provides a few units function, see the [Utilities](#utilities) section for
13389 a list of built-in units functions. The default xUnits function is dc.units.integers.
13390 ```js
13391 // set x units to count days
13392 chart.xUnits(d3.time.days);
13393 // set x units to count months
13394 chart.xUnits(d3.time.months);
13395 ```
13396 A custom xUnits function can be used as long as it follows the following interface:
13397 ```js
13398 // units in integer
13399 function(start, end, xDomain) {
13400 // simply calculates how many integers in the domain
13401 return Math.abs(end - start);
13402 };
13403
13404 // fixed units
13405 function(start, end, xDomain) {
13406 // be aware using fixed units will disable the focus/zoom ability on the chart
13407 return 1000;
13408 };
13409 ```
13410
13411 **/
13412 _chart.xUnits = function (_) {
13413 if (!arguments.length) {
13414 return _xUnits;
13415 }
13416 _xUnits = _;
13417 return _chart;
13418 };
13419
13420 /**
13421 #### .xAxis([xAxis])
13422 Set or get the x axis used by a particular coordinate grid chart instance. This function is most
13423 useful when x axis customization is required. The x axis in dc.js is an instance of a [d3
13424 axis object](https://github.com/mbostock/d3/wiki/SVG-Axes#wiki-axis); therefore it supports any
13425 valid d3 axis manipulation. **Caution**: The x axis is usually generated internally by dc;
13426 resetting it may cause unexpected results.
13427 ```js
13428 // customize x axis tick format
13429 chart.xAxis().tickFormat(function(v) {return v + '%';});
13430 // customize x axis tick values
13431 chart.xAxis().tickValues([0, 100, 200, 300]);
13432 ```
13433
13434 **/
13435 _chart.xAxis = function (_) {
13436 if (!arguments.length) {
13437 return _xAxis;
13438 }
13439 _xAxis = _;
13440 return _chart;
13441 };
13442
13443 /**
13444 #### .elasticX([boolean])
13445 Turn on/off elastic x axis behavior. If x axis elasticity is turned on, then the grid chart will
13446 attempt to recalculate the x axis range whenever a redraw event is triggered.
13447
13448 **/
13449 _chart.elasticX = function (_) {
13450 if (!arguments.length) {
13451 return _xElasticity;
13452 }
13453 _xElasticity = _;
13454 return _chart;
13455 };
13456
13457 /**
13458 #### .xAxisPadding([padding])
13459 Set or get x axis padding for the elastic x axis. The padding will be added to both end of the x
13460 axis if elasticX is turned on; otherwise it is ignored.
13461
13462 * padding can be an integer or percentage in string (e.g. '10%'). Padding can be applied to
13463 number or date x axes. When padding a date axis, an integer represents number of days being padded
13464 and a percentage string will be treated the same as an integer.
13465
13466 **/
13467 _chart.xAxisPadding = function (_) {
13468 if (!arguments.length) {
13469 return _xAxisPadding;
13470 }
13471 _xAxisPadding = _;
13472 return _chart;
13473 };
13474
13475 /**
13476 #### .xUnitCount()
13477 Returns the number of units displayed on the x axis using the unit measure configured by
13478 .xUnits.
13479 **/
13480 _chart.xUnitCount = function () {
13481 if (_unitCount === undefined) {
13482 var units = _chart.xUnits()(_chart.x().domain()[0], _chart.x().domain()[1], _chart.x().domain());
13483
13484 if (units instanceof Array) {
13485 _unitCount = units.length;
13486 } else {
13487 _unitCount = units;
13488 }
13489 }
13490
13491 return _unitCount;
13492 };
13493 /**
13494 #### .useRightYAxis()
13495 Gets or sets whether the chart should be drawn with a right axis instead of a left axis. When
13496 used with a chart in a composite chart, allows both left and right Y axes to be shown on a
13497 chart.
13498 **/
13499
13500 _chart.useRightYAxis = function (_) {
13501 if (!arguments.length) {
13502 return _useRightYAxis;
13503 }
13504 _useRightYAxis = _;
13505 return _chart;
13506 };
13507
13508 /**
13509 #### isOrdinal()
13510 Returns true if the chart is using ordinal xUnits ([dc.units.ordinal](#dcunitsordinal)), or false
13511 otherwise. Most charts behave differently with ordinal data and use the result of this method to
13512 trigger the appropriate logic.
13513 **/
13514 _chart.isOrdinal = function () {
13515 return _chart.xUnits() === dc.units.ordinal;
13516 };
13517
13518 _chart._useOuterPadding = function () {
13519 return true;
13520 };
13521
13522 _chart._ordinalXDomain = function () {
13523 var groups = _chart._computeOrderedGroups(_chart.data());
13524 return groups.map(_chart.keyAccessor());
13525 };
13526
13527 function prepareXAxis(g) {
13528 if (!_chart.isOrdinal()) {
13529 if (_chart.elasticX()) {
13530 _x.domain([_chart.xAxisMin(), _chart.xAxisMax()]);
13531 }
13532 }
13533 else { // _chart.isOrdinal()
13534 if (_chart.elasticX() || _x.domain().length === 0) {
13535 _x.domain(_chart._ordinalXDomain());
13536 }
13537 }
13538
13539 // has the domain changed?
13540 var xdom = _x.domain();
13541 if (!_lastXDomain || xdom.some(function (elem, i) { return elem !== _lastXDomain[i]; })) {
13542 _chart.rescale();
13543 }
13544 _lastXDomain = xdom;
13545
13546 // please can't we always use rangeBands for bar charts?
13547 if (_chart.isOrdinal()) {
13548 _x.rangeBands([0, _chart.xAxisLength()], _rangeBandPadding,
13549 _chart._useOuterPadding() ? _outerRangeBandPadding : 0);
13550 } else {
13551 _x.range([0, _chart.xAxisLength()]);
13552 }
13553
13554 _xAxis = _xAxis.scale(_chart.x());
13555
13556 renderVerticalGridLines(g);
13557 }
13558
13559 _chart.renderXAxis = function (g) {
13560 var axisXG = g.selectAll('g.x');
13561
13562 if (axisXG.empty()) {
13563 axisXG = g.append('g')
13564 .attr('class', 'axis x')
13565 .attr('transform', 'translate(' + _chart.margins().left + ',' + _chart._xAxisY() + ')');
13566 }
13567
13568 var axisXLab = g.selectAll('text.' + X_AXIS_LABEL_CLASS);
13569 if (axisXLab.empty() && _chart.xAxisLabel()) {
13570 axisXLab = g.append('text')
13571 .attr('transform', 'translate(' + (_chart.margins().left + _chart.xAxisLength() / 2) + ',' +
13572 (_chart.height() - _xAxisLabelPadding) + ')')
13573 .attr('class', X_AXIS_LABEL_CLASS)
13574 .attr('text-anchor', 'middle')
13575 .text(_chart.xAxisLabel());
13576 }
13577 if (_chart.xAxisLabel() && axisXLab.text() !== _chart.xAxisLabel()) {
13578 axisXLab.text(_chart.xAxisLabel());
13579 }
13580
13581 dc.transition(axisXG, _chart.transitionDuration())
13582 .call(_xAxis);
13583 };
13584
13585 function renderVerticalGridLines(g) {
13586 var gridLineG = g.selectAll('g.' + VERTICAL_CLASS);
13587
13588 if (_renderVerticalGridLine) {
13589 if (gridLineG.empty()) {
13590 gridLineG = g.insert('g', ':first-child')
13591 .attr('class', GRID_LINE_CLASS + ' ' + VERTICAL_CLASS)
13592 .attr('transform', 'translate(' + _chart.margins().left + ',' + _chart.margins().top + ')');
13593 }
13594
13595 var ticks = _xAxis.tickValues() ? _xAxis.tickValues() :
13596 (typeof _x.ticks === 'function' ? _x.ticks(_xAxis.ticks()[0]) : _x.domain());
13597
13598 var lines = gridLineG.selectAll('line')
13599 .data(ticks);
13600
13601 // enter
13602 var linesGEnter = lines.enter()
13603 .append('line')
13604 .attr('x1', function (d) {
13605 return _x(d);
13606 })
13607 .attr('y1', _chart._xAxisY() - _chart.margins().top)
13608 .attr('x2', function (d) {
13609 return _x(d);
13610 })
13611 .attr('y2', 0)
13612 .attr('opacity', 0);
13613 dc.transition(linesGEnter, _chart.transitionDuration())
13614 .attr('opacity', 1);
13615
13616 // update
13617 dc.transition(lines, _chart.transitionDuration())
13618 .attr('x1', function (d) {
13619 return _x(d);
13620 })
13621 .attr('y1', _chart._xAxisY() - _chart.margins().top)
13622 .attr('x2', function (d) {
13623 return _x(d);
13624 })
13625 .attr('y2', 0);
13626
13627 // exit
13628 lines.exit().remove();
13629 }
13630 else {
13631 gridLineG.selectAll('line').remove();
13632 }
13633 }
13634
13635 _chart._xAxisY = function () {
13636 return (_chart.height() - _chart.margins().bottom);
13637 };
13638
13639 _chart.xAxisLength = function () {
13640 return _chart.effectiveWidth();
13641 };
13642
13643 /**
13644 #### .xAxisLabel([labelText, [, padding]])
13645 Set or get the x axis label. If setting the label, you may optionally include additional padding to
13646 the margin to make room for the label. By default the padded is set to 12 to accomodate the text height.
13647 **/
13648 _chart.xAxisLabel = function (_, padding) {
13649 if (!arguments.length) {
13650 return _xAxisLabel;
13651 }
13652 _xAxisLabel = _;
13653 _chart.margins().bottom -= _xAxisLabelPadding;
13654 _xAxisLabelPadding = (padding === undefined) ? DEFAULT_AXIS_LABEL_PADDING : padding;
13655 _chart.margins().bottom += _xAxisLabelPadding;
13656 return _chart;
13657 };
13658
13659 _chart._prepareYAxis = function (g) {
13660 if (_y === undefined || _chart.elasticY()) {
13661 _y = d3.scale.linear();
13662 var min = _chart.yAxisMin() || 0,
13663 max = _chart.yAxisMax() || 0;
13664 _y.domain([min, max]).rangeRound([_chart.yAxisHeight(), 0]);
13665 }
13666
13667 _y.range([_chart.yAxisHeight(), 0]);
13668 _yAxis = _yAxis.scale(_y);
13669
13670 if (_useRightYAxis) {
13671 _yAxis.orient('right');
13672 }
13673
13674 _chart._renderHorizontalGridLinesForAxis(g, _y, _yAxis);
13675 };
13676
13677 _chart.renderYAxisLabel = function (axisClass, text, rotation, labelXPosition) {
13678 labelXPosition = labelXPosition || _yAxisLabelPadding;
13679
13680 var axisYLab = _chart.g().selectAll('text.' + Y_AXIS_LABEL_CLASS + '.' + axisClass + '-label');
13681 if (axisYLab.empty() && text) {
13682
13683 var labelYPosition = (_chart.margins().top + _chart.yAxisHeight() / 2);
13684 axisYLab = _chart.g().append('text')
13685 .attr('transform', 'translate(' + labelXPosition + ',' + labelYPosition + '),rotate(' + rotation + ')')
13686 .attr('class', Y_AXIS_LABEL_CLASS + ' ' + axisClass + '-label')
13687 .attr('text-anchor', 'middle')
13688 .text(text);
13689 }
13690 if (text && axisYLab.text() !== text) {
13691 axisYLab.text(text);
13692 }
13693 };
13694
13695 _chart.renderYAxisAt = function (axisClass, axis, position) {
13696 var axisYG = _chart.g().selectAll('g.' + axisClass);
13697 if (axisYG.empty()) {
13698 axisYG = _chart.g().append('g')
13699 .attr('class', 'axis ' + axisClass)
13700 .attr('transform', 'translate(' + position + ',' + _chart.margins().top + ')');
13701 }
13702
13703 dc.transition(axisYG, _chart.transitionDuration()).call(axis);
13704 };
13705
13706 _chart.renderYAxis = function () {
13707 var axisPosition = _useRightYAxis ? (_chart.width() - _chart.margins().right) : _chart._yAxisX();
13708 _chart.renderYAxisAt('y', _yAxis, axisPosition);
13709 var labelPosition = _useRightYAxis ? (_chart.width() - _yAxisLabelPadding) : _yAxisLabelPadding;
13710 var rotation = _useRightYAxis ? 90 : -90;
13711 _chart.renderYAxisLabel('y', _chart.yAxisLabel(), rotation, labelPosition);
13712 };
13713
13714 _chart._renderHorizontalGridLinesForAxis = function (g, scale, axis) {
13715 var gridLineG = g.selectAll('g.' + HORIZONTAL_CLASS);
13716
13717 if (_renderHorizontalGridLine) {
13718 var ticks = axis.tickValues() ? axis.tickValues() : scale.ticks(axis.ticks()[0]);
13719
13720 if (gridLineG.empty()) {
13721 gridLineG = g.insert('g', ':first-child')
13722 .attr('class', GRID_LINE_CLASS + ' ' + HORIZONTAL_CLASS)
13723 .attr('transform', 'translate(' + _chart.margins().left + ',' + _chart.margins().top + ')');
13724 }
13725
13726 var lines = gridLineG.selectAll('line')
13727 .data(ticks);
13728
13729 // enter
13730 var linesGEnter = lines.enter()
13731 .append('line')
13732 .attr('x1', 1)
13733 .attr('y1', function (d) {
13734 return scale(d);
13735 })
13736 .attr('x2', _chart.xAxisLength())
13737 .attr('y2', function (d) {
13738 return scale(d);
13739 })
13740 .attr('opacity', 0);
13741 dc.transition(linesGEnter, _chart.transitionDuration())
13742 .attr('opacity', 1);
13743
13744 // update
13745 dc.transition(lines, _chart.transitionDuration())
13746 .attr('x1', 1)
13747 .attr('y1', function (d) {
13748 return scale(d);
13749 })
13750 .attr('x2', _chart.xAxisLength())
13751 .attr('y2', function (d) {
13752 return scale(d);
13753 });
13754
13755 // exit
13756 lines.exit().remove();
13757 }
13758 else {
13759 gridLineG.selectAll('line').remove();
13760 }
13761 };
13762
13763 _chart._yAxisX = function () {
13764 return _chart.useRightYAxis() ? _chart.width() - _chart.margins().right : _chart.margins().left;
13765 };
13766
13767 /**
13768 #### .yAxisLabel([labelText, [, padding]])
13769 Set or get the y axis label. If setting the label, you may optionally include additional padding
13770 to the margin to make room for the label. By default the padded is set to 12 to accomodate the
13771 text height.
13772 **/
13773 _chart.yAxisLabel = function (_, padding) {
13774 if (!arguments.length) {
13775 return _yAxisLabel;
13776 }
13777 _yAxisLabel = _;
13778 _chart.margins().left -= _yAxisLabelPadding;
13779 _yAxisLabelPadding = (padding === undefined) ? DEFAULT_AXIS_LABEL_PADDING : padding;
13780 _chart.margins().left += _yAxisLabelPadding;
13781 return _chart;
13782 };
13783
13784 /**
13785 #### .y([yScale])
13786 Get or set the y scale. The y scale is typically automatically determined by the chart implementation.
13787
13788 **/
13789 _chart.y = function (_) {
13790 if (!arguments.length) {
13791 return _y;
13792 }
13793 _y = _;
13794 return _chart;
13795 };
13796
13797 /**
13798 #### .yAxis([yAxis])
13799 Set or get the y axis used by the coordinate grid chart instance. This function is most useful
13800 when y axis customization is required. The y axis in dc.js is simply an instance of a [d3 axis
13801 object](https://github.com/mbostock/d3/wiki/SVG-Axes#wiki-_axis); therefore it supports any
13802 valid d3 axis manipulation. **Caution**: The y axis is usually generated internally by dc;
13803 resetting it may cause unexpected results.
13804 ```js
13805 // customize y axis tick format
13806 chart.yAxis().tickFormat(function(v) {return v + '%';});
13807 // customize y axis tick values
13808 chart.yAxis().tickValues([0, 100, 200, 300]);
13809 ```
13810
13811 **/
13812 _chart.yAxis = function (y) {
13813 if (!arguments.length) {
13814 return _yAxis;
13815 }
13816 _yAxis = y;
13817 return _chart;
13818 };
13819
13820 /**
13821 #### .elasticY([boolean])
13822 Turn on/off elastic y axis behavior. If y axis elasticity is turned on, then the grid chart will
13823 attempt to recalculate the y axis range whenever a redraw event is triggered.
13824
13825 **/
13826 _chart.elasticY = function (_) {
13827 if (!arguments.length) {
13828 return _yElasticity;
13829 }
13830 _yElasticity = _;
13831 return _chart;
13832 };
13833
13834 /**
13835 #### .renderHorizontalGridLines([boolean])
13836 Turn on/off horizontal grid lines.
13837
13838 **/
13839 _chart.renderHorizontalGridLines = function (_) {
13840 if (!arguments.length) {
13841 return _renderHorizontalGridLine;
13842 }
13843 _renderHorizontalGridLine = _;
13844 return _chart;
13845 };
13846
13847 /**
13848 #### .renderVerticalGridLines([boolean])
13849 Turn on/off vertical grid lines.
13850
13851 **/
13852 _chart.renderVerticalGridLines = function (_) {
13853 if (!arguments.length) {
13854 return _renderVerticalGridLine;
13855 }
13856 _renderVerticalGridLine = _;
13857 return _chart;
13858 };
13859
13860 /**
13861 #### .xAxisMin()
13862 Calculates the minimum x value to display in the chart. Includes xAxisPadding if set.
13863 **/
13864 _chart.xAxisMin = function () {
13865 var min = d3.min(_chart.data(), function (e) {
13866 return _chart.keyAccessor()(e);
13867 });
13868 return dc.utils.subtract(min, _xAxisPadding);
13869 };
13870
13871 /**
13872 #### .xAxisMax()
13873 Calculates the maximum x value to display in the chart. Includes xAxisPadding if set.
13874 **/
13875 _chart.xAxisMax = function () {
13876 var max = d3.max(_chart.data(), function (e) {
13877 return _chart.keyAccessor()(e);
13878 });
13879 return dc.utils.add(max, _xAxisPadding);
13880 };
13881
13882 /**
13883 #### .yAxisMin()
13884 Calculates the minimum y value to display in the chart. Includes yAxisPadding if set.
13885 **/
13886 _chart.yAxisMin = function () {
13887 var min = d3.min(_chart.data(), function (e) {
13888 return _chart.valueAccessor()(e);
13889 });
13890 return dc.utils.subtract(min, _yAxisPadding);
13891 };
13892
13893 /**
13894 #### .yAxisMax()
13895 Calculates the maximum y value to display in the chart. Includes yAxisPadding if set.
13896 **/
13897 _chart.yAxisMax = function () {
13898 var max = d3.max(_chart.data(), function (e) {
13899 return _chart.valueAccessor()(e);
13900 });
13901 return dc.utils.add(max, _yAxisPadding);
13902 };
13903
13904 /**
13905 #### .yAxisPadding([padding])
13906 Set or get y axis padding for the elastic y axis. The padding will be added to the top of the y
13907 axis if elasticY is turned on; otherwise it is ignored.
13908
13909 * padding can be an integer or percentage in string (e.g. '10%'). Padding can be applied to
13910 number or date axes. When padding a date axis, an integer represents number of days being padded
13911 and a percentage string will be treated the same as an integer.
13912
13913 **/
13914 _chart.yAxisPadding = function (_) {
13915 if (!arguments.length) {
13916 return _yAxisPadding;
13917 }
13918 _yAxisPadding = _;
13919 return _chart;
13920 };
13921
13922 _chart.yAxisHeight = function () {
13923 return _chart.effectiveHeight();
13924 };
13925
13926 /**
13927 #### .round([rounding function])
13928 Set or get the rounding function used to quantize the selection when brushing is enabled.
13929 ```js
13930 // set x unit round to by month, this will make sure range selection brush will
13931 // select whole months
13932 chart.round(d3.time.month.round);
13933 ```
13934
13935 **/
13936 _chart.round = function (_) {
13937 if (!arguments.length) {
13938 return _round;
13939 }
13940 _round = _;
13941 return _chart;
13942 };
13943
13944 _chart._rangeBandPadding = function (_) {
13945 if (!arguments.length) {
13946 return _rangeBandPadding;
13947 }
13948 _rangeBandPadding = _;
13949 return _chart;
13950 };
13951
13952 _chart._outerRangeBandPadding = function (_) {
13953 if (!arguments.length) {
13954 return _outerRangeBandPadding;
13955 }
13956 _outerRangeBandPadding = _;
13957 return _chart;
13958 };
13959
13960 dc.override(_chart, 'filter', function (_) {
13961 if (!arguments.length) {
13962 return _chart._filter();
13963 }
13964
13965 _chart._filter(_);
13966
13967 if (_) {
13968 _chart.brush().extent(_);
13969 } else {
13970 _chart.brush().clear();
13971 }
13972
13973 return _chart;
13974 });
13975
13976 _chart.brush = function (_) {
13977 if (!arguments.length) {
13978 return _brush;
13979 }
13980 _brush = _;
13981 return _chart;
13982 };
13983
13984 function brushHeight() {
13985 return _chart._xAxisY() - _chart.margins().top;
13986 }
13987
13988 _chart.renderBrush = function (g) {
13989 if (_brushOn) {
13990 _brush.on('brush', _chart._brushing);
13991 _brush.on('brushstart', _chart._disableMouseZoom);
13992 _brush.on('brushend', configureMouseZoom);
13993
13994 var gBrush = g.append('g')
13995 .attr('class', 'brush')
13996 .attr('transform', 'translate(' + _chart.margins().left + ',' + _chart.margins().top + ')')
13997 .call(_brush.x(_chart.x()));
13998 _chart.setBrushY(gBrush);
13999 _chart.setHandlePaths(gBrush);
14000
14001 if (_chart.hasFilter()) {
14002 _chart.redrawBrush(g);
14003 }
14004 }
14005 };
14006
14007 _chart.setHandlePaths = function (gBrush) {
14008 gBrush.selectAll('.resize').append('path').attr('d', _chart.resizeHandlePath);
14009 };
14010
14011 _chart.setBrushY = function (gBrush) {
14012 gBrush.selectAll('rect').attr('height', brushHeight());
14013 };
14014
14015 _chart.extendBrush = function () {
14016 var extent = _brush.extent();
14017 if (_chart.round()) {
14018 extent[0] = extent.map(_chart.round())[0];
14019 extent[1] = extent.map(_chart.round())[1];
14020
14021 _g.select('.brush')
14022 .call(_brush.extent(extent));
14023 }
14024 return extent;
14025 };
14026
14027 _chart.brushIsEmpty = function (extent) {
14028 return _brush.empty() || !extent || extent[1] <= extent[0];
14029 };
14030
14031 _chart._brushing = function () {
14032 var extent = _chart.extendBrush();
14033
14034 _chart.redrawBrush(_g);
14035
14036 if (_chart.brushIsEmpty(extent)) {
14037 dc.events.trigger(function () {
14038 _chart.filter(null);
14039 _chart.redrawGroup();
14040 }, dc.constants.EVENT_DELAY);
14041 } else {
14042 var rangedFilter = dc.filters.RangedFilter(extent[0], extent[1]);
14043
14044 dc.events.trigger(function () {
14045 _chart.replaceFilter(rangedFilter);
14046 _chart.redrawGroup();
14047 }, dc.constants.EVENT_DELAY);
14048 }
14049 };
14050
14051 _chart.redrawBrush = function (g) {
14052 if (_brushOn) {
14053 if (_chart.filter() && _chart.brush().empty()) {
14054 _chart.brush().extent(_chart.filter());
14055 }
14056
14057 var gBrush = g.select('g.brush');
14058 gBrush.call(_chart.brush().x(_chart.x()));
14059 _chart.setBrushY(gBrush);
14060 }
14061
14062 _chart.fadeDeselectedArea();
14063 };
14064
14065 _chart.fadeDeselectedArea = function () {
14066 // do nothing, sub-chart should override this function
14067 };
14068
14069 // borrowed from Crossfilter example
14070 _chart.resizeHandlePath = function (d) {
14071 var e = +(d === 'e'), x = e ? 1 : -1, y = brushHeight() / 3;
14072 /*jshint -W014 */
14073 return 'M' + (0.5 * x) + ',' + y
14074 + 'A6,6 0 0 ' + e + ' ' + (6.5 * x) + ',' + (y + 6)
14075 + 'V' + (2 * y - 6)
14076 + 'A6,6 0 0 ' + e + ' ' + (0.5 * x) + ',' + (2 * y)
14077 + 'Z'
14078 + 'M' + (2.5 * x) + ',' + (y + 8)
14079 + 'V' + (2 * y - 8)
14080 + 'M' + (4.5 * x) + ',' + (y + 8)
14081 + 'V' + (2 * y - 8);
14082 /*jshint +W014 */
14083 };
14084
14085 function getClipPathId() {
14086 return _chart.anchorName().replace(/[ .#]/g, '-') + '-clip';
14087 }
14088
14089 /**
14090 #### .clipPadding([padding])
14091 Get or set the padding in pixels for the clip path. Once set padding will be applied evenly to
14092 the top, left, right, and bottom when the clip path is generated. If set to zero, the clip area
14093 will be exactly the chart body area minus the margins. Default: 5
14094
14095 **/
14096 _chart.clipPadding = function (p) {
14097 if (!arguments.length) {
14098 return _clipPadding;
14099 }
14100 _clipPadding = p;
14101 return _chart;
14102 };
14103
14104 function generateClipPath() {
14105 var defs = dc.utils.appendOrSelect(_parent, 'defs');
14106 // cannot select <clippath> elements; bug in WebKit, must select by id
14107 // https://groups.google.com/forum/#!topic/d3-js/6EpAzQ2gU9I
14108 var id = getClipPathId();
14109 var chartBodyClip = dc.utils.appendOrSelect(defs, '#' + id, 'clipPath').attr('id', id);
14110
14111 var padding = _clipPadding * 2;
14112
14113 dc.utils.appendOrSelect(chartBodyClip, 'rect')
14114 .attr('width', _chart.xAxisLength() + padding)
14115 .attr('height', _chart.yAxisHeight() + padding)
14116 .attr('transform', 'translate(-' + _clipPadding + ', -' + _clipPadding + ')');
14117 }
14118
14119 _chart._preprocessData = function () {};
14120
14121 _chart._doRender = function () {
14122 _chart.resetSvg();
14123
14124 _chart._preprocessData();
14125
14126 _chart._generateG();
14127 generateClipPath();
14128
14129 drawChart(true);
14130
14131 configureMouseZoom();
14132
14133 return _chart;
14134 };
14135
14136 _chart._doRedraw = function () {
14137 _chart._preprocessData();
14138
14139 drawChart(false);
14140 generateClipPath();
14141
14142 return _chart;
14143 };
14144
14145 function drawChart (render) {
14146 if (_chart.isOrdinal()) {
14147 _brushOn = false;
14148 }
14149
14150 prepareXAxis(_chart.g());
14151 _chart._prepareYAxis(_chart.g());
14152
14153 _chart.plotData();
14154
14155 if (_chart.elasticX() || _refocused || render) {
14156 _chart.renderXAxis(_chart.g());
14157 }
14158
14159 if (_chart.elasticY() || render) {
14160 _chart.renderYAxis(_chart.g());
14161 }
14162
14163 if (render) {
14164 _chart.renderBrush(_chart.g());
14165 } else {
14166 _chart.redrawBrush(_chart.g());
14167 }
14168 }
14169
14170 function configureMouseZoom () {
14171 if (_mouseZoomable) {
14172 _chart._enableMouseZoom();
14173 }
14174 else if (_hasBeenMouseZoomable) {
14175 _chart._disableMouseZoom();
14176 }
14177 }
14178
14179 _chart._enableMouseZoom = function () {
14180 _hasBeenMouseZoomable = true;
14181 _zoom.x(_chart.x())
14182 .scaleExtent(_zoomScale)
14183 .size([_chart.width(), _chart.height()])
14184 .duration(_chart.transitionDuration());
14185 _chart.root().call(_zoom);
14186 };
14187
14188 _chart._disableMouseZoom = function () {
14189 _chart.root().call(_nullZoom);
14190 };
14191
14192 function constrainRange(range, constraint) {
14193 var constrainedRange = [];
14194 constrainedRange[0] = d3.max([range[0], constraint[0]]);
14195 constrainedRange[1] = d3.min([range[1], constraint[1]]);
14196 return constrainedRange;
14197 }
14198
14199 /**
14200 #### .focus([range])
14201 Zoom this chart to focus on the given range. The given range should be an array containing only
14202 2 elements (`[start, end]`) defining a range in the x domain. If the range is not given or set
14203 to null, then the zoom will be reset. _For focus to work elasticX has to be turned off;
14204 otherwise focus will be ignored._
14205 ```js
14206 chart.renderlet(function(chart){
14207 // smooth the rendering through event throttling
14208 dc.events.trigger(function(){
14209 // focus some other chart to the range selected by user on this chart
14210 someOtherChart.focus(chart.filter());
14211 });
14212 })
14213 ```
14214
14215 **/
14216 _chart.focus = function (range) {
14217 if (hasRangeSelected(range)) {
14218 _chart.x().domain(range);
14219 } else {
14220 _chart.x().domain(_xOriginalDomain);
14221 }
14222
14223 _zoom.x(_chart.x());
14224 zoomHandler();
14225 };
14226
14227 _chart.refocused = function () {
14228 return _refocused;
14229 };
14230
14231 _chart.focusChart = function (c) {
14232 if (!arguments.length) {
14233 return _focusChart;
14234 }
14235 _focusChart = c;
14236 _chart.on('filtered', function (chart) {
14237 if (!chart.filter()) {
14238 dc.events.trigger(function () {
14239 _focusChart.x().domain(_focusChart.xOriginalDomain());
14240 });
14241 } else if (!rangesEqual(chart.filter(), _focusChart.filter())) {
14242 dc.events.trigger(function () {
14243 _focusChart.focus(chart.filter());
14244 });
14245 }
14246 });
14247 return _chart;
14248 };
14249
14250 function rangesEqual(range1, range2) {
14251 if (!range1 && !range2) {
14252 return true;
14253 }
14254 else if (!range1 || !range2) {
14255 return false;
14256 }
14257 else if (range1.length === 0 && range2.length === 0) {
14258 return true;
14259 }
14260 else if (range1[0].valueOf() === range2[0].valueOf() &&
14261 range1[1].valueOf() === range2[1].valueOf()) {
14262 return true;
14263 }
14264 return false;
14265 }
14266
14267 /**
14268 #### .brushOn([boolean])
14269 Turn on/off the brush-based range filter. When brushing is on then user can drag the mouse
14270 across a chart with a quantitative scale to perform range filtering based on the extent of the
14271 brush, or click on the bars of an ordinal bar chart or slices of a pie chart to filter and
14272 unfilter them. However turning on the brush filter will disable other interactive elements on
14273 the chart such as highlighting, tool tips, and reference lines. Zooming will still be possible
14274 if enabled, but only via scrolling (panning will be disabled.) Default: true
14275
14276 **/
14277 _chart.brushOn = function (_) {
14278 if (!arguments.length) {
14279 return _brushOn;
14280 }
14281 _brushOn = _;
14282 return _chart;
14283 };
14284
14285 function hasRangeSelected(range) {
14286 return range instanceof Array && range.length > 1;
14287 }
14288
14289 return _chart;
14290 };
14291
14292 /**
14293 ## Stack Mixin
14294 Stack Mixin is an mixin that provides cross-chart support of stackability using d3.layout.stack.
14295
14296 **/
14297 dc.stackMixin = function (_chart) {
14298
14299 function prepareValues (layer, layerIdx) {
14300 var valAccessor = layer.accessor || _chart.valueAccessor();
14301 layer.name = String(layer.name || layerIdx);
14302 layer.values = layer.group.all().map(function (d, i) {
14303 return {
14304 x: _chart.keyAccessor()(d, i),
14305 y: layer.hidden ? null : valAccessor(d, i),
14306 data: d,
14307 layer: layer.name,
14308 hidden: layer.hidden
14309 };
14310 });
14311
14312 layer.values = layer.values.filter(domainFilter());
14313 return layer.values;
14314 }
14315
14316 var _stackLayout = d3.layout.stack()
14317 .values(prepareValues);
14318
14319 var _stack = [];
14320 var _titles = {};
14321
14322 var _hidableStacks = false;
14323
14324 function domainFilter() {
14325 if (!_chart.x()) {
14326 return d3.functor(true);
14327 }
14328 var xDomain = _chart.x().domain();
14329 if (_chart.isOrdinal()) {
14330 // TODO #416
14331 //var domainSet = d3.set(xDomain);
14332 return function () {
14333 return true; //domainSet.has(p.x);
14334 };
14335 }
14336 if (_chart.elasticX()) {
14337 return function () { return true; };
14338 }
14339 return function (p) {
14340 //return true;
14341 return p.x >= xDomain[0] && p.x <= xDomain[xDomain.length - 1];
14342 };
14343 }
14344
14345 /**
14346 #### .stack(group[, name, accessor])
14347 Stack a new crossfilter group onto this chart with an optional custom value accessor. All stacks
14348 in the same chart will share the same key accessor and therefore the same set of keys.
14349
14350 For example, in a stacked bar chart, the bars of each stack will be positioned using the same set
14351 of keys on the x axis, while stacked vertically. If name is specified then it will be used to
14352 generate the legend label.
14353 ```js
14354 // stack group using default accessor
14355 chart.stack(valueSumGroup)
14356 // stack group using custom accessor
14357 .stack(avgByDayGroup, function(d){return d.value.avgByDay;});
14358 ```
14359
14360 **/
14361 _chart.stack = function (group, name, accessor) {
14362 if (!arguments.length) {
14363 return _stack;
14364 }
14365
14366 if (arguments.length <= 2) {
14367 accessor = name;
14368 }
14369
14370 var layer = {group:group};
14371 if (typeof name === 'string') {
14372 layer.name = name;
14373 }
14374 if (typeof accessor === 'function') {
14375 layer.accessor = accessor;
14376 }
14377 _stack.push(layer);
14378
14379 return _chart;
14380 };
14381
14382 dc.override(_chart, 'group', function (g, n, f) {
14383 if (!arguments.length) {
14384 return _chart._group();
14385 }
14386 _stack = [];
14387 _titles = {};
14388 _chart.stack(g, n);
14389 if (f) {
14390 _chart.valueAccessor(f);
14391 }
14392 return _chart._group(g, n);
14393 });
14394
14395 /**
14396 #### .hidableStacks([boolean])
14397 Allow named stacks to be hidden or shown by clicking on legend items.
14398 This does not affect the behavior of hideStack or showStack.
14399
14400 **/
14401 _chart.hidableStacks = function (_) {
14402 if (!arguments.length) {
14403 return _hidableStacks;
14404 }
14405 _hidableStacks = _;
14406 return _chart;
14407 };
14408
14409 function findLayerByName(n) {
14410 var i = _stack.map(dc.pluck('name')).indexOf(n);
14411 return _stack[i];
14412 }
14413
14414 /**
14415 #### .hideStack(name)
14416 Hide all stacks on the chart with the given name.
14417 The chart must be re-rendered for this change to appear.
14418
14419 **/
14420 _chart.hideStack = function (stackName) {
14421 var layer = findLayerByName(stackName);
14422 if (layer) {
14423 layer.hidden = true;
14424 }
14425 return _chart;
14426 };
14427
14428 /**
14429 #### .showStack(name)
14430 Show all stacks on the chart with the given name.
14431 The chart must be re-rendered for this change to appear.
14432
14433 **/
14434 _chart.showStack = function (stackName) {
14435 var layer = findLayerByName(stackName);
14436 if (layer) {
14437 layer.hidden = false;
14438 }
14439 return _chart;
14440 };
14441
14442 _chart.getValueAccessorByIndex = function (index) {
14443 return _stack[index].accessor || _chart.valueAccessor();
14444 };
14445
14446 _chart.yAxisMin = function () {
14447 var min = d3.min(flattenStack(), function (p) {
14448 return (p.y + p.y0 < p.y0) ? (p.y + p.y0) : p.y0;
14449 });
14450
14451 return dc.utils.subtract(min, _chart.yAxisPadding());
14452
14453 };
14454
14455 _chart.yAxisMax = function () {
14456 var max = d3.max(flattenStack(), function (p) {
14457 return p.y + p.y0;
14458 });
14459
14460 return dc.utils.add(max, _chart.yAxisPadding());
14461 };
14462
14463 function flattenStack() {
14464 return _chart.data().reduce(function (all, layer) {
14465 return all.concat(layer.values);
14466 }, []);
14467 }
14468
14469 _chart.xAxisMin = function () {
14470 var min = d3.min(flattenStack(), dc.pluck('x'));
14471 return dc.utils.subtract(min, _chart.xAxisPadding());
14472 };
14473
14474 _chart.xAxisMax = function () {
14475 var max = d3.max(flattenStack(), dc.pluck('x'));
14476 return dc.utils.add(max, _chart.xAxisPadding());
14477 };
14478
14479 /**
14480 #### .title([stackName], [titleFunction])
14481 Set or get the title function. Chart class will use this function to render svg title (usually interpreted by
14482 browser as tooltips) for each child element in the chart, i.e. a slice in a pie chart or a bubble in a bubble chart.
14483 Almost every chart supports title function however in grid coordinate chart you need to turn off brush in order to
14484 use title otherwise the brush layer will block tooltip trigger.
14485
14486 If the first argument is a stack name, the title function will get or set the title for that stack. If stackName
14487 is not provided, the first stack is implied.
14488 ```js
14489 // set a title function on 'first stack'
14490 chart.title('first stack', function(d) { return d.key + ': ' + d.value; });
14491 // get a title function from 'second stack'
14492 var secondTitleFunction = chart.title('second stack');
14493 );
14494 ```
14495 **/
14496 dc.override(_chart, 'title', function (stackName, titleAccessor) {
14497 if (!stackName) {
14498 return _chart._title();
14499 }
14500
14501 if (typeof stackName === 'function') {
14502 return _chart._title(stackName);
14503 }
14504 if (stackName === _chart._groupName && typeof titleAccessor === 'function') {
14505 return _chart._title(titleAccessor);
14506 }
14507
14508 if (typeof titleAccessor !== 'function') {
14509 return _titles[stackName] || _chart._title();
14510 }
14511
14512 _titles[stackName] = titleAccessor;
14513
14514 return _chart;
14515 });
14516
14517 /**
14518 #### .stackLayout([layout])
14519 Gets or sets the stack layout algorithm, which computes a baseline for each stack and
14520 propagates it to the next. The default is
14521 [d3.layout.stack](https://github.com/mbostock/d3/wiki/Stack-Layout#stack).
14522 **/
14523 _chart.stackLayout = function (stack) {
14524 if (!arguments.length) {
14525 return _stackLayout;
14526 }
14527 _stackLayout = stack;
14528 return _chart;
14529 };
14530
14531 function visability(l) {
14532 return !l.hidden;
14533 }
14534
14535 _chart.data(function () {
14536 var layers = _stack.filter(visability);
14537 return layers.length ? _chart.stackLayout()(layers) : [];
14538 });
14539
14540 _chart._ordinalXDomain = function () {
14541 return flattenStack().map(dc.pluck('x'));
14542 };
14543
14544 _chart.colorAccessor(function (d) {
14545 var layer = this.layer || this.name || d.name || d.layer;
14546 return layer;
14547 });
14548
14549 _chart.legendables = function () {
14550 return _stack.map(function (layer, i) {
14551 return {
14552 chart:_chart,
14553 name:layer.name,
14554 hidden: layer.hidden || false,
14555 color:_chart.getColor.call(layer, layer.values, i)
14556 };
14557 });
14558 };
14559
14560 _chart.isLegendableHidden = function (d) {
14561 var layer = findLayerByName(d.name);
14562 return layer ? layer.hidden : false;
14563 };
14564
14565 _chart.legendToggle = function (d) {
14566 if (_hidableStacks) {
14567 if (_chart.isLegendableHidden(d)) {
14568 _chart.showStack(d.name);
14569 } else {
14570 _chart.hideStack(d.name);
14571 }
14572 //_chart.redraw();
14573 _chart.renderGroup();
14574 }
14575 };
14576
14577 return _chart;
14578 };
14579
14580 /**
14581 ## Cap Mixin
14582 Cap is a mixin that groups small data elements below a _cap_ into an *others* grouping for both the
14583 Row and Pie Charts.
14584
14585 The top ordered elements in the group up to the cap amount will be kept in the chart, and the rest
14586 will be replaced with an *others* element, with value equal to the sum of the replaced values. The
14587 keys of the elements below the cap limit are recorded in order to filter by those keys when the
14588 *others* element is clicked.
14589
14590 **/
14591 dc.capMixin = function (_chart) {
14592
14593 var _cap = Infinity;
14594
14595 var _othersLabel = 'Others';
14596
14597 var _othersGrouper = function (topRows) {
14598 var topRowsSum = d3.sum(topRows, _chart.valueAccessor()),
14599 allRows = _chart.group().all(),
14600 allRowsSum = d3.sum(allRows, _chart.valueAccessor()),
14601 topKeys = topRows.map(_chart.keyAccessor()),
14602 allKeys = allRows.map(_chart.keyAccessor()),
14603 topSet = d3.set(topKeys),
14604 others = allKeys.filter(function (d) {return !topSet.has(d);});
14605 if (allRowsSum > topRowsSum) {
14606 return topRows.concat([{'others': others, 'key': _othersLabel, 'value': allRowsSum - topRowsSum}]);
14607 }
14608 return topRows;
14609 };
14610
14611 _chart.cappedKeyAccessor = function (d, i) {
14612 if (d.others) {
14613 return d.key;
14614 }
14615 return _chart.keyAccessor()(d, i);
14616 };
14617
14618 _chart.cappedValueAccessor = function (d, i) {
14619 if (d.others) {
14620 return d.value;
14621 }
14622 return _chart.valueAccessor()(d, i);
14623 };
14624
14625 _chart.data(function (group) {
14626 if (_cap === Infinity) {
14627 return _chart._computeOrderedGroups(group.all());
14628 } else {
14629 var topRows = group.top(_cap); // ordered by crossfilter group order (default value)
14630 topRows = _chart._computeOrderedGroups(topRows); // re-order using ordering (default key)
14631 if (_othersGrouper) {
14632 return _othersGrouper(topRows);
14633 }
14634 return topRows;
14635 }
14636 });
14637
14638 /**
14639 #### .cap([count])
14640 Get or set the count of elements to that will be included in the cap.
14641 **/
14642 _chart.cap = function (_) {
14643 if (!arguments.length) {
14644 return _cap;
14645 }
14646 _cap = _;
14647 return _chart;
14648 };
14649
14650 /**
14651 #### .othersLabel([label])
14652 Get or set the label for *Others* slice when slices cap is specified. Default label is **Others**.
14653 **/
14654 _chart.othersLabel = function (_) {
14655 if (!arguments.length) {
14656 return _othersLabel;
14657 }
14658 _othersLabel = _;
14659 return _chart;
14660 };
14661
14662 /**
14663 #### .othersGrouper([grouperFunction])
14664 Get or set the grouper function that will perform the insertion of data for the *Others* slice
14665 if the slices cap is specified. If set to a falsy value, no others will be added. By default the
14666 grouper function computes the sum of all values below the cap.
14667 ```js
14668 chart.othersGrouper(function (data) {
14669 // compute the value for others, presumably the sum of all values below the cap
14670 var othersSum = yourComputeOthersValueLogic(data)
14671
14672 // the keys are needed to properly filter when the others element is clicked
14673 var othersKeys = yourComputeOthersKeysArrayLogic(data);
14674
14675 // add the others row to the dataset
14676 data.push({'key': 'Others', 'value': othersSum, 'others': othersKeys });
14677
14678 return data;
14679 });
14680 ```
14681 **/
14682 _chart.othersGrouper = function (_) {
14683 if (!arguments.length) {
14684 return _othersGrouper;
14685 }
14686 _othersGrouper = _;
14687 return _chart;
14688 };
14689
14690 dc.override(_chart, 'onClick', function (d) {
14691 if (d.others) {
14692 _chart.filter([d.others]);
14693 }
14694 _chart._onClick(d);
14695 });
14696
14697 return _chart;
14698 };
14699
14700 /**
14701 ## Bubble Mixin
14702 Includes: [Color Mixin](#color-mixin)
14703
14704 This Mixin provides reusable functionalities for any chart that needs to visualize data using bubbles.
14705
14706 **/
14707 dc.bubbleMixin = function (_chart) {
14708 var _maxBubbleRelativeSize = 0.3;
14709 var _minRadiusWithLabel = 10;
14710
14711 _chart.BUBBLE_NODE_CLASS = 'node';
14712 _chart.BUBBLE_CLASS = 'bubble';
14713 _chart.MIN_RADIUS = 10;
14714
14715 _chart = dc.colorMixin(_chart);
14716
14717 _chart.renderLabel(true);
14718
14719 _chart.data(function (group) {
14720 return group.top(Infinity);
14721 });
14722
14723 var _r = d3.scale.linear().domain([0, 100]);
14724
14725 var _rValueAccessor = function (d) {
14726 return d.r;
14727 };
14728
14729 /**
14730 #### .r([bubbleRadiusScale])
14731 Get or set the bubble radius scale. By default the bubble chart uses
14732 `d3.scale.linear().domain([0, 100])` as its r scale .
14733
14734 **/
14735 _chart.r = function (_) {
14736 if (!arguments.length) {
14737 return _r;
14738 }
14739 _r = _;
14740 return _chart;
14741 };
14742
14743 /**
14744 #### .radiusValueAccessor([radiusValueAccessor])
14745 Get or set the radius value accessor function. If set, the radius value accessor function will
14746 be used to retrieve a data value for each bubble. The data retrieved then will be mapped using
14747 the r scale to the actual bubble radius. This allows you to encode a data dimension using bubble
14748 size.
14749
14750 **/
14751 _chart.radiusValueAccessor = function (_) {
14752 if (!arguments.length) {
14753 return _rValueAccessor;
14754 }
14755 _rValueAccessor = _;
14756 return _chart;
14757 };
14758
14759 _chart.rMin = function () {
14760 var min = d3.min(_chart.data(), function (e) {
14761 return _chart.radiusValueAccessor()(e);
14762 });
14763 return min;
14764 };
14765
14766 _chart.rMax = function () {
14767 var max = d3.max(_chart.data(), function (e) {
14768 return _chart.radiusValueAccessor()(e);
14769 });
14770 return max;
14771 };
14772
14773 _chart.bubbleR = function (d) {
14774 var value = _chart.radiusValueAccessor()(d);
14775 var r = _chart.r()(value);
14776 if (isNaN(r) || value <= 0) {
14777 r = 0;
14778 }
14779 return r;
14780 };
14781
14782 var labelFunction = function (d) {
14783 return _chart.label()(d);
14784 };
14785
14786 var labelOpacity = function (d) {
14787 return (_chart.bubbleR(d) > _minRadiusWithLabel) ? 1 : 0;
14788 };
14789
14790 _chart._doRenderLabel = function (bubbleGEnter) {
14791 if (_chart.renderLabel()) {
14792 var label = bubbleGEnter.select('text');
14793
14794 if (label.empty()) {
14795 label = bubbleGEnter.append('text')
14796 .attr('text-anchor', 'middle')
14797 .attr('dy', '.3em')
14798 .on('click', _chart.onClick);
14799 }
14800
14801 label
14802 .attr('opacity', 0)
14803 .text(labelFunction);
14804 dc.transition(label, _chart.transitionDuration())
14805 .attr('opacity', labelOpacity);
14806 }
14807 };
14808
14809 _chart.doUpdateLabels = function (bubbleGEnter) {
14810 if (_chart.renderLabel()) {
14811 var labels = bubbleGEnter.selectAll('text')
14812 .text(labelFunction);
14813 dc.transition(labels, _chart.transitionDuration())
14814 .attr('opacity', labelOpacity);
14815 }
14816 };
14817
14818 var titleFunction = function (d) {
14819 return _chart.title()(d);
14820 };
14821
14822 _chart._doRenderTitles = function (g) {
14823 if (_chart.renderTitle()) {
14824 var title = g.select('title');
14825
14826 if (title.empty()) {
14827 g.append('title').text(titleFunction);
14828 }
14829 }
14830 };
14831
14832 _chart.doUpdateTitles = function (g) {
14833 if (_chart.renderTitle()) {
14834 g.selectAll('title').text(titleFunction);
14835 }
14836 };
14837
14838 /**
14839 #### .minRadiusWithLabel([radius])
14840 Get or set the minimum radius for label rendering. If a bubble's radius is less than this value
14841 then no label will be rendered. Default: 10
14842
14843 **/
14844 _chart.minRadiusWithLabel = function (_) {
14845 if (!arguments.length) {
14846 return _minRadiusWithLabel;
14847 }
14848 _minRadiusWithLabel = _;
14849 return _chart;
14850 };
14851
14852 /**
14853 #### .maxBubbleRelativeSize([relativeSize])
14854 Get or set the maximum relative size of a bubble to the length of x axis. This value is useful
14855 when the difference in radius between bubbles is too great. Default: 0.3
14856
14857 **/
14858 _chart.maxBubbleRelativeSize = function (_) {
14859 if (!arguments.length) {
14860 return _maxBubbleRelativeSize;
14861 }
14862 _maxBubbleRelativeSize = _;
14863 return _chart;
14864 };
14865
14866 _chart.fadeDeselectedArea = function () {
14867 if (_chart.hasFilter()) {
14868 _chart.selectAll('g.' + _chart.BUBBLE_NODE_CLASS).each(function (d) {
14869 if (_chart.isSelectedNode(d)) {
14870 _chart.highlightSelected(this);
14871 } else {
14872 _chart.fadeDeselected(this);
14873 }
14874 });
14875 } else {
14876 _chart.selectAll('g.' + _chart.BUBBLE_NODE_CLASS).each(function () {
14877 _chart.resetHighlight(this);
14878 });
14879 }
14880 };
14881
14882 _chart.isSelectedNode = function (d) {
14883 return _chart.hasFilter(d.key);
14884 };
14885
14886 _chart.onClick = function (d) {
14887 var filter = d.key;
14888 dc.events.trigger(function () {
14889 _chart.filter(filter);
14890 _chart.redrawGroup();
14891 });
14892 };
14893
14894 return _chart;
14895 };
14896
14897 /**
14898 ## Pie Chart
14899 Includes: [Cap Mixin](#cap-mixin), [Color Mixin](#color-mixin), [Base Mixin](#base-mixin)
14900
14901 The pie chart implementation is usually used to visualize a small categorical distribution. The pie
14902 chart uses keyAccessor to determine the slices, and valueAccessor to calculate the size of each
14903 slice relative to the sum of all values. Slices are ordered by `.ordering` which defaults to sorting
14904 by key.
14905
14906 Examples:
14907
14908 * [Nasdaq 100 Index](http://dc-js.github.com/dc.js/)
14909 #### dc.pieChart(parent[, chartGroup])
14910 Create a pie chart instance and attaches it to the given parent element.
14911
14912 Parameters:
14913
14914 * parent : string | node | selection - any valid
14915 [d3 single selector](https://github.com/mbostock/d3/wiki/Selections#selecting-elements) specifying
14916 a dom block element such as a div; or a dom element or d3 selection.
14917
14918 * chartGroup : string (optional) - name of the chart group this chart instance should be placed in.
14919 Interaction with a chart will only trigger events and redraws within the chart's group.
14920
14921 Returns:
14922 A newly created pie chart instance
14923
14924 ```js
14925 // create a pie chart under #chart-container1 element using the default global chart group
14926 var chart1 = dc.pieChart('#chart-container1');
14927 // create a pie chart under #chart-container2 element using chart group A
14928 var chart2 = dc.pieChart('#chart-container2', 'chartGroupA');
14929 ```
14930
14931 **/
14932 dc.pieChart = function (parent, chartGroup) {
14933 var DEFAULT_MIN_ANGLE_FOR_LABEL = 0.5;
14934
14935 var _sliceCssClass = 'pie-slice';
14936 var _emptyCssClass = 'empty-chart';
14937 var _emptyTitle = 'empty';
14938
14939 var _radius,
14940 _innerRadius = 0;
14941
14942 var _g;
14943 var _cx;
14944 var _cy;
14945 var _minAngleForLabel = DEFAULT_MIN_ANGLE_FOR_LABEL;
14946 var _externalLabelRadius;
14947 var _chart = dc.capMixin(dc.colorMixin(dc.baseMixin({})));
14948
14949 _chart.colorAccessor(_chart.cappedKeyAccessor);
14950
14951 _chart.title(function (d) {
14952 return _chart.cappedKeyAccessor(d) + ': ' + _chart.cappedValueAccessor(d);
14953 });
14954
14955 /**
14956 #### .slicesCap([cap])
14957 Get or set the maximum number of slices the pie chart will generate. The top slices are determined by
14958 value from high to low. Other slices exeeding the cap will be rolled up into one single *Others* slice.
14959 The resulting data will still be sorted by .ordering (default by key).
14960
14961 **/
14962 _chart.slicesCap = _chart.cap;
14963
14964 _chart.label(_chart.cappedKeyAccessor);
14965 _chart.renderLabel(true);
14966
14967 _chart.transitionDuration(350);
14968
14969 _chart._doRender = function () {
14970 _chart.resetSvg();
14971
14972 _g = _chart.svg()
14973 .append('g')
14974 .attr('transform', 'translate(' + _chart.cx() + ',' + _chart.cy() + ')');
14975
14976 drawChart();
14977
14978 return _chart;
14979 };
14980
14981 function drawChart() {
14982 // set radius on basis of chart dimension if missing
14983 _radius = _radius ? _radius : d3.min([_chart.width(), _chart.height()]) / 2;
14984
14985 var arc = buildArcs();
14986
14987 var pie = pieLayout();
14988 var pieData;
14989 // if we have data...
14990 if (d3.sum(_chart.data(), _chart.valueAccessor())) {
14991 pieData = pie(_chart.data());
14992 _g.classed(_emptyCssClass, false);
14993 } else {
14994 // otherwise we'd be getting NaNs, so override
14995 // note: abuse others for its ignoring the value accessor
14996 pieData = pie([{key:_emptyTitle, value:1, others: [_emptyTitle]}]);
14997 _g.classed(_emptyCssClass, true);
14998 }
14999
15000 if (_g) {
15001 var slices = _g.selectAll('g.' + _sliceCssClass)
15002 .data(pieData);
15003
15004 createElements(slices, arc, pieData);
15005
15006 updateElements(pieData, arc);
15007
15008 removeElements(slices);
15009
15010 highlightFilter();
15011 }
15012 }
15013
15014 function createElements(slices, arc, pieData) {
15015 var slicesEnter = createSliceNodes(slices);
15016
15017 createSlicePath(slicesEnter, arc);
15018
15019 createTitles(slicesEnter);
15020
15021 createLabels(pieData, arc);
15022 }
15023
15024 function createSliceNodes(slices) {
15025 var slicesEnter = slices
15026 .enter()
15027 .append('g')
15028 .attr('class', function (d, i) {
15029 return _sliceCssClass + ' _' + i;
15030 });
15031 return slicesEnter;
15032 }
15033
15034 function createSlicePath(slicesEnter, arc) {
15035 var slicePath = slicesEnter.append('path')
15036 .attr('fill', fill)
15037 .on('click', onClick)
15038 .attr('d', function (d, i) {
15039 return safeArc(d, i, arc);
15040 });
15041
15042 dc.transition(slicePath, _chart.transitionDuration(), function (s) {
15043 s.attrTween('d', tweenPie);
15044 });
15045 }
15046
15047 function createTitles(slicesEnter) {
15048 if (_chart.renderTitle()) {
15049 slicesEnter.append('title').text(function (d) {
15050 return _chart.title()(d);
15051 });
15052 }
15053 }
15054
15055 function positionLabels(labelsEnter, arc) {
15056 dc.transition(labelsEnter, _chart.transitionDuration())
15057 .attr('transform', function (d) {
15058 return labelPosition(d, arc);
15059 })
15060 .attr('text-anchor', 'middle')
15061 .text(function (d) {
15062 var data = d.data;
15063 if ((sliceHasNoData(data) || sliceTooSmall(d)) && !isSelectedSlice(d)) {
15064 return '';
15065 }
15066 return _chart.label()(d.data);
15067 });
15068 }
15069
15070 function createLabels(pieData, arc) {
15071 if (_chart.renderLabel()) {
15072 var labels = _g.selectAll('text.' + _sliceCssClass)
15073 .data(pieData);
15074
15075 labels.exit().remove();
15076
15077 var labelsEnter = labels
15078 .enter()
15079 .append('text')
15080 .attr('class', function (d, i) {
15081 var classes = _sliceCssClass + ' _' + i;
15082 if (_externalLabelRadius) {
15083 classes += ' external';
15084 }
15085 return classes;
15086 })
15087 .on('click', onClick);
15088 positionLabels(labelsEnter, arc);
15089 }
15090 }
15091
15092 function updateElements(pieData, arc) {
15093 updateSlicePaths(pieData, arc);
15094 updateLabels(pieData, arc);
15095 updateTitles(pieData);
15096 }
15097
15098 function updateSlicePaths(pieData, arc) {
15099 var slicePaths = _g.selectAll('g.' + _sliceCssClass)
15100 .data(pieData)
15101 .select('path')
15102 .attr('d', function (d, i) {
15103 return safeArc(d, i, arc);
15104 });
15105 dc.transition(slicePaths, _chart.transitionDuration(),
15106 function (s) {
15107 s.attrTween('d', tweenPie);
15108 }).attr('fill', fill);
15109 }
15110
15111 function updateLabels(pieData, arc) {
15112 if (_chart.renderLabel()) {
15113 var labels = _g.selectAll('text.' + _sliceCssClass)
15114 .data(pieData);
15115 positionLabels(labels, arc);
15116 }
15117 }
15118
15119 function updateTitles(pieData) {
15120 if (_chart.renderTitle()) {
15121 _g.selectAll('g.' + _sliceCssClass)
15122 .data(pieData)
15123 .select('title')
15124 .text(function (d) {
15125 return _chart.title()(d.data);
15126 });
15127 }
15128 }
15129
15130 function removeElements(slices) {
15131 slices.exit().remove();
15132 }
15133
15134 function highlightFilter() {
15135 if (_chart.hasFilter()) {
15136 _chart.selectAll('g.' + _sliceCssClass).each(function (d) {
15137 if (isSelectedSlice(d)) {
15138 _chart.highlightSelected(this);
15139 } else {
15140 _chart.fadeDeselected(this);
15141 }
15142 });
15143 } else {
15144 _chart.selectAll('g.' + _sliceCssClass).each(function () {
15145 _chart.resetHighlight(this);
15146 });
15147 }
15148 }
15149
15150 /**
15151 #### .innerRadius([innerRadius])
15152 Get or set the inner radius of the pie chart. If the inner radius is greater than 0px then the
15153 pie chart will be rendered as a doughnut chart. Default inner radius is 0px.
15154
15155 **/
15156 _chart.innerRadius = function (r) {
15157 if (!arguments.length) {
15158 return _innerRadius;
15159 }
15160 _innerRadius = r;
15161 return _chart;
15162 };
15163
15164 /**
15165 #### .radius([radius])
15166 Get or set the outer radius. If the radius is not set, it will be half of the minimum of the
15167 chart width and height.
15168
15169 **/
15170 _chart.radius = function (r) {
15171 if (!arguments.length) {
15172 return _radius;
15173 }
15174 _radius = r;
15175 return _chart;
15176 };
15177
15178 /**
15179 #### .cx([cx])
15180 Get or set center x coordinate position. Default is center of svg.
15181
15182 **/
15183 _chart.cx = function (cx) {
15184 if (!arguments.length) {
15185 return (_cx || _chart.width() / 2);
15186 }
15187 _cx = cx;
15188 return _chart;
15189 };
15190
15191 /**
15192 #### .cy([cy])
15193 Get or set center y coordinate position. Default is center of svg.
15194
15195 **/
15196 _chart.cy = function (cy) {
15197 if (!arguments.length) {
15198 return (_cy || _chart.height() / 2);
15199 }
15200 _cy = cy;
15201 return _chart;
15202 };
15203
15204 function buildArcs() {
15205 return d3.svg.arc().outerRadius(_radius).innerRadius(_innerRadius);
15206 }
15207
15208 function isSelectedSlice(d) {
15209 return _chart.hasFilter(_chart.cappedKeyAccessor(d.data));
15210 }
15211
15212 _chart._doRedraw = function () {
15213 drawChart();
15214 return _chart;
15215 };
15216
15217 /**
15218 #### .minAngleForLabel([minAngle])
15219 Get or set the minimal slice angle for label rendering. Any slice with a smaller angle will not
15220 display a slice label. Default min angle is 0.5.
15221 **/
15222 _chart.minAngleForLabel = function (_) {
15223 if (!arguments.length) {
15224 return _minAngleForLabel;
15225 }
15226 _minAngleForLabel = _;
15227 return _chart;
15228 };
15229
15230 function pieLayout() {
15231 return d3.layout.pie().sort(null).value(_chart.cappedValueAccessor);
15232 }
15233
15234 function sliceTooSmall(d) {
15235 var angle = (d.endAngle - d.startAngle);
15236 return isNaN(angle) || angle < _minAngleForLabel;
15237 }
15238
15239 function sliceHasNoData(d) {
15240 return _chart.cappedValueAccessor(d) === 0;
15241 }
15242
15243 function tweenPie(b) {
15244 b.innerRadius = _innerRadius;
15245 var current = this._current;
15246 if (isOffCanvas(current)) {
15247 current = {startAngle: 0, endAngle: 0};
15248 }
15249 var i = d3.interpolate(current, b);
15250 this._current = i(0);
15251 return function (t) {
15252 return safeArc(i(t), 0, buildArcs());
15253 };
15254 }
15255
15256 function isOffCanvas(current) {
15257 return !current || isNaN(current.startAngle) || isNaN(current.endAngle);
15258 }
15259
15260 function fill(d, i) {
15261 return _chart.getColor(d.data, i);
15262 }
15263
15264 function onClick(d, i) {
15265 if (_g.attr('class') !== _emptyCssClass) {
15266 _chart.onClick(d.data, i);
15267 }
15268 }
15269
15270 function safeArc(d, i, arc) {
15271 var path = arc(d, i);
15272 if (path.indexOf('NaN') >= 0) {
15273 path = 'M0,0';
15274 }
15275 return path;
15276 }
15277
15278 /**
15279 #### .emptyTitle([title])
15280 Title to use for the only slice when there is no data
15281 */
15282 _chart.emptyTitle = function (title) {
15283 if (arguments.length === 0) {
15284 return _emptyTitle;
15285 }
15286 _emptyTitle = title;
15287 return _chart;
15288 };
15289
15290 /**
15291 #### .externalLabels([radius])
15292 Position slice labels offset from the outer edge of the chart
15293
15294 The given argument sets the radial offset.
15295 */
15296 _chart.externalLabels = function (radius) {
15297 if (arguments.length === 0) {
15298 return _externalLabelRadius;
15299 } else if (radius) {
15300 _externalLabelRadius = radius;
15301 } else {
15302 _externalLabelRadius = undefined;
15303 }
15304
15305 return _chart;
15306 };
15307
15308 function labelPosition(d, arc) {
15309 var centroid;
15310 if (_externalLabelRadius) {
15311 centroid = d3.svg.arc()
15312 .outerRadius(_radius + _externalLabelRadius)
15313 .innerRadius(_radius + _externalLabelRadius)
15314 .centroid(d);
15315 } else {
15316 centroid = arc.centroid(d);
15317 }
15318 if (isNaN(centroid[0]) || isNaN(centroid[1])) {
15319 return 'translate(0,0)';
15320 } else {
15321 return 'translate(' + centroid + ')';
15322 }
15323 }
15324
15325 _chart.legendables = function () {
15326 return _chart.data().map(function (d, i) {
15327 var legendable = {name: d.key, data: d.value, others: d.others, chart:_chart};
15328 legendable.color = _chart.getColor(d, i);
15329 return legendable;
15330 });
15331 };
15332
15333 _chart.legendHighlight = function (d) {
15334 highlightSliceFromLegendable(d, true);
15335 };
15336
15337 _chart.legendReset = function (d) {
15338 highlightSliceFromLegendable(d, false);
15339 };
15340
15341 _chart.legendToggle = function (d) {
15342 _chart.onClick({key: d.name, others: d.others});
15343 };
15344
15345 function highlightSliceFromLegendable(legendable, highlighted) {
15346 _chart.selectAll('g.pie-slice').each(function (d) {
15347 if (legendable.name === d.data.key) {
15348 d3.select(this).classed('highlight', highlighted);
15349 }
15350 });
15351 }
15352
15353 return _chart.anchor(parent, chartGroup);
15354 };
15355
15356 /**
15357 ## Bar Chart
15358 Includes: [Stack Mixin](#stack Mixin), [Coordinate Grid Mixin](#coordinate-grid-mixin)
15359
15360 Concrete bar chart/histogram implementation.
15361
15362 Examples:
15363
15364 * [Nasdaq 100 Index](http://dc-js.github.com/dc.js/)
15365 * [Canadian City Crime Stats](http://dc-js.github.com/dc.js/crime/index.html)
15366 #### dc.barChart(parent[, chartGroup])
15367 Create a bar chart instance and attach it to the given parent element.
15368
15369 Parameters:
15370 * parent : string | node | selection | compositeChart - any valid
15371 [d3 single selector](https://github.com/mbostock/d3/wiki/Selections#selecting-elements) specifying
15372 a dom block element such as a div; or a dom element or d3 selection.
15373 If the bar chart is a sub-chart in a [Composite Chart](#composite-chart) then pass in the parent composite
15374 chart instance.
15375 * chartGroup : string (optional) - name of the chart group this chart instance should be placed in.
15376 Interaction with a chart will only trigger events and redraws within the chart's group.
15377
15378 Returns:
15379 A newly created bar chart instance
15380
15381 ```js
15382 // create a bar chart under #chart-container1 element using the default global chart group
15383 var chart1 = dc.barChart('#chart-container1');
15384 // create a bar chart under #chart-container2 element using chart group A
15385 var chart2 = dc.barChart('#chart-container2', 'chartGroupA');
15386 // create a sub-chart under a composite parent chart
15387 var chart3 = dc.barChart(compositeChart);
15388 ```
15389
15390 **/
15391 dc.barChart = function (parent, chartGroup) {
15392 var MIN_BAR_WIDTH = 1;
15393 var DEFAULT_GAP_BETWEEN_BARS = 2;
15394
15395 var _chart = dc.stackMixin(dc.coordinateGridMixin({}));
15396
15397 var _gap = DEFAULT_GAP_BETWEEN_BARS;
15398 var _centerBar = false;
15399 var _alwaysUseRounding = false;
15400
15401 var _barWidth;
15402
15403 dc.override(_chart, 'rescale', function () {
15404 _chart._rescale();
15405 _barWidth = undefined;
15406 });
15407
15408 dc.override(_chart, 'render', function () {
15409 if (_chart.round() && _centerBar && !_alwaysUseRounding) {
15410 dc.logger.warn('By default, brush rounding is disabled if bars are centered. ' +
15411 'See dc.js bar chart API documentation for details.');
15412 }
15413
15414 _chart._render();
15415 });
15416
15417 _chart.plotData = function () {
15418 var layers = _chart.chartBodyG().selectAll('g.stack')
15419 .data(_chart.data());
15420
15421 calculateBarWidth();
15422
15423 layers
15424 .enter()
15425 .append('g')
15426 .attr('class', function (d, i) {
15427 return 'stack ' + '_' + i;
15428 });
15429
15430 layers.each(function (d, i) {
15431 var layer = d3.select(this);
15432
15433 renderBars(layer, i, d);
15434 });
15435 };
15436
15437 function barHeight(d) {
15438 return dc.utils.safeNumber(Math.abs(_chart.y()(d.y + d.y0) - _chart.y()(d.y0)));
15439 }
15440
15441 function renderBars(layer, layerIndex, d) {
15442 var bars = layer.selectAll('rect.bar')
15443 .data(d.values, dc.pluck('x'));
15444
15445 var enter = bars.enter()
15446 .append('rect')
15447 .attr('class', 'bar')
15448 .attr('fill', dc.pluck('data', _chart.getColor))
15449 .attr('y', _chart.yAxisHeight())
15450 .attr('height', 0);
15451
15452 if (_chart.renderTitle()) {
15453 enter.append('title').text(dc.pluck('data', _chart.title(d.name)));
15454 }
15455
15456 if (_chart.isOrdinal()) {
15457 bars.on('click', onClick);
15458 }
15459
15460 dc.transition(bars, _chart.transitionDuration())
15461 .attr('x', function (d) {
15462 var x = _chart.x()(d.x);
15463 if (_centerBar) {
15464 x -= _barWidth / 2;
15465 }
15466 if (_chart.isOrdinal() && _gap !== undefined) {
15467 x += _gap / 2;
15468 }
15469 return dc.utils.safeNumber(x);
15470 })
15471 .attr('y', function (d) {
15472 var y = _chart.y()(d.y + d.y0);
15473
15474 if (d.y < 0) {
15475 y -= barHeight(d);
15476 }
15477
15478 return dc.utils.safeNumber(y);
15479 })
15480 .attr('width', _barWidth)
15481 .attr('height', function (d) {
15482 return barHeight(d);
15483 })
15484 .attr('fill', dc.pluck('data', _chart.getColor))
15485 .select('title').text(dc.pluck('data', _chart.title(d.name)));
15486
15487 dc.transition(bars.exit(), _chart.transitionDuration())
15488 .attr('height', 0)
15489 .remove();
15490 }
15491
15492 function calculateBarWidth() {
15493 if (_barWidth === undefined) {
15494 var numberOfBars = _chart.xUnitCount();
15495
15496 // please can't we always use rangeBands for bar charts?
15497 if (_chart.isOrdinal() && _gap === undefined) {
15498 _barWidth = Math.floor(_chart.x().rangeBand());
15499 } else if (_gap) {
15500 _barWidth = Math.floor((_chart.xAxisLength() - (numberOfBars - 1) * _gap) / numberOfBars);
15501 } else {
15502 _barWidth = Math.floor(_chart.xAxisLength() / (1 + _chart.barPadding()) / numberOfBars);
15503 }
15504
15505 if (_barWidth === Infinity || isNaN(_barWidth) || _barWidth < MIN_BAR_WIDTH) {
15506 _barWidth = MIN_BAR_WIDTH;
15507 }
15508 }
15509 }
15510
15511 _chart.fadeDeselectedArea = function () {
15512 var bars = _chart.chartBodyG().selectAll('rect.bar');
15513 var extent = _chart.brush().extent();
15514
15515 if (_chart.isOrdinal()) {
15516 if (_chart.hasFilter()) {
15517 bars.classed(dc.constants.SELECTED_CLASS, function (d) {
15518 return _chart.hasFilter(d.x);
15519 });
15520 bars.classed(dc.constants.DESELECTED_CLASS, function (d) {
15521 return !_chart.hasFilter(d.x);
15522 });
15523 } else {
15524 bars.classed(dc.constants.SELECTED_CLASS, false);
15525 bars.classed(dc.constants.DESELECTED_CLASS, false);
15526 }
15527 } else {
15528 if (!_chart.brushIsEmpty(extent)) {
15529 var start = extent[0];
15530 var end = extent[1];
15531
15532 bars.classed(dc.constants.DESELECTED_CLASS, function (d) {
15533 return d.x < start || d.x >= end;
15534 });
15535 } else {
15536 bars.classed(dc.constants.DESELECTED_CLASS, false);
15537 }
15538 }
15539 };
15540
15541 /**
15542 #### .centerBar(boolean)
15543 Whether the bar chart will render each bar centered around the data position on x axis. Default: false
15544
15545 **/
15546 _chart.centerBar = function (_) {
15547 if (!arguments.length) {
15548 return _centerBar;
15549 }
15550 _centerBar = _;
15551 return _chart;
15552 };
15553
15554 function onClick(d) {
15555 _chart.onClick(d.data);
15556 }
15557
15558 /**
15559 #### .barPadding([padding])
15560 Get or set the spacing between bars as a fraction of bar size. Valid values are between 0-1.
15561 Setting this value will also remove any previously set `gap`. See the
15562 [d3 docs](https://github.com/mbostock/d3/wiki/Ordinal-Scales#wiki-ordinal_rangeBands)
15563 for a visual description of how the padding is applied.
15564 **/
15565 _chart.barPadding = function (_) {
15566 if (!arguments.length) {
15567 return _chart._rangeBandPadding();
15568 }
15569 _chart._rangeBandPadding(_);
15570 _gap = undefined;
15571 return _chart;
15572 };
15573
15574 _chart._useOuterPadding = function () {
15575 return _gap === undefined;
15576 };
15577
15578 /**
15579 #### .outerPadding([padding])
15580 Get or set the outer padding on an ordinal bar chart. This setting has no effect on non-ordinal charts.
15581 Will pad the width by `padding * barWidth` on each side of the chart.
15582
15583 Default: 0.5
15584 **/
15585 _chart.outerPadding = _chart._outerRangeBandPadding;
15586
15587 /**
15588 #### .gap(gapBetweenBars)
15589 Manually set fixed gap (in px) between bars instead of relying on the default auto-generated
15590 gap. By default the bar chart implementation will calculate and set the gap automatically
15591 based on the number of data points and the length of the x axis.
15592
15593 **/
15594 _chart.gap = function (_) {
15595 if (!arguments.length) {
15596 return _gap;
15597 }
15598 _gap = _;
15599 return _chart;
15600 };
15601
15602 _chart.extendBrush = function () {
15603 var extent = _chart.brush().extent();
15604 if (_chart.round() && (!_centerBar || _alwaysUseRounding)) {
15605 extent[0] = extent.map(_chart.round())[0];
15606 extent[1] = extent.map(_chart.round())[1];
15607
15608 _chart.chartBodyG().select('.brush')
15609 .call(_chart.brush().extent(extent));
15610 }
15611
15612 return extent;
15613 };
15614
15615 /**
15616 #### .alwaysUseRounding([boolean])
15617 Set or get whether rounding is enabled when bars are centered. Default: false. If false, using
15618 rounding with centered bars will result in a warning and rounding will be ignored. This flag
15619 has no effect if bars are not centered.
15620
15621 When using standard d3.js rounding methods, the brush often doesn't align correctly with
15622 centered bars since the bars are offset. The rounding function must add an offset to
15623 compensate, such as in the following example.
15624 ```js
15625 chart.round(function(n) {return Math.floor(n)+0.5});
15626 ```
15627 **/
15628 _chart.alwaysUseRounding = function (_) {
15629 if (!arguments.length) {
15630 return _alwaysUseRounding;
15631 }
15632 _alwaysUseRounding = _;
15633 return _chart;
15634 };
15635
15636 function colorFilter(color, inv) {
15637 return function () {
15638 var item = d3.select(this);
15639 var match = item.attr('fill') === color;
15640 return inv ? !match : match;
15641 };
15642 }
15643
15644 _chart.legendHighlight = function (d) {
15645 if (!_chart.isLegendableHidden(d)) {
15646 _chart.g().selectAll('rect.bar')
15647 .classed('highlight', colorFilter(d.color))
15648 .classed('fadeout', colorFilter(d.color, true));
15649 }
15650 };
15651
15652 _chart.legendReset = function () {
15653 _chart.g().selectAll('rect.bar')
15654 .classed('highlight', false)
15655 .classed('fadeout', false);
15656 };
15657
15658 dc.override(_chart, 'xAxisMax', function () {
15659 var max = this._xAxisMax();
15660 if ('resolution' in _chart.xUnits()) {
15661 var res = _chart.xUnits().resolution;
15662 max += res;
15663 }
15664 return max;
15665 });
15666
15667 return _chart.anchor(parent, chartGroup);
15668 };
15669
15670 /**
15671 ## Line Chart
15672 Includes [Stack Mixin](#stack-mixin), [Coordinate Grid Mixin](#coordinate-grid-mixin)
15673
15674 Concrete line/area chart implementation.
15675
15676 Examples:
15677 * [Nasdaq 100 Index](http://dc-js.github.com/dc.js/)
15678 * [Canadian City Crime Stats](http://dc-js.github.com/dc.js/crime/index.html)
15679 #### dc.lineChart(parent[, chartGroup])
15680 Create a line chart instance and attach it to the given parent element.
15681
15682 Parameters:
15683
15684 * parent : string | node | selection | compositeChart - any valid
15685 [d3 single selector](https://github.com/mbostock/d3/wiki/Selections#selecting-elements) specifying
15686 a dom block element such as a div; or a dom element or d3 selection.
15687 If the line chart is a sub-chart in a [Composite Chart](#composite-chart) then pass in the parent composite
15688 chart instance.
15689
15690 * chartGroup : string (optional) - name of the chart group this chart instance should be placed in.
15691 Interaction with a chart will only trigger events and redraws within the chart's group.
15692
15693 Returns:
15694 A newly created line chart instance
15695
15696 ```js
15697 // create a line chart under #chart-container1 element using the default global chart group
15698 var chart1 = dc.lineChart('#chart-container1');
15699 // create a line chart under #chart-container2 element using chart group A
15700 var chart2 = dc.lineChart('#chart-container2', 'chartGroupA');
15701 // create a sub-chart under a composite parent chart
15702 var chart3 = dc.lineChart(compositeChart);
15703 ```
15704
15705 **/
15706 dc.lineChart = function (parent, chartGroup) {
15707 var DEFAULT_DOT_RADIUS = 5;
15708 var TOOLTIP_G_CLASS = 'dc-tooltip';
15709 var DOT_CIRCLE_CLASS = 'dot';
15710 var Y_AXIS_REF_LINE_CLASS = 'yRef';
15711 var X_AXIS_REF_LINE_CLASS = 'xRef';
15712 var DEFAULT_DOT_OPACITY = 1e-6;
15713
15714 var _chart = dc.stackMixin(dc.coordinateGridMixin({}));
15715 var _renderArea = false;
15716 var _dotRadius = DEFAULT_DOT_RADIUS;
15717 var _dataPointRadius = null;
15718 var _dataPointFillOpacity = DEFAULT_DOT_OPACITY;
15719 var _dataPointStrokeOpacity = DEFAULT_DOT_OPACITY;
15720 var _interpolate = 'linear';
15721 var _tension = 0.7;
15722 var _defined;
15723 var _dashStyle;
15724
15725 _chart.transitionDuration(500);
15726 _chart._rangeBandPadding(1);
15727
15728 _chart.plotData = function () {
15729 var chartBody = _chart.chartBodyG();
15730 var layersList = chartBody.selectAll('g.stack-list');
15731
15732 if (layersList.empty()) {
15733 layersList = chartBody.append('g').attr('class', 'stack-list');
15734 }
15735
15736 var layers = layersList.selectAll('g.stack').data(_chart.data());
15737
15738 var layersEnter = layers
15739 .enter()
15740 .append('g')
15741 .attr('class', function (d, i) {
15742 return 'stack ' + '_' + i;
15743 });
15744
15745 drawLine(layersEnter, layers);
15746
15747 drawArea(layersEnter, layers);
15748
15749 drawDots(chartBody, layers);
15750 };
15751
15752 /**
15753 #### .interpolate([value])
15754 Gets or sets the interpolator to use for lines drawn, by string name, allowing e.g. step
15755 functions, splines, and cubic interpolation. This is passed to
15756 [d3.svg.line.interpolate](https://github.com/mbostock/d3/wiki/SVG-Shapes#line_interpolate) and
15757 [d3.svg.area.interpolate](https://github.com/mbostock/d3/wiki/SVG-Shapes#area_interpolate),
15758 where you can find a complete list of valid arguments
15759 **/
15760 _chart.interpolate = function (_) {
15761 if (!arguments.length) {
15762 return _interpolate;
15763 }
15764 _interpolate = _;
15765 return _chart;
15766 };
15767
15768 /**
15769 #### .tension([value]) Gets or sets the tension to use for lines drawn, in the range 0 to 1.
15770 This parameter further customizes the interpolation behavior. It is passed to
15771 [d3.svg.line.tension](https://github.com/mbostock/d3/wiki/SVG-Shapes#line_tension) and
15772 [d3.svg.area.tension](https://github.com/mbostock/d3/wiki/SVG-Shapes#area_tension). Default:
15773 0.7
15774 **/
15775 _chart.tension = function (_) {
15776 if (!arguments.length) {
15777 return _tension;
15778 }
15779 _tension = _;
15780 return _chart;
15781 };
15782
15783 /**
15784 #### .defined([value])
15785 Gets or sets a function that will determine discontinuities in the line which should be
15786 skipped: the path will be broken into separate subpaths if some points are undefined.
15787 This function is passed to
15788 [d3.svg.line.defined](https://github.com/mbostock/d3/wiki/SVG-Shapes#line_defined)
15789
15790 Note: crossfilter will sometimes coerce nulls to 0, so you may need to carefully write
15791 custom reduce functions to get this to work, depending on your data. See
15792 https://github.com/dc-js/dc.js/issues/615#issuecomment-49089248
15793 **/
15794 _chart.defined = function (_) {
15795 if (!arguments.length) {
15796 return _defined;
15797 }
15798 _defined = _;
15799 return _chart;
15800 };
15801
15802 /**
15803 #### .dashStyle([array])
15804 Set the line's d3 dashstyle. This value becomes the 'stroke-dasharray' of line. Defaults to empty
15805 array (solid line).
15806 ```js
15807 // create a Dash Dot Dot Dot
15808 chart.dashStyle([3,1,1,1]);
15809 ```
15810 **/
15811 _chart.dashStyle = function (_) {
15812 if (!arguments.length) {
15813 return _dashStyle;
15814 }
15815 _dashStyle = _;
15816 return _chart;
15817 };
15818
15819 /**
15820 #### .renderArea([boolean])
15821 Get or set render area flag. If the flag is set to true then the chart will render the area
15822 beneath each line and the line chart effectively becomes an area chart.
15823
15824 **/
15825 _chart.renderArea = function (_) {
15826 if (!arguments.length) {
15827 return _renderArea;
15828 }
15829 _renderArea = _;
15830 return _chart;
15831 };
15832
15833 function colors(d, i) {
15834 return _chart.getColor.call(d, d.values, i);
15835 }
15836
15837 function drawLine(layersEnter, layers) {
15838 var line = d3.svg.line()
15839 .x(function (d) {
15840 return _chart.x()(d.x);
15841 })
15842 .y(function (d) {
15843 return _chart.y()(d.y + d.y0);
15844 })
15845 .interpolate(_interpolate)
15846 .tension(_tension);
15847 if (_defined) {
15848 line.defined(_defined);
15849 }
15850
15851 var path = layersEnter.append('path')
15852 .attr('class', 'line')
15853 .attr('stroke', colors);
15854 if (_dashStyle) {
15855 path.attr('stroke-dasharray', _dashStyle);
15856 }
15857
15858 dc.transition(layers.select('path.line'), _chart.transitionDuration())
15859 //.ease('linear')
15860 .attr('stroke', colors)
15861 .attr('d', function (d) {
15862 return safeD(line(d.values));
15863 });
15864 }
15865
15866 function drawArea(layersEnter, layers) {
15867 if (_renderArea) {
15868 var area = d3.svg.area()
15869 .x(function (d) {
15870 return _chart.x()(d.x);
15871 })
15872 .y(function (d) {
15873 return _chart.y()(d.y + d.y0);
15874 })
15875 .y0(function (d) {
15876 return _chart.y()(d.y0);
15877 })
15878 .interpolate(_interpolate)
15879 .tension(_tension);
15880 if (_defined) {
15881 area.defined(_defined);
15882 }
15883
15884 layersEnter.append('path')
15885 .attr('class', 'area')
15886 .attr('fill', colors)
15887 .attr('d', function (d) {
15888 return safeD(area(d.values));
15889 });
15890
15891 dc.transition(layers.select('path.area'), _chart.transitionDuration())
15892 //.ease('linear')
15893 .attr('fill', colors)
15894 .attr('d', function (d) {
15895 return safeD(area(d.values));
15896 });
15897 }
15898 }
15899
15900 function safeD (d) {
15901 return (!d || d.indexOf('NaN') >= 0) ? 'M0,0' : d;
15902 }
15903
15904 function drawDots(chartBody, layers) {
15905 if (!_chart.brushOn()) {
15906 var tooltipListClass = TOOLTIP_G_CLASS + '-list';
15907 var tooltips = chartBody.select('g.' + tooltipListClass);
15908
15909 if (tooltips.empty()) {
15910 tooltips = chartBody.append('g').attr('class', tooltipListClass);
15911 }
15912
15913 layers.each(function (d, layerIndex) {
15914 var points = d.values;
15915 if (_defined) {
15916 points = points.filter(_defined);
15917 }
15918
15919 var g = tooltips.select('g.' + TOOLTIP_G_CLASS + '._' + layerIndex);
15920 if (g.empty()) {
15921 g = tooltips.append('g').attr('class', TOOLTIP_G_CLASS + ' _' + layerIndex);
15922 }
15923
15924 createRefLines(g);
15925
15926 var dots = g.selectAll('circle.' + DOT_CIRCLE_CLASS)
15927 .data(points, dc.pluck('x'));
15928
15929 dots.enter()
15930 .append('circle')
15931 .attr('class', DOT_CIRCLE_CLASS)
15932 .attr('r', getDotRadius())
15933 .style('fill-opacity', _dataPointFillOpacity)
15934 .style('stroke-opacity', _dataPointStrokeOpacity)
15935 .on('mousemove', function () {
15936 var dot = d3.select(this);
15937 showDot(dot);
15938 showRefLines(dot, g);
15939 })
15940 .on('mouseout', function () {
15941 var dot = d3.select(this);
15942 hideDot(dot);
15943 hideRefLines(g);
15944 });
15945
15946 dots
15947 .attr('cx', function (d) {
15948 return dc.utils.safeNumber(_chart.x()(d.x));
15949 })
15950 .attr('cy', function (d) {
15951 return dc.utils.safeNumber(_chart.y()(d.y + d.y0));
15952 })
15953 .attr('fill', _chart.getColor)
15954 .call(renderTitle, d);
15955
15956 dots.exit().remove();
15957 });
15958 }
15959 }
15960
15961 function createRefLines(g) {
15962 var yRefLine = g.select('path.' + Y_AXIS_REF_LINE_CLASS).empty() ?
15963 g.append('path').attr('class', Y_AXIS_REF_LINE_CLASS) : g.select('path.' + Y_AXIS_REF_LINE_CLASS);
15964 yRefLine.style('display', 'none').attr('stroke-dasharray', '5,5');
15965
15966 var xRefLine = g.select('path.' + X_AXIS_REF_LINE_CLASS).empty() ?
15967 g.append('path').attr('class', X_AXIS_REF_LINE_CLASS) : g.select('path.' + X_AXIS_REF_LINE_CLASS);
15968 xRefLine.style('display', 'none').attr('stroke-dasharray', '5,5');
15969 }
15970
15971 function showDot(dot) {
15972 dot.style('fill-opacity', 0.8);
15973 dot.style('stroke-opacity', 0.8);
15974 dot.attr('r', _dotRadius);
15975 return dot;
15976 }
15977
15978 function showRefLines(dot, g) {
15979 var x = dot.attr('cx');
15980 var y = dot.attr('cy');
15981 var yAxisX = (_chart._yAxisX() - _chart.margins().left);
15982 var yAxisRefPathD = 'M' + yAxisX + ' ' + y + 'L' + (x) + ' ' + (y);
15983 var xAxisRefPathD = 'M' + x + ' ' + _chart.yAxisHeight() + 'L' + x + ' ' + y;
15984 g.select('path.' + Y_AXIS_REF_LINE_CLASS).style('display', '').attr('d', yAxisRefPathD);
15985 g.select('path.' + X_AXIS_REF_LINE_CLASS).style('display', '').attr('d', xAxisRefPathD);
15986 }
15987
15988 function getDotRadius() {
15989 return _dataPointRadius || _dotRadius;
15990 }
15991
15992 function hideDot(dot) {
15993 dot.style('fill-opacity', _dataPointFillOpacity)
15994 .style('stroke-opacity', _dataPointStrokeOpacity)
15995 .attr('r', getDotRadius());
15996 }
15997
15998 function hideRefLines(g) {
15999 g.select('path.' + Y_AXIS_REF_LINE_CLASS).style('display', 'none');
16000 g.select('path.' + X_AXIS_REF_LINE_CLASS).style('display', 'none');
16001 }
16002
16003 function renderTitle(dot, d) {
16004 if (_chart.renderTitle()) {
16005 dot.selectAll('title').remove();
16006 dot.append('title').text(dc.pluck('data', _chart.title(d.name)));
16007 }
16008 }
16009
16010 /**
16011 #### .dotRadius([dotRadius])
16012 Get or set the radius (in px) for dots displayed on the data points. Default dot radius is 5.
16013 **/
16014 _chart.dotRadius = function (_) {
16015 if (!arguments.length) {
16016 return _dotRadius;
16017 }
16018 _dotRadius = _;
16019 return _chart;
16020 };
16021
16022 /**
16023 #### .renderDataPoints([options])
16024 Always show individual dots for each datapoint.
16025
16026 Options, if given, is an object that can contain the following:
16027
16028 * fillOpacity (default 0.8)
16029 * strokeOpacity (default 0.8)
16030 * radius (default 2)
16031
16032 If `options` is falsy, it disables data point rendering.
16033
16034 If no `options` are provided, the current `options` values are instead returned.
16035
16036 Example:
16037 ```
16038 chart.renderDataPoints({radius: 2, fillOpacity: 0.8, strokeOpacity: 0.8})
16039 ```
16040 **/
16041 _chart.renderDataPoints = function (options) {
16042 if (!arguments.length) {
16043 return {
16044 fillOpacity: _dataPointFillOpacity,
16045 strokeOpacity: _dataPointStrokeOpacity,
16046 radius: _dataPointRadius
16047 };
16048 } else if (!options) {
16049 _dataPointFillOpacity = DEFAULT_DOT_OPACITY;
16050 _dataPointStrokeOpacity = DEFAULT_DOT_OPACITY;
16051 _dataPointRadius = null;
16052 } else {
16053 _dataPointFillOpacity = options.fillOpacity || 0.8;
16054 _dataPointStrokeOpacity = options.strokeOpacity || 0.8;
16055 _dataPointRadius = options.radius || 2;
16056 }
16057 return _chart;
16058 };
16059
16060 function colorFilter(color, dashstyle, inv) {
16061 return function () {
16062 var item = d3.select(this);
16063 var match = (item.attr('stroke') === color &&
16064 item.attr('stroke-dasharray') === ((dashstyle instanceof Array) ?
16065 dashstyle.join(',') : null)) || item.attr('fill') === color;
16066 return inv ? !match : match;
16067 };
16068 }
16069
16070 _chart.legendHighlight = function (d) {
16071 if (!_chart.isLegendableHidden(d)) {
16072 _chart.g().selectAll('path.line, path.area')
16073 .classed('highlight', colorFilter(d.color, d.dashstyle))
16074 .classed('fadeout', colorFilter(d.color, d.dashstyle, true));
16075 }
16076 };
16077
16078 _chart.legendReset = function () {
16079 _chart.g().selectAll('path.line, path.area')
16080 .classed('highlight', false)
16081 .classed('fadeout', false);
16082 };
16083
16084 dc.override(_chart, 'legendables', function () {
16085 var legendables = _chart._legendables();
16086 if (!_dashStyle) {
16087 return legendables;
16088 }
16089 return legendables.map(function (l) {
16090 l.dashstyle = _dashStyle;
16091 return l;
16092 });
16093 });
16094
16095 return _chart.anchor(parent, chartGroup);
16096 };
16097
16098 /**
16099 ## Data Count Widget
16100 Includes: [Base Mixin](#base-mixin)
16101
16102 The data count widget is a simple widget designed to display the number of records selected by the
16103 current filters out of the total number of records in the data set. Once created the data count widget
16104 will automatically update the text content of the following elements under the parent element.
16105
16106 * '.total-count' - total number of records
16107 * '.filter-count' - number of records matched by the current filters
16108
16109 Examples:
16110
16111 * [Nasdaq 100 Index](http://dc-js.github.com/dc.js/)
16112 #### dc.dataCount(parent[, chartGroup])
16113 Create a data count widget and attach it to the given parent element.
16114
16115 Parameters:
16116
16117 * parent : string | node | selection - any valid
16118 [d3 single selector](https://github.com/mbostock/d3/wiki/Selections#selecting-elements) specifying
16119 a dom block element such as a div; or a dom element or d3 selection.
16120 * chartGroup : string (optional) - name of the chart group this widget should be placed in.
16121 The data count widget will only react to filter changes in the chart group.
16122
16123 Returns:
16124 A newly created data count widget instance
16125 #### .dimension(allData) - **mandatory**
16126 For the data count widget the only valid dimension is the entire data set.
16127 #### .group(groupAll) - **mandatory**
16128 For the data count widget the only valid group is the group returned by `dimension.groupAll()`.
16129
16130 ```js
16131 var ndx = crossfilter(data);
16132 var all = ndx.groupAll();
16133
16134 dc.dataCount('.dc-data-count')
16135 .dimension(ndx)
16136 .group(all);
16137 ```
16138
16139 **/
16140 dc.dataCount = function (parent, chartGroup) {
16141 var _formatNumber = d3.format(',d');
16142 var _chart = dc.baseMixin({});
16143 var _html = {some:'', all:''};
16144
16145 /**
16146 #### html([object])
16147 Gets or sets an optional object specifying HTML templates to use depending how many items are
16148 selected. The text `%total-count` will replaced with the total number of records, and the text
16149 `%filter-count` will be replaced with the number of selected records.
16150 - all: HTML template to use if all items are selected
16151 - some: HTML template to use if not all items are selected
16152
16153 ```js
16154 counter.html({
16155 some: '%filter-count out of %total-count records selected',
16156 all: 'All records selected. Click on charts to apply filters'
16157 })
16158 ```
16159 **/
16160 _chart.html = function (s) {
16161 if (!arguments.length) {
16162 return _html;
16163 }
16164 if (s.all) {
16165 _html.all = s.all;
16166 }
16167 if (s.some) {
16168 _html.some = s.some;
16169 }
16170 return _chart;
16171 };
16172
16173 /**
16174 #### formatNumber([formatter])
16175 Gets or sets an optional function to format the filter count and total count.
16176
16177 ```js
16178 counter.formatNumber(d3.format('.2g'))
16179 ```
16180 **/
16181 _chart.formatNumber = function (s) {
16182 if (!arguments.length) {
16183 return _formatNumber;
16184 }
16185 _formatNumber = s;
16186 return _chart;
16187 };
16188
16189 _chart._doRender = function () {
16190 var tot = _chart.dimension().size(),
16191 val = _chart.group().value();
16192 var all = _formatNumber(tot);
16193 var selected = _formatNumber(val);
16194
16195 if ((tot === val) && (_html.all !== '')) {
16196 _chart.root().html(_html.all.replace('%total-count', all).replace('%filter-count', selected));
16197 } else if (_html.some !== '') {
16198 _chart.root().html(_html.some.replace('%total-count', all).replace('%filter-count', selected));
16199 } else {
16200 _chart.selectAll('.total-count').text(all);
16201 _chart.selectAll('.filter-count').text(selected);
16202 }
16203 return _chart;
16204 };
16205
16206 _chart._doRedraw = function () {
16207 return _chart._doRender();
16208 };
16209
16210 return _chart.anchor(parent, chartGroup);
16211 };
16212
16213 /**
16214 ## Data Table Widget
16215 Includes: [Base Mixin](#base-mixin)
16216
16217 The data table is a simple widget designed to list crossfilter focused data set (rows being
16218 filtered) in a good old tabular fashion.
16219
16220 Examples:
16221 * [Nasdaq 100 Index](http://dc-js.github.com/dc.js/)
16222 #### dc.dataTable(parent[, chartGroup])
16223 Create a data table widget instance and attach it to the given parent element.
16224
16225 Parameters:
16226 * parent : string | node | selection - any valid
16227 [d3 single selector](https://github.com/mbostock/d3/wiki/Selections#selecting-elements) specifying
16228 a dom block element such as a div; or a dom element or d3 selection.
16229
16230 * chartGroup : string (optional) - name of the chart group this chart instance should be placed in.
16231 Interaction with a chart will only trigger events and redraws within the chart's group.
16232
16233 Returns:
16234 A newly created data table widget instance
16235
16236 **/
16237 dc.dataTable = function (parent, chartGroup) {
16238 var LABEL_CSS_CLASS = 'dc-table-label';
16239 var ROW_CSS_CLASS = 'dc-table-row';
16240 var COLUMN_CSS_CLASS = 'dc-table-column';
16241 var GROUP_CSS_CLASS = 'dc-table-group';
16242 var HEAD_CSS_CLASS = 'dc-table-head';
16243
16244 var _chart = dc.baseMixin({});
16245
16246 var _size = 25;
16247 var _columns = [];
16248 var _sortBy = function (d) {
16249 return d;
16250 };
16251 var _order = d3.ascending;
16252
16253 _chart._doRender = function () {
16254 _chart.selectAll('tbody').remove();
16255
16256 renderRows(renderGroups());
16257
16258 return _chart;
16259 };
16260
16261 _chart._doColumnValueFormat = function (v, d) {
16262 return ((typeof v === 'function') ?
16263 v(d) : // v as function
16264 ((typeof v === 'string') ?
16265 d[v] : // v is field name string
16266 v.format(d) // v is Object, use fn (element 2)
16267 )
16268 );
16269 };
16270
16271 _chart._doColumnHeaderFormat = function (d) {
16272 // if 'function', convert to string representation
16273 // show a string capitalized
16274 // if an object then display it's label string as-is.
16275 return (typeof d === 'function') ?
16276 _chart._doColumnHeaderFnToString(d) :
16277 ((typeof d === 'string') ?
16278 _chart._doColumnHeaderCapitalize(d) : String(d.label));
16279 };
16280
16281 _chart._doColumnHeaderCapitalize = function (s) {
16282 // capitalize
16283 return s.charAt(0).toUpperCase() + s.slice(1);
16284 };
16285
16286 _chart._doColumnHeaderFnToString = function (f) {
16287 // columnString(f) {
16288 var s = String(f);
16289 var i1 = s.indexOf('return ');
16290 if (i1 >= 0) {
16291 var i2 = s.lastIndexOf(';');
16292 if (i2 >= 0) {
16293 s = s.substring(i1 + 7, i2);
16294 var i3 = s.indexOf('numberFormat');
16295 if (i3 >= 0) {
16296 s = s.replace('numberFormat', '');
16297 }
16298 }
16299 }
16300 return s;
16301 };
16302
16303 function renderGroups() {
16304 // The 'original' example uses all 'functions'.
16305 // If all 'functions' are used, then don't remove/add a header, and leave
16306 // the html alone. This preserves the functionality of earlier releases.
16307 // A 2nd option is a string representing a field in the data.
16308 // A third option is to supply an Object such as an array of 'information', and
16309 // supply your own _doColumnHeaderFormat and _doColumnValueFormat functions to
16310 // create what you need.
16311 var bAllFunctions = true;
16312 _columns.forEach(function (f) {
16313 bAllFunctions = bAllFunctions & (typeof f === 'function');
16314 });
16315
16316 if (!bAllFunctions) {
16317 _chart.selectAll('th').remove();
16318 var headcols = _chart.root().selectAll('th')
16319 .data(_columns);
16320
16321 var headGroup = headcols
16322 .enter()
16323 .append('th');
16324
16325 headGroup
16326 .attr('class', HEAD_CSS_CLASS)
16327 .html(function (d) {
16328 return (_chart._doColumnHeaderFormat(d));
16329
16330 });
16331 }
16332
16333 var groups = _chart.root().selectAll('tbody')
16334 .data(nestEntries(), function (d) {
16335 return _chart.keyAccessor()(d);
16336 });
16337
16338 var rowGroup = groups
16339 .enter()
16340 .append('tbody');
16341
16342 rowGroup
16343 .append('tr')
16344 .attr('class', GROUP_CSS_CLASS)
16345 .append('td')
16346 .attr('class', LABEL_CSS_CLASS)
16347 .attr('colspan', _columns.length)
16348 .html(function (d) {
16349 return _chart.keyAccessor()(d);
16350 });
16351
16352 groups.exit().remove();
16353
16354 return rowGroup;
16355 }
16356
16357 function nestEntries() {
16358 var entries;
16359 if (_order === d3.ascending) {
16360 entries = _chart.dimension().bottom(_size);
16361 } else {
16362 entries = _chart.dimension().top(_size);
16363 }
16364
16365 return d3.nest()
16366 .key(_chart.group())
16367 .sortKeys(_order)
16368 .entries(entries.sort(function (a, b) {
16369 return _order(_sortBy(a), _sortBy(b));
16370 }));
16371 }
16372
16373 function renderRows(groups) {
16374 var rows = groups.order()
16375 .selectAll('tr.' + ROW_CSS_CLASS)
16376 .data(function (d) {
16377 return d.values;
16378 });
16379
16380 var rowEnter = rows.enter()
16381 .append('tr')
16382 .attr('class', ROW_CSS_CLASS);
16383
16384 _columns.forEach(function (v, i) {
16385 rowEnter.append('td')
16386 .attr('class', COLUMN_CSS_CLASS + ' _' + i)
16387 .html(function (d) {
16388 return _chart._doColumnValueFormat(v, d);
16389 });
16390 });
16391
16392 rows.exit().remove();
16393
16394 return rows;
16395 }
16396
16397 _chart._doRedraw = function () {
16398 return _chart._doRender();
16399 };
16400
16401 /**
16402 #### .size([size])
16403 Get or set the table size which determines the number of rows displayed by the widget.
16404
16405 **/
16406 _chart.size = function (s) {
16407 if (!arguments.length) {
16408 return _size;
16409 }
16410 _size = s;
16411 return _chart;
16412 };
16413
16414 /**
16415 #### .columns([columnFunctionArray])
16416 Get or set column functions. The data table widget now supports several methods of specifying
16417 the columns to display. The original method, first shown below, uses an array of functions to
16418 generate dynamic columns. Column functions are simple javascript functions with only one input
16419 argument `d` which represents a row in the data set. The return value of these functions will be
16420 used directly to generate table content for each cell. However, this method requires the .html
16421 table entry to have a fixed set of column headers.
16422
16423 ```js
16424 chart.columns([
16425 function(d) {
16426 return d.date;
16427 },
16428 function(d) {
16429 return d.open;
16430 },
16431 function(d) {
16432 return d.close;
16433 },
16434 function(d) {
16435 return numberFormat(d.close - d.open);
16436 },
16437 function(d) {
16438 return d.volume;
16439 }
16440 ]);
16441 ```
16442
16443 The next example shows you can simply list the data (d) content directly without
16444 specifying it as a function, except where necessary (ie, computed columns). Note
16445 the data element accessor name is capitalized when displayed in the table. You can
16446 also mix in functions as desired or necessary, but you must use the
16447 Object = [Label, Fn] method as shown below.
16448 You may wish to override the following two functions, which are internally used to
16449 translate the column information or function into a displayed header. The first one
16450 is used on the simple "string" column specifier, the second is used to transform the
16451 String(fn) into something displayable. For the Stock example, the function for Change
16452 becomes a header of 'd.close - d.open'.
16453 _chart._doColumnHeaderCapitalize _chart._doColumnHeaderFnToString
16454 You may use your own Object definition, however you must then override
16455 _chart._doColumnHeaderFormat , _chart._doColumnValueFormat
16456 Be aware that fields without numberFormat specification will be displayed just as
16457 they are stored in the data, unformatted.
16458 ```js
16459 chart.columns([
16460 "date", // d["date"], ie, a field accessor; capitalized automatically
16461 "open", // ...
16462 "close", // ...
16463 ["Change", // Specify an Object = [Label, Fn]
16464 function (d) {
16465 return numberFormat(d.close - d.open);
16466 }],
16467 "volume" // d["volume"], ie, a field accessor; capitalized automatically
16468 ]);
16469 ```
16470
16471 A third example, where all fields are specified using the Object = [Label, Fn] method.
16472
16473 ```js
16474 chart.columns([
16475 ["Date", // Specify an Object = [Label, Fn]
16476 function (d) {
16477 return d.date;
16478 }],
16479 ["Open",
16480 function (d) {
16481 return numberFormat(d.open);
16482 }],
16483 ["Close",
16484 function (d) {
16485 return numberFormat(d.close);
16486 }],
16487 ["Change",
16488 function (d) {
16489 return numberFormat(d.close - d.open);
16490 }],
16491 ["Volume",
16492 function (d) {
16493 return d.volume;
16494 }]
16495 ]);
16496 ```
16497
16498 **/
16499 _chart.columns = function (_) {
16500 if (!arguments.length) {
16501 return _columns;
16502 }
16503 _columns = _;
16504 return _chart;
16505 };
16506
16507 /**
16508 #### .sortBy([sortByFunction])
16509 Get or set sort-by function. This function works as a value accessor at row level and returns a
16510 particular field to be sorted by. Default value: identity function
16511
16512 ```js
16513 chart.sortBy(function(d) {
16514 return d.date;
16515 });
16516 ```
16517
16518 **/
16519 _chart.sortBy = function (_) {
16520 if (!arguments.length) {
16521 return _sortBy;
16522 }
16523 _sortBy = _;
16524 return _chart;
16525 };
16526
16527 /**
16528 #### .order([order])
16529 Get or set sort order. Default value: ``` d3.ascending ```
16530
16531 ```js
16532 chart.order(d3.descending);
16533 ```
16534
16535 **/
16536 _chart.order = function (_) {
16537 if (!arguments.length) {
16538 return _order;
16539 }
16540 _order = _;
16541 return _chart;
16542 };
16543
16544 return _chart.anchor(parent, chartGroup);
16545 };
16546
16547 /**
16548 ## Data Grid Widget
16549
16550 Includes: [Base Mixin](#base-mixin)
16551
16552 Data grid is a simple widget designed to list the filtered records, providing
16553 a simple way to define how the items are displayed.
16554
16555 Examples:
16556 * [List of members of the european parliament](http://europarl.me/dc.js/web/ep/index.html)
16557
16558 #### dc.dataGrid(parent[, chartGroup])
16559 Create a data grid widget instance and attach it to the given parent element.
16560
16561 Parameters:
16562 * parent : string | node | selection - any valid
16563 [d3 single selector](https://github.com/mbostock/d3/wiki/Selections#selecting-elements) specifying
16564 a dom block element such as a div; or a dom element or d3 selection.
16565
16566 * chartGroup : string (optional) - name of the chart group this chart instance should be placed in.
16567 Interaction with a chart will only trigger events and redraws within the chart's group.
16568
16569 Returns:
16570 A newly created data grid widget instance
16571
16572 **/
16573 dc.dataGrid = function (parent, chartGroup) {
16574 var LABEL_CSS_CLASS = 'dc-grid-label';
16575 var ITEM_CSS_CLASS = 'dc-grid-item';
16576 var GROUP_CSS_CLASS = 'dc-grid-group';
16577 var GRID_CSS_CLASS = 'dc-grid-top';
16578
16579 var _chart = dc.baseMixin({});
16580
16581 var _size = 999; // shouldn't be needed, but you might
16582 var _html = function (d) { return 'you need to provide an html() handling param: ' + JSON.stringify(d); };
16583 var _sortBy = function (d) {
16584 return d;
16585 };
16586 var _order = d3.ascending;
16587
16588 var _htmlGroup = function (d) {
16589 return '<div class=\'' + GROUP_CSS_CLASS + '\'><h1 class=\'' + LABEL_CSS_CLASS + '\'>' +
16590 _chart.keyAccessor()(d) + '</h1></div>';
16591 };
16592
16593 _chart._doRender = function () {
16594 _chart.selectAll('div.' + GRID_CSS_CLASS).remove();
16595
16596 renderItems(renderGroups());
16597
16598 return _chart;
16599 };
16600
16601 function renderGroups() {
16602 var groups = _chart.root().selectAll('div.' + GRID_CSS_CLASS)
16603 .data(nestEntries(), function (d) {
16604 return _chart.keyAccessor()(d);
16605 });
16606
16607 var itemGroup = groups
16608 .enter()
16609 .append('div')
16610 .attr('class', GRID_CSS_CLASS);
16611
16612 if (_htmlGroup) {
16613 itemGroup
16614 .html(function (d) {
16615 return _htmlGroup(d);
16616 });
16617 }
16618
16619 groups.exit().remove();
16620 return itemGroup;
16621 }
16622
16623 function nestEntries() {
16624 var entries = _chart.dimension().top(_size);
16625
16626 return d3.nest()
16627 .key(_chart.group())
16628 .sortKeys(_order)
16629 .entries(entries.sort(function (a, b) {
16630 return _order(_sortBy(a), _sortBy(b));
16631 }));
16632 }
16633
16634 function renderItems(groups) {
16635 var items = groups.order()
16636 .selectAll('div.' + ITEM_CSS_CLASS)
16637 .data(function (d) {
16638 return d.values;
16639 });
16640
16641 items.enter()
16642 .append('div')
16643 .attr('class', ITEM_CSS_CLASS)
16644 .html(function (d) {
16645 return _html(d);
16646 });
16647
16648 items.exit().remove();
16649
16650 return items;
16651 }
16652
16653 _chart._doRedraw = function () {
16654 return _chart._doRender();
16655 };
16656
16657 /**
16658 #### .size([size])
16659 Get or set the grid size which determines the number of items displayed by the widget.
16660
16661 **/
16662 _chart.size = function (s) {
16663 if (!arguments.length) {
16664 return _size;
16665 }
16666 _size = s;
16667 return _chart;
16668 };
16669
16670 /**
16671 #### .html( function (data) { return '<html>'; })
16672 Get or set the function that formats an item. The data grid widget uses a
16673 function to generate dynamic html. Use your favourite templating engine or
16674 generate the string directly.
16675 ```js
16676 chart.html(function (d) { return '<div class='item '+data.exampleCategory+''>'+data.exampleString+'</div>';});
16677 ```
16678
16679 **/
16680 _chart.html = function (_) {
16681 if (!arguments.length) {
16682 return _html;
16683 }
16684 _html = _;
16685 return _chart;
16686 };
16687
16688 /**
16689 #### .htmlGroup( function (data) { return '<html>'; })
16690 Get or set the function that formats a group label.
16691 ```js
16692 chart.htmlGroup (function (d) { return '<h2>'.d.key . 'with ' . d.values.length .' items</h2>'});
16693 ```
16694
16695 **/
16696 _chart.htmlGroup = function (_) {
16697 if (!arguments.length) {
16698 return _htmlGroup;
16699 }
16700 _htmlGroup = _;
16701 return _chart;
16702 };
16703
16704 /**
16705 #### .sortBy([sortByFunction])
16706 Get or set sort-by function. This function works as a value accessor at the item
16707 level and returns a particular field to be sorted.
16708 by. Default: identity function
16709
16710 ```js
16711 chart.sortBy(function(d) {
16712 return d.date;
16713 });
16714 ```
16715
16716 **/
16717 _chart.sortBy = function (_) {
16718 if (!arguments.length) {
16719 return _sortBy;
16720 }
16721 _sortBy = _;
16722 return _chart;
16723 };
16724
16725 /**
16726 #### .order([order])
16727 Get or set sort order function. Default value: ``` d3.ascending ```
16728
16729 ```js
16730 chart.order(d3.descending);
16731 ```
16732
16733 **/
16734 _chart.order = function (_) {
16735 if (!arguments.length) {
16736 return _order;
16737 }
16738 _order = _;
16739 return _chart;
16740 };
16741
16742 return _chart.anchor(parent, chartGroup);
16743 };
16744
16745 /**
16746 ## Bubble Chart
16747 Includes: [Bubble Mixin](#bubble-mixin), [Coordinate Grid Mixin](#coordinate-grid-mixin)
16748
16749 A concrete implementation of a general purpose bubble chart that allows data visualization using the
16750 following dimensions:
16751
16752 * x axis position
16753 * y axis position
16754 * bubble radius
16755 * color
16756
16757 Examples:
16758 * [Nasdaq 100 Index](http://dc-js.github.com/dc.js/)
16759 * [US Venture Capital Landscape 2011](http://dc-js.github.com/dc.js/vc/index.html)
16760 #### dc.bubbleChart(parent[, chartGroup])
16761 Create a bubble chart instance and attach it to the given parent element.
16762
16763 Parameters:
16764 * parent : string | node | selection | compositeChart - any valid
16765 [d3 single selector](https://github.com/mbostock/d3/wiki/Selections#selecting-elements) specifying
16766 a dom block element such as a div; or a dom element or d3 selection.
16767 * chartGroup : string (optional) - name of the chart group this chart instance should be placed in.
16768 Interaction with a chart will only trigger events and redraws within the chart's group.
16769
16770 Returns:
16771 A newly created bubble chart instance
16772
16773 ```js
16774 // create a bubble chart under #chart-container1 element using the default global chart group
16775 var bubbleChart1 = dc.bubbleChart('#chart-container1');
16776 // create a bubble chart under #chart-container2 element using chart group A
16777 var bubbleChart2 = dc.bubbleChart('#chart-container2', 'chartGroupA');
16778 ```
16779
16780 **/
16781 dc.bubbleChart = function (parent, chartGroup) {
16782 var _chart = dc.bubbleMixin(dc.coordinateGridMixin({}));
16783
16784 var _elasticRadius = false;
16785
16786 _chart.transitionDuration(750);
16787
16788 var bubbleLocator = function (d) {
16789 return 'translate(' + (bubbleX(d)) + ',' + (bubbleY(d)) + ')';
16790 };
16791
16792 /**
16793 #### .elasticRadius([boolean])
16794 Turn on or off the elastic bubble radius feature, or return the value of the flag. If this
16795 feature is turned on, then bubble radii will be automatically rescaled to fit the chart better.
16796
16797 **/
16798 _chart.elasticRadius = function (_) {
16799 if (!arguments.length) {
16800 return _elasticRadius;
16801 }
16802 _elasticRadius = _;
16803 return _chart;
16804 };
16805
16806 _chart.plotData = function () {
16807 if (_elasticRadius) {
16808 _chart.r().domain([_chart.rMin(), _chart.rMax()]);
16809 }
16810
16811 _chart.r().range([_chart.MIN_RADIUS, _chart.xAxisLength() * _chart.maxBubbleRelativeSize()]);
16812
16813 var bubbleG = _chart.chartBodyG().selectAll('g.' + _chart.BUBBLE_NODE_CLASS)
16814 .data(_chart.data(), function (d) { return d.key; });
16815
16816 renderNodes(bubbleG);
16817
16818 updateNodes(bubbleG);
16819
16820 removeNodes(bubbleG);
16821
16822 _chart.fadeDeselectedArea();
16823 };
16824
16825 function renderNodes(bubbleG) {
16826 var bubbleGEnter = bubbleG.enter().append('g');
16827
16828 bubbleGEnter
16829 .attr('class', _chart.BUBBLE_NODE_CLASS)
16830 .attr('transform', bubbleLocator)
16831 .append('circle').attr('class', function (d, i) {
16832 return _chart.BUBBLE_CLASS + ' _' + i;
16833 })
16834 .on('click', _chart.onClick)
16835 .attr('fill', _chart.getColor)
16836 .attr('r', 0);
16837 dc.transition(bubbleG, _chart.transitionDuration())
16838 .selectAll('circle.' + _chart.BUBBLE_CLASS)
16839 .attr('r', function (d) {
16840 return _chart.bubbleR(d);
16841 })
16842 .attr('opacity', function (d) {
16843 return (_chart.bubbleR(d) > 0) ? 1 : 0;
16844 });
16845
16846 _chart._doRenderLabel(bubbleGEnter);
16847
16848 _chart._doRenderTitles(bubbleGEnter);
16849 }
16850
16851 function updateNodes(bubbleG) {
16852 dc.transition(bubbleG, _chart.transitionDuration())
16853 .attr('transform', bubbleLocator)
16854 .selectAll('circle.' + _chart.BUBBLE_CLASS)
16855 .attr('fill', _chart.getColor)
16856 .attr('r', function (d) {
16857 return _chart.bubbleR(d);
16858 })
16859 .attr('opacity', function (d) {
16860 return (_chart.bubbleR(d) > 0) ? 1 : 0;
16861 });
16862
16863 _chart.doUpdateLabels(bubbleG);
16864 _chart.doUpdateTitles(bubbleG);
16865 }
16866
16867 function removeNodes(bubbleG) {
16868 bubbleG.exit().remove();
16869 }
16870
16871 function bubbleX(d) {
16872 var x = _chart.x()(_chart.keyAccessor()(d));
16873 if (isNaN(x)) {
16874 x = 0;
16875 }
16876 return x;
16877 }
16878
16879 function bubbleY(d) {
16880 var y = _chart.y()(_chart.valueAccessor()(d));
16881 if (isNaN(y)) {
16882 y = 0;
16883 }
16884 return y;
16885 }
16886
16887 _chart.renderBrush = function () {
16888 // override default x axis brush from parent chart
16889 };
16890
16891 _chart.redrawBrush = function () {
16892 // override default x axis brush from parent chart
16893 _chart.fadeDeselectedArea();
16894 };
16895
16896 return _chart.anchor(parent, chartGroup);
16897 };
16898
16899 /**
16900 ## Composite Chart
16901 Includes: [Coordinate Grid Mixin](#coordinate-grid-mixin)
16902
16903 Composite charts are a special kind of chart that render multiple charts on the same Coordinate
16904 Grid. You can overlay (compose) different bar/line/area charts in a single composite chart to
16905 achieve some quite flexible charting effects.
16906 #### dc.compositeChart(parent[, chartGroup])
16907 Create a composite chart instance and attach it to the given parent element.
16908
16909 Parameters:
16910 * parent : string | node | selection - any valid
16911 [d3 single selector](https://github.com/mbostock/d3/wiki/Selections#selecting-elements) specifying
16912 a dom block element such as a div; or a dom element or d3 selection.
16913 * chartGroup : string (optional) - name of the chart group this chart instance should be placed in.
16914 Interaction with a chart will only trigger events and redraws within the chart's group.
16915
16916 Returns:
16917 A newly created composite chart instance
16918
16919 ```js
16920 // create a composite chart under #chart-container1 element using the default global chart group
16921 var compositeChart1 = dc.compositeChart('#chart-container1');
16922 // create a composite chart under #chart-container2 element using chart group A
16923 var compositeChart2 = dc.compositeChart('#chart-container2', 'chartGroupA');
16924 ```
16925
16926 **/
16927 dc.compositeChart = function (parent, chartGroup) {
16928
16929 var SUB_CHART_CLASS = 'sub';
16930 var DEFAULT_RIGHT_Y_AXIS_LABEL_PADDING = 12;
16931
16932 var _chart = dc.coordinateGridMixin({});
16933 var _children = [];
16934
16935 var _childOptions = {};
16936
16937 var _shareColors = false,
16938 _shareTitle = true;
16939
16940 var _rightYAxis = d3.svg.axis(),
16941 _rightYAxisLabel = 0,
16942 _rightYAxisLabelPadding = DEFAULT_RIGHT_Y_AXIS_LABEL_PADDING,
16943 _rightY,
16944 _rightAxisGridLines = false;
16945
16946 _chart._mandatoryAttributes([]);
16947 _chart.transitionDuration(500);
16948
16949 dc.override(_chart, '_generateG', function () {
16950 var g = this.__generateG();
16951
16952 for (var i = 0; i < _children.length; ++i) {
16953 var child = _children[i];
16954
16955 generateChildG(child, i);
16956
16957 if (!child.dimension()) {
16958 child.dimension(_chart.dimension());
16959 }
16960 if (!child.group()) {
16961 child.group(_chart.group());
16962 }
16963
16964 child.chartGroup(_chart.chartGroup());
16965 child.svg(_chart.svg());
16966 child.xUnits(_chart.xUnits());
16967 child.transitionDuration(_chart.transitionDuration());
16968 child.brushOn(_chart.brushOn());
16969 child.renderTitle(_chart.renderTitle());
16970 }
16971
16972 return g;
16973 });
16974
16975 _chart._brushing = function () {
16976 var extent = _chart.extendBrush();
16977 var brushIsEmpty = _chart.brushIsEmpty(extent);
16978
16979 for (var i = 0; i < _children.length; ++i) {
16980 _children[i].filter(null);
16981 if (!brushIsEmpty) {
16982 _children[i].filter(extent);
16983 }
16984 }
16985 };
16986
16987 _chart._prepareYAxis = function () {
16988 if (leftYAxisChildren().length !== 0) { prepareLeftYAxis(); }
16989 if (rightYAxisChildren().length !== 0) { prepareRightYAxis(); }
16990
16991 if (leftYAxisChildren().length > 0 && !_rightAxisGridLines) {
16992 _chart._renderHorizontalGridLinesForAxis(_chart.g(), _chart.y(), _chart.yAxis());
16993 }
16994 else if (rightYAxisChildren().length > 0) {
16995 _chart._renderHorizontalGridLinesForAxis(_chart.g(), _rightY, _rightYAxis);
16996 }
16997 };
16998
16999 _chart.renderYAxis = function () {
17000 if (leftYAxisChildren().length !== 0) {
17001 _chart.renderYAxisAt('y', _chart.yAxis(), _chart.margins().left);
17002 _chart.renderYAxisLabel('y', _chart.yAxisLabel(), -90);
17003 }
17004
17005 if (rightYAxisChildren().length !== 0) {
17006 _chart.renderYAxisAt('yr', _chart.rightYAxis(), _chart.width() - _chart.margins().right);
17007 _chart.renderYAxisLabel('yr', _chart.rightYAxisLabel(), 90, _chart.width() - _rightYAxisLabelPadding);
17008 }
17009 };
17010
17011 function prepareRightYAxis() {
17012 if (_chart.rightY() === undefined || _chart.elasticY()) {
17013 _chart.rightY(d3.scale.linear());
17014 _chart.rightY().domain([rightYAxisMin(), rightYAxisMax()]).rangeRound([_chart.yAxisHeight(), 0]);
17015 }
17016
17017 _chart.rightY().range([_chart.yAxisHeight(), 0]);
17018 _chart.rightYAxis(_chart.rightYAxis().scale(_chart.rightY()));
17019
17020 _chart.rightYAxis().orient('right');
17021 }
17022
17023 function prepareLeftYAxis() {
17024 if (_chart.y() === undefined || _chart.elasticY()) {
17025 _chart.y(d3.scale.linear());
17026 _chart.y().domain([yAxisMin(), yAxisMax()]).rangeRound([_chart.yAxisHeight(), 0]);
17027 }
17028
17029 _chart.y().range([_chart.yAxisHeight(), 0]);
17030 _chart.yAxis(_chart.yAxis().scale(_chart.y()));
17031
17032 _chart.yAxis().orient('left');
17033 }
17034
17035 function generateChildG(child, i) {
17036 child._generateG(_chart.g());
17037 child.g().attr('class', SUB_CHART_CLASS + ' _' + i);
17038 }
17039
17040 _chart.plotData = function () {
17041 for (var i = 0; i < _children.length; ++i) {
17042 var child = _children[i];
17043
17044 if (!child.g()) {
17045 generateChildG(child, i);
17046 }
17047
17048 if (_shareColors) {
17049 child.colors(_chart.colors());
17050 }
17051
17052 child.x(_chart.x());
17053
17054 child.xAxis(_chart.xAxis());
17055
17056 if (child.useRightYAxis()) {
17057 child.y(_chart.rightY());
17058 child.yAxis(_chart.rightYAxis());
17059 }
17060 else {
17061 child.y(_chart.y());
17062 child.yAxis(_chart.yAxis());
17063 }
17064
17065 child.plotData();
17066
17067 child._activateRenderlets();
17068 }
17069 };
17070
17071 /**
17072 #### .useRightAxisGridLines(bool)
17073 Get or set whether to draw gridlines from the right y axis. Drawing from the left y axis is the
17074 default behavior. This option is only respected when subcharts with both left and right y-axes
17075 are present.
17076 **/
17077 _chart.useRightAxisGridLines = function (_) {
17078 if (!arguments) {
17079 return _rightAxisGridLines;
17080 }
17081
17082 _rightAxisGridLines = _;
17083 return _chart;
17084 };
17085
17086 /**
17087 #### .childOptions({object})
17088 Get or set chart-specific options for all child charts. This is equivalent to calling `.options`
17089 on each child chart.
17090 **/
17091 _chart.childOptions = function (_) {
17092 if (!arguments.length) {
17093 return _childOptions;
17094 }
17095 _childOptions = _;
17096 _children.forEach(function (child) {
17097 child.options(_childOptions);
17098 });
17099 return _chart;
17100 };
17101
17102 _chart.fadeDeselectedArea = function () {
17103 for (var i = 0; i < _children.length; ++i) {
17104 var child = _children[i];
17105 child.brush(_chart.brush());
17106 child.fadeDeselectedArea();
17107 }
17108 };
17109
17110 /**
17111 #### .rightYAxisLabel([labelText])
17112 Set or get the right y axis label.
17113 **/
17114 _chart.rightYAxisLabel = function (_, padding) {
17115 if (!arguments.length) {
17116 return _rightYAxisLabel;
17117 }
17118 _rightYAxisLabel = _;
17119 _chart.margins().right -= _rightYAxisLabelPadding;
17120 _rightYAxisLabelPadding = (padding === undefined) ? DEFAULT_RIGHT_Y_AXIS_LABEL_PADDING : padding;
17121 _chart.margins().right += _rightYAxisLabelPadding;
17122 return _chart;
17123 };
17124
17125 /**
17126 #### .compose(subChartArray)
17127 Combine the given charts into one single composite coordinate grid chart.
17128
17129 ```js
17130 // compose the given charts in the array into one single composite chart
17131 moveChart.compose([
17132 // when creating sub-chart you need to pass in the parent chart
17133 dc.lineChart(moveChart)
17134 .group(indexAvgByMonthGroup) // if group is missing then parent's group will be used
17135 .valueAccessor(function (d){return d.value.avg;})
17136 // most of the normal functions will continue to work in a composed chart
17137 .renderArea(true)
17138 .stack(monthlyMoveGroup, function (d){return d.value;})
17139 .title(function (d){
17140 var value = d.value.avg?d.value.avg:d.value;
17141 if(isNaN(value)) value = 0;
17142 return dateFormat(d.key) + '\n' + numberFormat(value);
17143 }),
17144 dc.barChart(moveChart)
17145 .group(volumeByMonthGroup)
17146 .centerBar(true)
17147 ]);
17148 ```
17149
17150 **/
17151 _chart.compose = function (charts) {
17152 _children = charts;
17153 _children.forEach(function (child) {
17154 child.height(_chart.height());
17155 child.width(_chart.width());
17156 child.margins(_chart.margins());
17157
17158 if (_shareTitle) {
17159 child.title(_chart.title());
17160 }
17161
17162 child.options(_childOptions);
17163 });
17164 return _chart;
17165 };
17166
17167 /**
17168 #### .children()
17169 Returns the child charts which are composed into the composite chart.
17170 **/
17171
17172 _chart.children = function () {
17173 return _children;
17174 };
17175
17176 /**
17177 #### .shareColors([boolean])
17178 Get or set color sharing for the chart. If set, the `.colors()` value from this chart
17179 will be shared with composed children. Additionally if the child chart implements
17180 Stackable and has not set a custom .colorAccessor, then it will generate a color
17181 specific to its order in the composition.
17182 **/
17183 _chart.shareColors = function (_) {
17184 if (!arguments.length) {
17185 return _shareColors;
17186 }
17187 _shareColors = _;
17188 return _chart;
17189 };
17190
17191 /**
17192 #### .shareTitle([[boolean])
17193 Get or set title sharing for the chart. If set, the `.title()` value from this chart will be
17194 shared with composed children. Default value is true.
17195 **/
17196 _chart.shareTitle = function (_) {
17197 if (!arguments.length) {
17198 return _shareTitle;
17199 }
17200 _shareTitle = _;
17201 return _chart;
17202 };
17203
17204 /**
17205 #### .rightY([yScale])
17206 Get or set the y scale for the right axis. The right y scale is typically automatically
17207 generated by the chart implementation.
17208
17209 **/
17210 _chart.rightY = function (_) {
17211 if (!arguments.length) {
17212 return _rightY;
17213 }
17214 _rightY = _;
17215 return _chart;
17216 };
17217
17218 function leftYAxisChildren() {
17219 return _children.filter(function (child) {
17220 return !child.useRightYAxis();
17221 });
17222 }
17223
17224 function rightYAxisChildren() {
17225 return _children.filter(function (child) {
17226 return child.useRightYAxis();
17227 });
17228 }
17229
17230 function getYAxisMin(charts) {
17231 return charts.map(function (c) {
17232 return c.yAxisMin();
17233 });
17234 }
17235
17236 delete _chart.yAxisMin;
17237 function yAxisMin() {
17238 return d3.min(getYAxisMin(leftYAxisChildren()));
17239 }
17240
17241 function rightYAxisMin() {
17242 return d3.min(getYAxisMin(rightYAxisChildren()));
17243 }
17244
17245 function getYAxisMax(charts) {
17246 return charts.map(function (c) {
17247 return c.yAxisMax();
17248 });
17249 }
17250
17251 delete _chart.yAxisMax;
17252 function yAxisMax() {
17253 return dc.utils.add(d3.max(getYAxisMax(leftYAxisChildren())), _chart.yAxisPadding());
17254 }
17255
17256 function rightYAxisMax() {
17257 return dc.utils.add(d3.max(getYAxisMax(rightYAxisChildren())), _chart.yAxisPadding());
17258 }
17259
17260 function getAllXAxisMinFromChildCharts() {
17261 return _children.map(function (c) {
17262 return c.xAxisMin();
17263 });
17264 }
17265
17266 dc.override(_chart, 'xAxisMin', function () {
17267 return dc.utils.subtract(d3.min(getAllXAxisMinFromChildCharts()), _chart.xAxisPadding());
17268 });
17269
17270 function getAllXAxisMaxFromChildCharts() {
17271 return _children.map(function (c) {
17272 return c.xAxisMax();
17273 });
17274 }
17275
17276 dc.override(_chart, 'xAxisMax', function () {
17277 return dc.utils.add(d3.max(getAllXAxisMaxFromChildCharts()), _chart.xAxisPadding());
17278 });
17279
17280 _chart.legendables = function () {
17281 return _children.reduce(function (items, child) {
17282 if (_shareColors) {
17283 child.colors(_chart.colors());
17284 }
17285 items.push.apply(items, child.legendables());
17286 return items;
17287 }, []);
17288 };
17289
17290 _chart.legendHighlight = function (d) {
17291 for (var j = 0; j < _children.length; ++j) {
17292 var child = _children[j];
17293 child.legendHighlight(d);
17294 }
17295 };
17296
17297 _chart.legendReset = function (d) {
17298 for (var j = 0; j < _children.length; ++j) {
17299 var child = _children[j];
17300 child.legendReset(d);
17301 }
17302 };
17303
17304 _chart.legendToggle = function () {
17305 console.log('composite should not be getting legendToggle itself');
17306 };
17307
17308 /**
17309 #### .rightYAxis([yAxis])
17310 Set or get the right y axis used by the composite chart. This function is most useful when y
17311 axis customization is required. The y axis in dc.js is an instance of a [d3 axis
17312 object](https://github.com/mbostock/d3/wiki/SVG-Axes#wiki-_axis) therefore it supports any valid
17313 d3 axis manipulation. **Caution**: The y axis is usually generated internally by dc;
17314 resetting it may cause unexpected results.
17315 ```jså
17316 // customize y axis tick format
17317 chart.rightYAxis().tickFormat(function (v) {return v + '%';});
17318 // customize y axis tick values
17319 chart.rightYAxis().tickValues([0, 100, 200, 300]);
17320 ```
17321
17322 **/
17323 _chart.rightYAxis = function (rightYAxis) {
17324 if (!arguments.length) {
17325 return _rightYAxis;
17326 }
17327 _rightYAxis = rightYAxis;
17328 return _chart;
17329 };
17330
17331 return _chart.anchor(parent, chartGroup);
17332 };
17333
17334 /**
17335 ## Series Chart
17336
17337 Includes: [Composite Chart](#composite chart)
17338
17339 A series chart is a chart that shows multiple series of data overlaid on one chart, where the
17340 series is specified in the data. It is a specialization of Composite Chart and inherits all
17341 composite features other than recomposing the chart.
17342
17343 #### dc.seriesChart(parent[, chartGroup])
17344 Create a series chart instance and attach it to the given parent element.
17345
17346 Parameters:
17347 * parent : string | node | selection - any valid
17348 [d3 single selector](https://github.com/mbostock/d3/wiki/Selections#selecting-elements) specifying
17349 a dom block element such as a div; or a dom element or d3 selection.
17350
17351 * chartGroup : string (optional) - name of the chart group this chart instance should be placed in.
17352 Interaction with a chart will only trigger events and redraws within the chart's group.
17353
17354 Returns:
17355 A newly created series chart instance
17356
17357 ```js
17358 // create a series chart under #chart-container1 element using the default global chart group
17359 var seriesChart1 = dc.seriesChart("#chart-container1");
17360 // create a series chart under #chart-container2 element using chart group A
17361 var seriesChart2 = dc.seriesChart("#chart-container2", "chartGroupA");
17362 ```
17363
17364 **/
17365 dc.seriesChart = function (parent, chartGroup) {
17366 var _chart = dc.compositeChart(parent, chartGroup);
17367
17368 function keySort(a, b) {
17369 return d3.ascending(_chart.keyAccessor()(a), _chart.keyAccessor()(b));
17370 }
17371
17372 var _charts = {};
17373 var _chartFunction = dc.lineChart;
17374 var _seriesAccessor;
17375 var _seriesSort = d3.ascending;
17376 var _valueSort = keySort;
17377
17378 _chart._mandatoryAttributes().push('seriesAccessor', 'chart');
17379 _chart.shareColors(true);
17380
17381 _chart._preprocessData = function () {
17382 var keep = [];
17383 var childrenChanged;
17384 var nester = d3.nest().key(_seriesAccessor);
17385 if (_seriesSort) {
17386 nester.sortKeys(_seriesSort);
17387 }
17388 if (_valueSort) {
17389 nester.sortValues(_valueSort);
17390 }
17391 var nesting = nester.entries(_chart.data());
17392 var children =
17393 nesting.map(function (sub, i) {
17394 var subChart = _charts[sub.key] || _chartFunction.call(_chart, _chart, chartGroup, sub.key, i);
17395 if (!_charts[sub.key]) {
17396 childrenChanged = true;
17397 }
17398 _charts[sub.key] = subChart;
17399 keep.push(sub.key);
17400 return subChart
17401 .dimension(_chart.dimension())
17402 .group({all:d3.functor(sub.values)}, sub.key)
17403 .keyAccessor(_chart.keyAccessor())
17404 .valueAccessor(_chart.valueAccessor())
17405 .brushOn(_chart.brushOn());
17406 });
17407 // this works around the fact compositeChart doesn't really
17408 // have a removal interface
17409 Object.keys(_charts)
17410 .filter(function (c) {return keep.indexOf(c) === -1;})
17411 .forEach(function (c) {
17412 clearChart(c);
17413 childrenChanged = true;
17414 });
17415 _chart._compose(children);
17416 if (childrenChanged && _chart.legend()) {
17417 _chart.legend().render();
17418 }
17419 };
17420
17421 function clearChart(c) {
17422 if (_charts[c].g()) {
17423 _charts[c].g().remove();
17424 }
17425 delete _charts[c];
17426 }
17427
17428 function resetChildren() {
17429 Object.keys(_charts).map(clearChart);
17430 _charts = {};
17431 }
17432
17433 /**
17434 #### .chart([function])
17435 Get or set the chart function, which generates the child charts. Default: dc.lineChart
17436
17437 ```
17438 // put interpolation on the line charts used for the series
17439 chart.chart(function(c) { return dc.lineChart(c).interpolate('basis'); })
17440 // do a scatter series chart
17441 chart.chart(dc.scatterPlot)
17442 ```
17443
17444 **/
17445 _chart.chart = function (_) {
17446 if (!arguments.length) {
17447 return _chartFunction;
17448 }
17449 _chartFunction = _;
17450 resetChildren();
17451 return _chart;
17452 };
17453
17454 /**
17455 #### .seriesAccessor([accessor])
17456 Get or set accessor function for the displayed series. Given a datum, this function
17457 should return the series that datum belongs to.
17458 **/
17459 _chart.seriesAccessor = function (_) {
17460 if (!arguments.length) {
17461 return _seriesAccessor;
17462 }
17463 _seriesAccessor = _;
17464 resetChildren();
17465 return _chart;
17466 };
17467
17468 /**
17469 #### .seriesSort([sortFunction])
17470 Get or set a function to sort the list of series by, given series values.
17471
17472 Example:
17473 ```
17474 chart.seriesSort(d3.descending);
17475 ```
17476 **/
17477 _chart.seriesSort = function (_) {
17478 if (!arguments.length) {
17479 return _seriesSort;
17480 }
17481 _seriesSort = _;
17482 resetChildren();
17483 return _chart;
17484 };
17485
17486 /**
17487 #### .valueSort([sortFunction])
17488 Get or set a function to sort each series values by. By default this is the key accessor which,
17489 for example, will ensure a lineChart series connects its points in increasing key/x order,
17490 rather than haphazardly.
17491 **/
17492 _chart.valueSort = function (_) {
17493 if (!arguments.length) {
17494 return _valueSort;
17495 }
17496 _valueSort = _;
17497 resetChildren();
17498 return _chart;
17499 };
17500
17501 // make compose private
17502 _chart._compose = _chart.compose;
17503 delete _chart.compose;
17504
17505 return _chart;
17506 };
17507
17508 /**
17509 ## Geo Choropleth Chart
17510 Includes: [Color Mixin](#color-mixin), [Base Mixin](#base-mixin)
17511
17512 The geo choropleth chart is designed as an easy way to create a crossfilter driven choropleth map
17513 from GeoJson data. This chart implementation was inspired by [the great d3 choropleth
17514 example](http://bl.ocks.org/4060606).
17515
17516 Examples:
17517 * [US Venture Capital Landscape 2011](http://dc-js.github.com/dc.js/vc/index.html)
17518 #### dc.geoChoroplethChart(parent[, chartGroup])
17519 Create a choropleth chart instance and attach it to the given parent element.
17520
17521 Parameters:
17522 * parent : string | node | selection - any valid
17523 [d3 single selector](https://github.com/mbostock/d3/wiki/Selections#selecting-elements) specifying
17524 a dom block element such as a div; or a dom element or d3 selection.
17525
17526 * chartGroup : string (optional) - name of the chart group this chart instance should be placed in.
17527 Interaction with a chart will only trigger events and redraws within the chart's group.
17528
17529 Returns:
17530 A newly created choropleth chart instance
17531
17532 ```js
17533 // create a choropleth chart under '#us-chart' element using the default global chart group
17534 var chart1 = dc.geoChoroplethChart('#us-chart');
17535 // create a choropleth chart under '#us-chart2' element using chart group A
17536 var chart2 = dc.compositeChart('#us-chart2', 'chartGroupA');
17537 ```
17538
17539 **/
17540 dc.geoChoroplethChart = function (parent, chartGroup) {
17541 var _chart = dc.colorMixin(dc.baseMixin({}));
17542
17543 _chart.colorAccessor(function (d) {
17544 return d || 0;
17545 });
17546
17547 var _geoPath = d3.geo.path();
17548 var _projectionFlag;
17549
17550 var _geoJsons = [];
17551
17552 _chart._doRender = function () {
17553 _chart.resetSvg();
17554 for (var layerIndex = 0; layerIndex < _geoJsons.length; ++layerIndex) {
17555 var states = _chart.svg().append('g')
17556 .attr('class', 'layer' + layerIndex);
17557
17558 var regionG = states.selectAll('g.' + geoJson(layerIndex).name)
17559 .data(geoJson(layerIndex).data)
17560 .enter()
17561 .append('g')
17562 .attr('class', geoJson(layerIndex).name);
17563
17564 regionG
17565 .append('path')
17566 .attr('fill', 'white')
17567 .attr('d', _geoPath);
17568
17569 regionG.append('title');
17570
17571 plotData(layerIndex);
17572 }
17573 _projectionFlag = false;
17574 };
17575
17576 function plotData(layerIndex) {
17577 var data = generateLayeredData();
17578
17579 if (isDataLayer(layerIndex)) {
17580 var regionG = renderRegionG(layerIndex);
17581
17582 renderPaths(regionG, layerIndex, data);
17583
17584 renderTitle(regionG, layerIndex, data);
17585 }
17586 }
17587
17588 function generateLayeredData() {
17589 var data = {};
17590 var groupAll = _chart.data();
17591 for (var i = 0; i < groupAll.length; ++i) {
17592 data[_chart.keyAccessor()(groupAll[i])] = _chart.valueAccessor()(groupAll[i]);
17593 }
17594 return data;
17595 }
17596
17597 function isDataLayer(layerIndex) {
17598 return geoJson(layerIndex).keyAccessor;
17599 }
17600
17601 function renderRegionG(layerIndex) {
17602 var regionG = _chart.svg()
17603 .selectAll(layerSelector(layerIndex))
17604 .classed('selected', function (d) {
17605 return isSelected(layerIndex, d);
17606 })
17607 .classed('deselected', function (d) {
17608 return isDeselected(layerIndex, d);
17609 })
17610 .attr('class', function (d) {
17611 var layerNameClass = geoJson(layerIndex).name;
17612 var regionClass = dc.utils.nameToId(geoJson(layerIndex).keyAccessor(d));
17613 var baseClasses = layerNameClass + ' ' + regionClass;
17614 if (isSelected(layerIndex, d)) {
17615 baseClasses += ' selected';
17616 }
17617 if (isDeselected(layerIndex, d)) {
17618 baseClasses += ' deselected';
17619 }
17620 return baseClasses;
17621 });
17622 return regionG;
17623 }
17624
17625 function layerSelector(layerIndex) {
17626 return 'g.layer' + layerIndex + ' g.' + geoJson(layerIndex).name;
17627 }
17628
17629 function isSelected(layerIndex, d) {
17630 return _chart.hasFilter() && _chart.hasFilter(getKey(layerIndex, d));
17631 }
17632
17633 function isDeselected(layerIndex, d) {
17634 return _chart.hasFilter() && !_chart.hasFilter(getKey(layerIndex, d));
17635 }
17636
17637 function getKey(layerIndex, d) {
17638 return geoJson(layerIndex).keyAccessor(d);
17639 }
17640
17641 function geoJson(index) {
17642 return _geoJsons[index];
17643 }
17644
17645 function renderPaths(regionG, layerIndex, data) {
17646 var paths = regionG
17647 .select('path')
17648 .attr('fill', function () {
17649 var currentFill = d3.select(this).attr('fill');
17650 if (currentFill) {
17651 return currentFill;
17652 }
17653 return 'none';
17654 })
17655 .on('click', function (d) {
17656 return _chart.onClick(d, layerIndex);
17657 });
17658
17659 dc.transition(paths, _chart.transitionDuration()).attr('fill', function (d, i) {
17660 return _chart.getColor(data[geoJson(layerIndex).keyAccessor(d)], i);
17661 });
17662 }
17663
17664 _chart.onClick = function (d, layerIndex) {
17665 var selectedRegion = geoJson(layerIndex).keyAccessor(d);
17666 dc.events.trigger(function () {
17667 _chart.filter(selectedRegion);
17668 _chart.redrawGroup();
17669 });
17670 };
17671
17672 function renderTitle(regionG, layerIndex, data) {
17673 if (_chart.renderTitle()) {
17674 regionG.selectAll('title').text(function (d) {
17675 var key = getKey(layerIndex, d);
17676 var value = data[key];
17677 return _chart.title()({key: key, value: value});
17678 });
17679 }
17680 }
17681
17682 _chart._doRedraw = function () {
17683 for (var layerIndex = 0; layerIndex < _geoJsons.length; ++layerIndex) {
17684 plotData(layerIndex);
17685 if (_projectionFlag) {
17686 _chart.svg().selectAll('g.' + geoJson(layerIndex).name + ' path').attr('d', _geoPath);
17687 }
17688 }
17689 _projectionFlag = false;
17690 };
17691
17692 /**
17693 #### .overlayGeoJson(json, name, keyAccessor) - **mandatory**
17694 Use this function to insert a new GeoJson map layer. This function can be invoked multiple times
17695 if you have multiple GeoJson data layers to render on top of each other. If you overlay multiple
17696 layers with the same name the new overlay will override the existing one.
17697
17698 Parameters:
17699 * json - GeoJson feed
17700 * name - name of the layer
17701 * keyAccessor - accessor function used to extract 'key' from the GeoJson data. The key extracted by
17702 this function should match the keys returned by the crossfilter groups.
17703
17704 ```js
17705 // insert a layer for rendering US states
17706 chart.overlayGeoJson(statesJson.features, 'state', function(d) {
17707 return d.properties.name;
17708 });
17709 ```
17710
17711 **/
17712 _chart.overlayGeoJson = function (json, name, keyAccessor) {
17713 for (var i = 0; i < _geoJsons.length; ++i) {
17714 if (_geoJsons[i].name === name) {
17715 _geoJsons[i].data = json;
17716 _geoJsons[i].keyAccessor = keyAccessor;
17717 return _chart;
17718 }
17719 }
17720 _geoJsons.push({name: name, data: json, keyAccessor: keyAccessor});
17721 return _chart;
17722 };
17723
17724 /**
17725 #### .projection(projection)
17726 Set custom geo projection function. See the available [d3 geo projection
17727 functions](https://github.com/mbostock/d3/wiki/Geo-Projections). Default value: albersUsa.
17728
17729 **/
17730 _chart.projection = function (projection) {
17731 _geoPath.projection(projection);
17732 _projectionFlag = true;
17733 return _chart;
17734 };
17735
17736 /**
17737 #### .geoJsons()
17738 Returns all GeoJson layers currently registered with this chart. The returned array is a
17739 reference to this chart's internal data structure, so any modification to this array will also
17740 modify this chart's internal registration.
17741
17742 Returns an array of objects containing fields {name, data, accessor}
17743
17744 **/
17745 _chart.geoJsons = function () {
17746 return _geoJsons;
17747 };
17748
17749 /**
17750 #### .geoPath()
17751 Returns the [d3.geo.path](https://github.com/mbostock/d3/wiki/Geo-Paths#path) object used to
17752 render the projection and features. Can be useful for figuring out the bounding box of the
17753 feature set and thus a way to calculate scale and translation for the projection.
17754
17755 **/
17756 _chart.geoPath = function () {
17757 return _geoPath;
17758 };
17759
17760 /**
17761 #### .removeGeoJson(name)
17762 Remove a GeoJson layer from this chart by name
17763
17764 **/
17765 _chart.removeGeoJson = function (name) {
17766 var geoJsons = [];
17767
17768 for (var i = 0; i < _geoJsons.length; ++i) {
17769 var layer = _geoJsons[i];
17770 if (layer.name !== name) {
17771 geoJsons.push(layer);
17772 }
17773 }
17774
17775 _geoJsons = geoJsons;
17776
17777 return _chart;
17778 };
17779
17780 return _chart.anchor(parent, chartGroup);
17781 };
17782
17783 /**
17784 ## Bubble Overlay Chart
17785 Includes: [Bubble Mixin](#bubble-mixin), [Base Mixin](#base-mixin)
17786
17787 The bubble overlay chart is quite different from the typical bubble chart. With the bubble overlay
17788 chart you can arbitrarily place bubbles on an existing svg or bitmap image, thus changing the
17789 typical x and y positioning while retaining the capability to visualize data using bubble radius
17790 and coloring.
17791
17792 Examples:
17793 * [Canadian City Crime Stats](http://dc-js.github.com/dc.js/crime/index.html)
17794 #### dc.bubbleOverlay(parent[, chartGroup])
17795 Create a bubble overlay chart instance and attach it to the given parent element.
17796
17797 Parameters:
17798 * parent : string | node | selection - any valid
17799 [d3 single selector](https://github.com/mbostock/d3/wiki/Selections#selecting-elements) specifying
17800 a dom block element such as a div; or a dom element or d3 selection.
17801 off-screen. Typically this element should also be the parent of the underlying image.
17802 * chartGroup : string (optional) - name of the chart group this chart instance should be placed in.
17803 Interaction with a chart will only trigger events and redraws within the chart's group.
17804
17805 Returns:
17806 A newly created bubble overlay chart instance
17807
17808 ```js
17809 // create a bubble overlay chart on top of the '#chart-container1 svg' element using the default global chart group
17810 var bubbleChart1 = dc.bubbleOverlayChart('#chart-container1').svg(d3.select('#chart-container1 svg'));
17811 // create a bubble overlay chart on top of the '#chart-container2 svg' element using chart group A
17812 var bubbleChart2 = dc.compositeChart('#chart-container2', 'chartGroupA').svg(d3.select('#chart-container2 svg'));
17813 ```
17814 #### .svg(imageElement) - **mandatory**
17815 Set the underlying svg image element. Unlike other dc charts this chart will not generate a svg
17816 element; therefore the bubble overlay chart will not work if this function is not invoked. If the
17817 underlying image is a bitmap, then an empty svg will need to be created on top of the image.
17818
17819 ```js
17820 // set up underlying svg element
17821 chart.svg(d3.select('#chart svg'));
17822 ```
17823
17824 **/
17825 dc.bubbleOverlay = function (root, chartGroup) {
17826 var BUBBLE_OVERLAY_CLASS = 'bubble-overlay';
17827 var BUBBLE_NODE_CLASS = 'node';
17828 var BUBBLE_CLASS = 'bubble';
17829
17830 var _chart = dc.bubbleMixin(dc.baseMixin({}));
17831 var _g;
17832 var _points = [];
17833
17834 _chart.transitionDuration(750);
17835
17836 _chart.radiusValueAccessor(function (d) {
17837 return d.value;
17838 });
17839
17840 /**
17841 #### .point(name, x, y) - **mandatory**
17842 Set up a data point on the overlay. The name of a data point should match a specific 'key' among
17843 data groups generated using keyAccessor. If a match is found (point name <-> data group key)
17844 then a bubble will be generated at the position specified by the function. x and y
17845 value specified here are relative to the underlying svg.
17846
17847 **/
17848 _chart.point = function (name, x, y) {
17849 _points.push({name: name, x: x, y: y});
17850 return _chart;
17851 };
17852
17853 _chart._doRender = function () {
17854 _g = initOverlayG();
17855
17856 _chart.r().range([_chart.MIN_RADIUS, _chart.width() * _chart.maxBubbleRelativeSize()]);
17857
17858 initializeBubbles();
17859
17860 _chart.fadeDeselectedArea();
17861
17862 return _chart;
17863 };
17864
17865 function initOverlayG() {
17866 _g = _chart.select('g.' + BUBBLE_OVERLAY_CLASS);
17867 if (_g.empty()) {
17868 _g = _chart.svg().append('g').attr('class', BUBBLE_OVERLAY_CLASS);
17869 }
17870 return _g;
17871 }
17872
17873 function initializeBubbles() {
17874 var data = mapData();
17875
17876 _points.forEach(function (point) {
17877 var nodeG = getNodeG(point, data);
17878
17879 var circle = nodeG.select('circle.' + BUBBLE_CLASS);
17880
17881 if (circle.empty()) {
17882 circle = nodeG.append('circle')
17883 .attr('class', BUBBLE_CLASS)
17884 .attr('r', 0)
17885 .attr('fill', _chart.getColor)
17886 .on('click', _chart.onClick);
17887 }
17888
17889 dc.transition(circle, _chart.transitionDuration())
17890 .attr('r', function (d) {
17891 return _chart.bubbleR(d);
17892 });
17893
17894 _chart._doRenderLabel(nodeG);
17895
17896 _chart._doRenderTitles(nodeG);
17897 });
17898 }
17899
17900 function mapData() {
17901 var data = {};
17902 _chart.data().forEach(function (datum) {
17903 data[_chart.keyAccessor()(datum)] = datum;
17904 });
17905 return data;
17906 }
17907
17908 function getNodeG(point, data) {
17909 var bubbleNodeClass = BUBBLE_NODE_CLASS + ' ' + dc.utils.nameToId(point.name);
17910
17911 var nodeG = _g.select('g.' + dc.utils.nameToId(point.name));
17912
17913 if (nodeG.empty()) {
17914 nodeG = _g.append('g')
17915 .attr('class', bubbleNodeClass)
17916 .attr('transform', 'translate(' + point.x + ',' + point.y + ')');
17917 }
17918
17919 nodeG.datum(data[point.name]);
17920
17921 return nodeG;
17922 }
17923
17924 _chart._doRedraw = function () {
17925 updateBubbles();
17926
17927 _chart.fadeDeselectedArea();
17928
17929 return _chart;
17930 };
17931
17932 function updateBubbles() {
17933 var data = mapData();
17934
17935 _points.forEach(function (point) {
17936 var nodeG = getNodeG(point, data);
17937
17938 var circle = nodeG.select('circle.' + BUBBLE_CLASS);
17939
17940 dc.transition(circle, _chart.transitionDuration())
17941 .attr('r', function (d) {
17942 return _chart.bubbleR(d);
17943 })
17944 .attr('fill', _chart.getColor);
17945
17946 _chart.doUpdateLabels(nodeG);
17947
17948 _chart.doUpdateTitles(nodeG);
17949 });
17950 }
17951
17952 _chart.debug = function (flag) {
17953 if (flag) {
17954 var debugG = _chart.select('g.' + dc.constants.DEBUG_GROUP_CLASS);
17955
17956 if (debugG.empty()) {
17957 debugG = _chart.svg()
17958 .append('g')
17959 .attr('class', dc.constants.DEBUG_GROUP_CLASS);
17960 }
17961
17962 var debugText = debugG.append('text')
17963 .attr('x', 10)
17964 .attr('y', 20);
17965
17966 debugG
17967 .append('rect')
17968 .attr('width', _chart.width())
17969 .attr('height', _chart.height())
17970 .on('mousemove', function () {
17971 var position = d3.mouse(debugG.node());
17972 var msg = position[0] + ', ' + position[1];
17973 debugText.text(msg);
17974 });
17975 } else {
17976 _chart.selectAll('.debug').remove();
17977 }
17978
17979 return _chart;
17980 };
17981
17982 _chart.anchor(root, chartGroup);
17983
17984 return _chart;
17985 };
17986
17987 /**
17988 ## Row Chart
17989 Includes: [Cap Mixin](#cap-mixin), [Margin Mixin](#margin-mixin), [Color Mixin](#color-mixin), [Base Mixin](#base-mixin)
17990
17991 Concrete row chart implementation.
17992 #### dc.rowChart(parent[, chartGroup])
17993 Create a row chart instance and attach it to the given parent element.
17994
17995 Parameters:
17996
17997 * parent : string | node | selection - any valid
17998 [d3 single selector](https://github.com/mbostock/d3/wiki/Selections#selecting-elements) specifying
17999 a dom block element such as a div; or a dom element or d3 selection.
18000
18001 * chartGroup : string (optional) - name of the chart group this chart instance should be placed in.
18002 Interaction with a chart will only trigger events and redraws within the chart's group.
18003
18004 Returns:
18005 A newly created row chart instance
18006
18007 ```js
18008 // create a row chart under #chart-container1 element using the default global chart group
18009 var chart1 = dc.rowChart('#chart-container1');
18010 // create a row chart under #chart-container2 element using chart group A
18011 var chart2 = dc.rowChart('#chart-container2', 'chartGroupA');
18012 ```
18013
18014 **/
18015 dc.rowChart = function (parent, chartGroup) {
18016
18017 var _g;
18018
18019 var _labelOffsetX = 10;
18020 var _labelOffsetY = 15;
18021 var _hasLabelOffsetY = false;
18022 var _dyOffset = '0.35em'; // this helps center labels https://github.com/mbostock/d3/wiki/SVG-Shapes#svg_text
18023 var _titleLabelOffsetX = 2;
18024
18025 var _gap = 5;
18026
18027 var _fixedBarHeight = false;
18028 var _rowCssClass = 'row';
18029 var _titleRowCssClass = 'titlerow';
18030 var _renderTitleLabel = false;
18031
18032 var _chart = dc.capMixin(dc.marginMixin(dc.colorMixin(dc.baseMixin({}))));
18033
18034 var _x;
18035
18036 var _elasticX;
18037
18038 var _xAxis = d3.svg.axis().orient('bottom');
18039
18040 var _rowData;
18041
18042 _chart.rowsCap = _chart.cap;
18043
18044 function calculateAxisScale() {
18045 if (!_x || _elasticX) {
18046 var extent = d3.extent(_rowData, _chart.cappedValueAccessor);
18047 if (extent[0] > 0) {
18048 extent[0] = 0;
18049 }
18050 _x = d3.scale.linear().domain(extent)
18051 .range([0, _chart.effectiveWidth()]);
18052 }
18053 _xAxis.scale(_x);
18054 }
18055
18056 function drawAxis() {
18057 var axisG = _g.select('g.axis');
18058
18059 calculateAxisScale();
18060
18061 if (axisG.empty()) {
18062 axisG = _g.append('g').attr('class', 'axis')
18063 .attr('transform', 'translate(0, ' + _chart.effectiveHeight() + ')');
18064 }
18065
18066 dc.transition(axisG, _chart.transitionDuration())
18067 .call(_xAxis);
18068 }
18069
18070 _chart._doRender = function () {
18071 _chart.resetSvg();
18072
18073 _g = _chart.svg()
18074 .append('g')
18075 .attr('transform', 'translate(' + _chart.margins().left + ',' + _chart.margins().top + ')');
18076
18077 drawChart();
18078
18079 return _chart;
18080 };
18081
18082 _chart.title(function (d) {
18083 return _chart.cappedKeyAccessor(d) + ': ' + _chart.cappedValueAccessor(d);
18084 });
18085
18086 _chart.label(_chart.cappedKeyAccessor);
18087
18088 /**
18089 #### .x([scale])
18090 Gets or sets the x scale. The x scale can be any d3
18091 [quantitive scale](https://github.com/mbostock/d3/wiki/Quantitative-Scales)
18092 **/
18093 _chart.x = function (x) {
18094 if (!arguments.length) {
18095 return _x;
18096 }
18097 _x = x;
18098 return _chart;
18099 };
18100
18101 function drawGridLines() {
18102 _g.selectAll('g.tick')
18103 .select('line.grid-line')
18104 .remove();
18105
18106 _g.selectAll('g.tick')
18107 .append('line')
18108 .attr('class', 'grid-line')
18109 .attr('x1', 0)
18110 .attr('y1', 0)
18111 .attr('x2', 0)
18112 .attr('y2', function () {
18113 return -_chart.effectiveHeight();
18114 });
18115 }
18116
18117 function drawChart() {
18118 _rowData = _chart.data();
18119
18120 drawAxis();
18121 drawGridLines();
18122
18123 var rows = _g.selectAll('g.' + _rowCssClass)
18124 .data(_rowData);
18125
18126 createElements(rows);
18127 removeElements(rows);
18128 updateElements(rows);
18129 }
18130
18131 function createElements(rows) {
18132 var rowEnter = rows.enter()
18133 .append('g')
18134 .attr('class', function (d, i) {
18135 return _rowCssClass + ' _' + i;
18136 });
18137
18138 rowEnter.append('rect').attr('width', 0);
18139
18140 createLabels(rowEnter);
18141 updateLabels(rows);
18142 }
18143
18144 function removeElements(rows) {
18145 rows.exit().remove();
18146 }
18147
18148 function rootValue() {
18149 var root = _x(0);
18150 return (root === -Infinity || root !== root) ? _x(1) : root;
18151 }
18152
18153 function updateElements(rows) {
18154 var n = _rowData.length;
18155
18156 var height;
18157 if (!_fixedBarHeight) {
18158 height = (_chart.effectiveHeight() - (n + 1) * _gap) / n;
18159 } else {
18160 height = _fixedBarHeight;
18161 }
18162
18163 // vertically align label in center unless they override the value via property setter
18164 if (!_hasLabelOffsetY) {
18165 _labelOffsetY = height / 2;
18166 }
18167
18168 var rect = rows.attr('transform', function (d, i) {
18169 return 'translate(0,' + ((i + 1) * _gap + i * height) + ')';
18170 }).select('rect')
18171 .attr('height', height)
18172 .attr('fill', _chart.getColor)
18173 .on('click', onClick)
18174 .classed('deselected', function (d) {
18175 return (_chart.hasFilter()) ? !isSelectedRow(d) : false;
18176 })
18177 .classed('selected', function (d) {
18178 return (_chart.hasFilter()) ? isSelectedRow(d) : false;
18179 });
18180
18181 dc.transition(rect, _chart.transitionDuration())
18182 .attr('width', function (d) {
18183 return Math.abs(rootValue() - _x(_chart.valueAccessor()(d)));
18184 })
18185 .attr('transform', translateX);
18186
18187 createTitles(rows);
18188 updateLabels(rows);
18189 }
18190
18191 function createTitles(rows) {
18192 if (_chart.renderTitle()) {
18193 rows.selectAll('title').remove();
18194 rows.append('title').text(_chart.title());
18195 }
18196 }
18197
18198 function createLabels(rowEnter) {
18199 if (_chart.renderLabel()) {
18200 rowEnter.append('text')
18201 .on('click', onClick);
18202 }
18203 if (_chart.renderTitleLabel()) {
18204 rowEnter.append('text')
18205 .attr('class', _titleRowCssClass)
18206 .on('click', onClick);
18207 }
18208 }
18209
18210 function updateLabels(rows) {
18211 if (_chart.renderLabel()) {
18212 var lab = rows.select('text')
18213 .attr('x', _labelOffsetX)
18214 .attr('y', _labelOffsetY)
18215 .attr('dy', _dyOffset)
18216 .on('click', onClick)
18217 .attr('class', function (d, i) {
18218 return _rowCssClass + ' _' + i;
18219 })
18220 .text(function (d) {
18221 return _chart.label()(d);
18222 });
18223 dc.transition(lab, _chart.transitionDuration())
18224 .attr('transform', translateX);
18225 }
18226 if (_chart.renderTitleLabel()) {
18227 var titlelab = rows.select('.' + _titleRowCssClass)
18228 .attr('x', _chart.effectiveWidth() - _titleLabelOffsetX)
18229 .attr('y', _labelOffsetY)
18230 .attr('text-anchor', 'end')
18231 .on('click', onClick)
18232 .attr('class', function (d, i) {
18233 return _titleRowCssClass + ' _' + i ;
18234 })
18235 .text(function (d) {
18236 return _chart.title()(d);
18237 });
18238 dc.transition(titlelab, _chart.transitionDuration())
18239 .attr('transform', translateX);
18240 }
18241 }
18242
18243 /**
18244 #### .renderTitleLabel(boolean)
18245 Turn on/off Title label rendering (values) using SVG style of text-anchor 'end'
18246
18247 **/
18248 _chart.renderTitleLabel = function (_) {
18249 if (!arguments.length) {
18250 return _renderTitleLabel;
18251 }
18252 _renderTitleLabel = _;
18253 return _chart;
18254 };
18255
18256 function onClick(d) {
18257 _chart.onClick(d);
18258 }
18259
18260 function translateX(d) {
18261 var x = _x(_chart.cappedValueAccessor(d)),
18262 x0 = rootValue(),
18263 s = x > x0 ? x0 : x;
18264 return 'translate(' + s + ',0)';
18265 }
18266
18267 _chart._doRedraw = function () {
18268 drawChart();
18269 return _chart;
18270 };
18271
18272 /**
18273 #### .xAxis()
18274 Get the x axis for the row chart instance. Note: not settable for row charts.
18275 See the [d3 axis object](https://github.com/mbostock/d3/wiki/SVG-Axes#wiki-axis) documention for more information.
18276 ```js
18277 // customize x axis tick format
18278 chart.xAxis().tickFormat(function (v) {return v + '%';});
18279 // customize x axis tick values
18280 chart.xAxis().tickValues([0, 100, 200, 300]);
18281 ```
18282
18283 **/
18284 _chart.xAxis = function () {
18285 return _xAxis;
18286 };
18287
18288 /**
18289 #### .fixedBarHeight([height])
18290 Get or set the fixed bar height. Default is [false] which will auto-scale bars.
18291 For example, if you want to fix the height for a specific number of bars (useful in TopN charts)
18292 you could fix height as follows (where count = total number of bars in your TopN and gap is
18293 your vertical gap space).
18294 ```js
18295 chart.fixedBarHeight( chartheight - (count + 1) * gap / count);
18296 ```
18297 **/
18298 _chart.fixedBarHeight = function (g) {
18299 if (!arguments.length) {
18300 return _fixedBarHeight;
18301 }
18302 _fixedBarHeight = g;
18303 return _chart;
18304 };
18305
18306 /**
18307 #### .gap([gap])
18308 Get or set the vertical gap space between rows on a particular row chart instance. Default gap is 5px;
18309
18310 **/
18311 _chart.gap = function (g) {
18312 if (!arguments.length) {
18313 return _gap;
18314 }
18315 _gap = g;
18316 return _chart;
18317 };
18318
18319 /**
18320 #### .elasticX([boolean])
18321 Get or set the elasticity on x axis. If this attribute is set to true, then the x axis will rescle to auto-fit the
18322 data range when filtered.
18323
18324 **/
18325 _chart.elasticX = function (_) {
18326 if (!arguments.length) {
18327 return _elasticX;
18328 }
18329 _elasticX = _;
18330 return _chart;
18331 };
18332
18333 /**
18334 #### .labelOffsetX([x])
18335 Get or set the x offset (horizontal space to the top left corner of a row) for labels on a particular row chart.
18336 Default x offset is 10px;
18337
18338 **/
18339 _chart.labelOffsetX = function (o) {
18340 if (!arguments.length) {
18341 return _labelOffsetX;
18342 }
18343 _labelOffsetX = o;
18344 return _chart;
18345 };
18346
18347 /**
18348 #### .labelOffsetY([y])
18349 Get or set the y offset (vertical space to the top left corner of a row) for labels on a particular row chart.
18350 Default y offset is 15px;
18351
18352 **/
18353 _chart.labelOffsetY = function (o) {
18354 if (!arguments.length) {
18355 return _labelOffsetY;
18356 }
18357 _labelOffsetY = o;
18358 _hasLabelOffsetY = true;
18359 return _chart;
18360 };
18361
18362 /**
18363 #### .titleLabelOffsetx([x])
18364 Get of set the x offset (horizontal space between right edge of row and right edge or text.
18365 Default x offset is 2px;
18366
18367 **/
18368 _chart.titleLabelOffsetX = function (o) {
18369 if (!arguments.length) {
18370 return _titleLabelOffsetX;
18371 }
18372 _titleLabelOffsetX = o;
18373 return _chart;
18374 };
18375
18376 function isSelectedRow (d) {
18377 return _chart.hasFilter(_chart.cappedKeyAccessor(d));
18378 }
18379
18380 return _chart.anchor(parent, chartGroup);
18381 };
18382
18383 /**
18384 ## Legend
18385 Legend is a attachable widget that can be added to other dc charts to render horizontal legend
18386 labels.
18387
18388 ```js
18389 chart.legend(dc.legend().x(400).y(10).itemHeight(13).gap(5))
18390 ```
18391
18392 Examples:
18393 * [Nasdaq 100 Index](http://dc-js.github.com/dc.js/)
18394 * [Canadian City Crime Stats](http://dc-js.github.com/dc.js/crime/index.html)
18395
18396 **/
18397 dc.legend = function () {
18398 var LABEL_GAP = 2;
18399
18400 var _legend = {},
18401 _parent,
18402 _x = 0,
18403 _y = 0,
18404 _itemHeight = 12,
18405 _gap = 5,
18406 _horizontal = false,
18407 _legendWidth = 560,
18408 _itemWidth = 70;
18409
18410 var _g;
18411
18412 _legend.parent = function (p) {
18413 if (!arguments.length) {
18414 return _parent;
18415 }
18416 _parent = p;
18417 return _legend;
18418 };
18419
18420 _legend.render = function () {
18421 _parent.svg().select('g.dc-legend').remove();
18422 _g = _parent.svg().append('g')
18423 .attr('class', 'dc-legend')
18424 .attr('transform', 'translate(' + _x + ',' + _y + ')');
18425 var legendables = _parent.legendables();
18426
18427 var itemEnter = _g.selectAll('g.dc-legend-item')
18428 .data(legendables)
18429 .enter()
18430 .append('g')
18431 .attr('class', 'dc-legend-item')
18432 .on('mouseover', function (d) {
18433 _parent.legendHighlight(d);
18434 })
18435 .on('mouseout', function (d) {
18436 _parent.legendReset(d);
18437 })
18438 .on('click', function (d) {
18439 d.chart.legendToggle(d);
18440 });
18441
18442 _g.selectAll('g.dc-legend-item')
18443 .classed('fadeout', function (d) {
18444 return d.chart.isLegendableHidden(d);
18445 });
18446
18447 if (legendables.some(dc.pluck('dashstyle'))) {
18448 itemEnter
18449 .append('line')
18450 .attr('x1', 0)
18451 .attr('y1', _itemHeight / 2)
18452 .attr('x2', _itemHeight)
18453 .attr('y2', _itemHeight / 2)
18454 .attr('stroke-width', 2)
18455 .attr('stroke-dasharray', dc.pluck('dashstyle'))
18456 .attr('stroke', dc.pluck('color'));
18457 } else {
18458 itemEnter
18459 .append('rect')
18460 .attr('width', _itemHeight)
18461 .attr('height', _itemHeight)
18462 .attr('fill', function (d) {return d ? d.color : 'blue';});
18463 }
18464
18465 itemEnter.append('text')
18466 .text(dc.pluck('name'))
18467 .attr('x', _itemHeight + LABEL_GAP)
18468 .attr('y', function () {
18469 return _itemHeight / 2 + (this.clientHeight ? this.clientHeight : 13) / 2 - 2;
18470 });
18471
18472 var _cumulativeLegendTextWidth = 0;
18473 var row = 0;
18474 itemEnter.attr('transform', function (d, i) {
18475 if (_horizontal) {
18476 var translateBy = 'translate(' + _cumulativeLegendTextWidth + ',' + row * legendItemHeight() + ')';
18477 if ((_cumulativeLegendTextWidth + _itemWidth) >= _legendWidth) {
18478 ++row ;
18479 _cumulativeLegendTextWidth = 0 ;
18480 } else {
18481 _cumulativeLegendTextWidth += _itemWidth;
18482 }
18483 return translateBy;
18484 }
18485 else {
18486 return 'translate(0,' + i * legendItemHeight() + ')';
18487 }
18488 });
18489 };
18490
18491 function legendItemHeight() {
18492 return _gap + _itemHeight;
18493 }
18494
18495 /**
18496 #### .x([value])
18497 Set or get x coordinate for legend widget. Default: 0.
18498 **/
18499 _legend.x = function (x) {
18500 if (!arguments.length) {
18501 return _x;
18502 }
18503 _x = x;
18504 return _legend;
18505 };
18506
18507 /**
18508 #### .y([value])
18509 Set or get y coordinate for legend widget. Default: 0.
18510 **/
18511 _legend.y = function (y) {
18512 if (!arguments.length) {
18513 return _y;
18514 }
18515 _y = y;
18516 return _legend;
18517 };
18518
18519 /**
18520 #### .gap([value])
18521 Set or get gap between legend items. Default: 5.
18522 **/
18523 _legend.gap = function (gap) {
18524 if (!arguments.length) {
18525 return _gap;
18526 }
18527 _gap = gap;
18528 return _legend;
18529 };
18530
18531 /**
18532 #### .itemHeight([value])
18533 Set or get legend item height. Default: 12.
18534 **/
18535 _legend.itemHeight = function (h) {
18536 if (!arguments.length) {
18537 return _itemHeight;
18538 }
18539 _itemHeight = h;
18540 return _legend;
18541 };
18542
18543 /**
18544 #### .horizontal([boolean])
18545 Position legend horizontally instead of vertically
18546 **/
18547 _legend.horizontal = function (_) {
18548 if (!arguments.length) {
18549 return _horizontal;
18550 }
18551 _horizontal = _;
18552 return _legend;
18553 };
18554
18555 /**
18556 #### .legendWidth([value])
18557 Maximum width for horizontal legend. Default: 560.
18558 **/
18559 _legend.legendWidth = function (_) {
18560 if (!arguments.length) {
18561 return _legendWidth;
18562 }
18563 _legendWidth = _;
18564 return _legend;
18565 };
18566
18567 /**
18568 #### .itemWidth([value])
18569 legendItem width for horizontal legend. Default: 70.
18570 **/
18571 _legend.itemWidth = function (_) {
18572 if (!arguments.length) {
18573 return _itemWidth;
18574 }
18575 _itemWidth = _;
18576 return _legend;
18577 };
18578
18579 return _legend;
18580 };
18581
18582 /**
18583 ## Scatter Plot
18584 Includes: [Coordinate Grid Mixin](#coordinate-grid-mixin)
18585
18586 A scatter plot chart
18587 #### dc.scatterPlot(parent[, chartGroup])
18588 Create a scatter plot instance and attach it to the given parent element.
18589
18590 Parameters:
18591
18592 * parent : string | node | selection | compositeChart - any valid
18593 [d3 single selector](https://github.com/mbostock/d3/wiki/Selections#selecting-elements) specifying
18594 a dom block element such as a div; or a dom element or d3 selection.
18595 If the scatter plot is a sub-chart in a [Composite Chart](#composite-chart) then pass in the parent composite
18596 chart instance.
18597
18598 * chartGroup : string (optional) - name of the chart group this chart instance should be placed in.
18599 Interaction with a chart will only trigger events and redraws within the chart's group.
18600
18601 Returns:
18602 A newly created scatter plot instance
18603
18604 ```js
18605 // create a scatter plot under #chart-container1 element using the default global chart group
18606 var chart1 = dc.scatterPlot('#chart-container1');
18607 // create a scatter plot under #chart-container2 element using chart group A
18608 var chart2 = dc.scatterPlot('#chart-container2', 'chartGroupA');
18609 // create a sub-chart under a composite parent chart
18610 var chart3 = dc.scatterPlot(compositeChart);
18611 ```
18612
18613 **/
18614 dc.scatterPlot = function (parent, chartGroup) {
18615 var _chart = dc.coordinateGridMixin({});
18616 var _symbol = d3.svg.symbol();
18617
18618 var _existenceAccessor = function (d) { return d.value; };
18619
18620 var originalKeyAccessor = _chart.keyAccessor();
18621 _chart.keyAccessor(function (d) { return originalKeyAccessor(d)[0]; });
18622 _chart.valueAccessor(function (d) { return originalKeyAccessor(d)[1]; });
18623 _chart.colorAccessor(function () { return _chart._groupName; });
18624
18625 var _locator = function (d) {
18626 return 'translate(' + _chart.x()(_chart.keyAccessor()(d)) + ',' +
18627 _chart.y()(_chart.valueAccessor()(d)) + ')';
18628 };
18629
18630 var _symbolSize = 3;
18631 var _highlightedSize = 5;
18632 var _hiddenSize = 0;
18633
18634 _symbol.size(function (d) {
18635 if (!_existenceAccessor(d)) {
18636 return _hiddenSize;
18637 } else if (this.filtered) {
18638 return Math.pow(_highlightedSize, 2);
18639 } else {
18640 return Math.pow(_symbolSize, 2);
18641 }
18642 });
18643
18644 dc.override(_chart, '_filter', function (filter) {
18645 if (!arguments.length) {
18646 return _chart.__filter();
18647 }
18648
18649 return _chart.__filter(dc.filters.RangedTwoDimensionalFilter(filter));
18650 });
18651
18652 _chart.plotData = function () {
18653 var symbols = _chart.chartBodyG().selectAll('path.symbol')
18654 .data(_chart.data());
18655
18656 symbols
18657 .enter()
18658 .append('path')
18659 .attr('class', 'symbol')
18660 .attr('opacity', 0)
18661 .attr('fill', _chart.getColor)
18662 .attr('transform', _locator);
18663
18664 dc.transition(symbols, _chart.transitionDuration())
18665 .attr('opacity', function (d) { return _existenceAccessor(d) ? 1 : 0; })
18666 .attr('fill', _chart.getColor)
18667 .attr('transform', _locator)
18668 .attr('d', _symbol);
18669
18670 dc.transition(symbols.exit(), _chart.transitionDuration())
18671 .attr('opacity', 0).remove();
18672 };
18673
18674 /**
18675 #### .existenceAccessor([accessor])
18676 Get or set the existence accessor. If a point exists, it is drawn with symbolSize radius and
18677 opacity 1; if it does not exist, it is drawn with hiddenSize radius and opacity 0. By default,
18678 the existence accessor checks if the reduced value is truthy.
18679 **/
18680
18681 _chart.existenceAccessor = function (acc) {
18682 if (!arguments.length) {
18683 return _existenceAccessor;
18684 }
18685 _existenceAccessor = acc;
18686 return this;
18687 };
18688
18689 /**
18690 #### .symbol([type])
18691 Get or set the symbol type used for each point. By default the symbol is a circle. See the D3
18692 [docs](https://github.com/mbostock/d3/wiki/SVG-Shapes#wiki-symbol_type) for acceptable types.
18693 Type can be a constant or an accessor.
18694
18695 **/
18696 _chart.symbol = function (type) {
18697 if (!arguments.length) {
18698 return _symbol.type();
18699 }
18700 _symbol.type(type);
18701 return _chart;
18702 };
18703
18704 /**
18705 #### .symbolSize([radius])
18706 Set or get radius for symbols. Default: 3.
18707
18708 **/
18709 _chart.symbolSize = function (s) {
18710 if (!arguments.length) {
18711 return _symbolSize;
18712 }
18713 _symbolSize = s;
18714 return _chart;
18715 };
18716
18717 /**
18718 #### .highlightedSize([radius])
18719 Set or get radius for highlighted symbols. Default: 4.
18720
18721 **/
18722 _chart.highlightedSize = function (s) {
18723 if (!arguments.length) {
18724 return _highlightedSize;
18725 }
18726 _highlightedSize = s;
18727 return _chart;
18728 };
18729
18730 /**
18731 #### .hiddenSize([radius])
18732 Set or get radius for symbols when the group is empty. Default: 0.
18733
18734 **/
18735 _chart.hiddenSize = function (s) {
18736 if (!arguments.length) {
18737 return _hiddenSize;
18738 }
18739 _hiddenSize = s;
18740 return _chart;
18741 };
18742
18743 _chart.legendables = function () {
18744 return [{chart: _chart, name: _chart._groupName, color: _chart.getColor()}];
18745 };
18746
18747 _chart.legendHighlight = function (d) {
18748 resizeSymbolsWhere(function (symbol) {
18749 return symbol.attr('fill') === d.color;
18750 }, _highlightedSize);
18751 _chart.selectAll('.chart-body path.symbol').filter(function () {
18752 return d3.select(this).attr('fill') !== d.color;
18753 }).classed('fadeout', true);
18754 };
18755
18756 _chart.legendReset = function (d) {
18757 resizeSymbolsWhere(function (symbol) {
18758 return symbol.attr('fill') === d.color;
18759 }, _symbolSize);
18760 _chart.selectAll('.chart-body path.symbol').filter(function () {
18761 return d3.select(this).attr('fill') !== d.color;
18762 }).classed('fadeout', false);
18763 };
18764
18765 function resizeSymbolsWhere(condition, size) {
18766 var symbols = _chart.selectAll('.chart-body path.symbol').filter(function () {
18767 return condition(d3.select(this));
18768 });
18769 var oldSize = _symbol.size();
18770 _symbol.size(Math.pow(size, 2));
18771 dc.transition(symbols, _chart.transitionDuration()).attr('d', _symbol);
18772 _symbol.size(oldSize);
18773 }
18774
18775 _chart.setHandlePaths = function () {
18776 // no handle paths for poly-brushes
18777 };
18778
18779 _chart.extendBrush = function () {
18780 var extent = _chart.brush().extent();
18781 if (_chart.round()) {
18782 extent[0] = extent[0].map(_chart.round());
18783 extent[1] = extent[1].map(_chart.round());
18784
18785 _chart.g().select('.brush')
18786 .call(_chart.brush().extent(extent));
18787 }
18788 return extent;
18789 };
18790
18791 _chart.brushIsEmpty = function (extent) {
18792 return _chart.brush().empty() || !extent || extent[0][0] >= extent[1][0] || extent[0][1] >= extent[1][1];
18793 };
18794
18795 function resizeFiltered(filter) {
18796 var symbols = _chart.selectAll('.chart-body path.symbol').each(function (d) {
18797 this.filtered = filter && filter.isFiltered(d.key);
18798 });
18799
18800 dc.transition(symbols, _chart.transitionDuration()).attr('d', _symbol);
18801 }
18802
18803 _chart._brushing = function () {
18804 var extent = _chart.extendBrush();
18805
18806 _chart.redrawBrush(_chart.g());
18807
18808 if (_chart.brushIsEmpty(extent)) {
18809 dc.events.trigger(function () {
18810 _chart.filter(null);
18811 _chart.redrawGroup();
18812 });
18813
18814 resizeFiltered(false);
18815
18816 } else {
18817 var ranged2DFilter = dc.filters.RangedTwoDimensionalFilter(extent);
18818 dc.events.trigger(function () {
18819 _chart.filter(null);
18820 _chart.filter(ranged2DFilter);
18821 _chart.redrawGroup();
18822 }, dc.constants.EVENT_DELAY);
18823
18824 resizeFiltered(ranged2DFilter);
18825 }
18826 };
18827
18828 _chart.setBrushY = function (gBrush) {
18829 gBrush.call(_chart.brush().y(_chart.y()));
18830 };
18831
18832 return _chart.anchor(parent, chartGroup);
18833 };
18834
18835 /**
18836 ## Number Display Widget
18837 Includes: [Base Mixin](#base-mixin)
18838
18839 A display of a single numeric value.
18840
18841 Examples:
18842
18843 * [Test Example](http://dc-js.github.io/dc.js/examples/number.html)
18844 #### dc.numberDisplay(parent[, chartGroup])
18845 Create a Number Display instance and attach it to the given parent element.
18846
18847 Unlike other charts, you do not need to set a dimension. Instead a group object must be provided and
18848 a valueAccessor that returns a single value.
18849
18850 Parameters:
18851
18852 * parent : string | node | selection - any valid
18853 [d3 single selector](https://github.com/mbostock/d3/wiki/Selections#selecting-elements) specifying
18854 a dom block element such as a div; or a dom element or d3 selection.
18855 * chartGroup : string (optional) - name of the chart group this chart instance should be placed in.
18856 The number display widget will only react to filter changes in the chart group.
18857
18858 Returns:
18859 A newly created number display instance
18860
18861 ```js
18862 // create a number display under #chart-container1 element using the default global chart group
18863 var display1 = dc.numberDisplay('#chart-container1');
18864 ```
18865
18866 **/
18867 dc.numberDisplay = function (parent, chartGroup) {
18868 var SPAN_CLASS = 'number-display';
18869 var _formatNumber = d3.format('.2s');
18870 var _chart = dc.baseMixin({});
18871 var _html = {one:'', some:'', none:''};
18872
18873 // dimension not required
18874 _chart._mandatoryAttributes(['group']);
18875
18876 /**
18877 #### .html([object])
18878 Gets or sets an optional object specifying HTML templates to use depending on the number
18879 displayed. The text `%number` will be replaced with the current value.
18880 - one: HTML template to use if the number is 1
18881 - zero: HTML template to use if the number is 0
18882 - some: HTML template to use otherwise
18883
18884 ```js
18885 numberWidget.html({
18886 one:'%number record',
18887 some:'%number records',
18888 none:'no records'})
18889 ```
18890 **/
18891
18892 _chart.html = function (s) {
18893 if (!arguments.length) {
18894 return _html;
18895 }
18896 if (s.none) {
18897 _html.none = s.none;//if none available
18898 } else if (s.one) {
18899 _html.none = s.one;//if none not available use one
18900 } else if (s.some) {
18901 _html.none = s.some;//if none and one not available use some
18902 }
18903 if (s.one) {
18904 _html.one = s.one;//if one available
18905 } else if (s.some) {
18906 _html.one = s.some;//if one not available use some
18907 }
18908 if (s.some) {
18909 _html.some = s.some;//if some available
18910 } else if (s.one) {
18911 _html.some = s.one;//if some not available use one
18912 }
18913 return _chart;
18914 };
18915
18916 /**
18917 #### .value()
18918 Calculate and return the underlying value of the display
18919 **/
18920
18921 _chart.value = function () {
18922 return _chart.data();
18923 };
18924
18925 _chart.data(function (group) {
18926 var valObj = group.value ? group.value() : group.top(1)[0];
18927 return _chart.valueAccessor()(valObj);
18928 });
18929
18930 _chart.transitionDuration(250); // good default
18931
18932 _chart._doRender = function () {
18933 var newValue = _chart.value(),
18934 span = _chart.selectAll('.' + SPAN_CLASS);
18935
18936 if (span.empty()) {
18937 span = span.data([0])
18938 .enter()
18939 .append('span')
18940 .attr('class', SPAN_CLASS);
18941 }
18942
18943 span.transition()
18944 .duration(_chart.transitionDuration())
18945 .ease('quad-out-in')
18946 .tween('text', function () {
18947 var interp = d3.interpolateNumber(this.lastValue || 0, newValue);
18948 this.lastValue = newValue;
18949 return function (t) {
18950 var html = null, num = _chart.formatNumber()(interp(t));
18951 if (newValue === 0 && (_html.none !== '')) {
18952 html = _html.none;
18953 } else if (newValue === 1 && (_html.one !== '')) {
18954 html = _html.one;
18955 } else if (_html.some !== '') {
18956 html = _html.some;
18957 }
18958 this.innerHTML = html ? html.replace('%number', num) : num;
18959 };
18960 });
18961 };
18962
18963 _chart._doRedraw = function () {
18964 return _chart._doRender();
18965 };
18966
18967 /**
18968 #### .formatNumber([formatter])
18969 Get or set a function to format the value for the display. By default `d3.format('.2s');` is used.
18970
18971 **/
18972 _chart.formatNumber = function (_) {
18973 if (!arguments.length) {
18974 return _formatNumber;
18975 }
18976 _formatNumber = _;
18977 return _chart;
18978 };
18979
18980 return _chart.anchor(parent, chartGroup);
18981 };
18982
18983 /**
18984 ## Heat Map
18985
18986 Includes: [Color Mixin](#color-mixin), [Margin Mixin](#margin-mixin), [Base Mixin](#base-mixin)
18987
18988 A heat map is matrix that represents the values of two dimensions of data using colors.
18989
18990 #### dc.heatMap(parent[, chartGroup])
18991 Create a heat map instance and attach it to the given parent element.
18992
18993 Parameters:
18994 * parent : string | node | selection - any valid
18995 [d3 single selector](https://github.com/mbostock/d3/wiki/Selections#selecting-elements) specifying
18996 a dom block element such as a div; or a dom element or d3 selection.
18997
18998 * chartGroup : string (optional) - name of the chart group this chart instance should be placed in.
18999 Interaction with a chart will only trigger events and redraws within the chart's group.
19000
19001 Returns:
19002 A newly created heat map instance
19003
19004 ```js
19005 // create a heat map under #chart-container1 element using the default global chart group
19006 var heatMap1 = dc.heatMap('#chart-container1');
19007 // create a heat map under #chart-container2 element using chart group A
19008 var heatMap2 = dc.heatMap('#chart-container2', 'chartGroupA');
19009 ```
19010
19011 **/
19012 dc.heatMap = function (parent, chartGroup) {
19013
19014 var DEFAULT_BORDER_RADIUS = 6.75;
19015
19016 var _chartBody;
19017
19018 var _cols;
19019 var _rows;
19020 var _xBorderRadius = DEFAULT_BORDER_RADIUS;
19021 var _yBorderRadius = DEFAULT_BORDER_RADIUS;
19022
19023 var _chart = dc.colorMixin(dc.marginMixin(dc.baseMixin({})));
19024 _chart._mandatoryAttributes(['group']);
19025 _chart.title(_chart.colorAccessor());
19026
19027 var _xAxisOnClick = function (d) { filterAxis(0, d); };
19028 var _yAxisOnClick = function (d) { filterAxis(1, d); };
19029 var _boxOnClick = function (d) {
19030 var filter = d.key;
19031 dc.events.trigger(function () {
19032 _chart.filter(filter);
19033 _chart.redrawGroup();
19034 });
19035 };
19036
19037 function filterAxis(axis, value) {
19038 var cellsOnAxis = _chart.selectAll('.box-group').filter(function (d) {
19039 return d.key[axis] === value;
19040 });
19041 var unfilteredCellsOnAxis = cellsOnAxis.filter(function (d) {
19042 return !_chart.hasFilter(d.key);
19043 });
19044 dc.events.trigger(function () {
19045 if (unfilteredCellsOnAxis.empty()) {
19046 cellsOnAxis.each(function (d) {
19047 _chart.filter(d.key);
19048 });
19049 } else {
19050 unfilteredCellsOnAxis.each(function (d) {
19051 _chart.filter(d.key);
19052 });
19053 }
19054 _chart.redrawGroup();
19055 });
19056 }
19057
19058 dc.override(_chart, 'filter', function (filter) {
19059 if (!arguments.length) {
19060 return _chart._filter();
19061 }
19062
19063 return _chart._filter(dc.filters.TwoDimensionalFilter(filter));
19064 });
19065
19066 function uniq(d, i, a) {
19067 return !i || a[i - 1] !== d;
19068 }
19069
19070 /**
19071 #### .rows([values])
19072 Gets or sets the values used to create the rows of the heatmap, as an array. By default, all
19073 the values will be fetched from the data using the value accessor, and they will be sorted in
19074 ascending order.
19075 **/
19076
19077 _chart.rows = function (_) {
19078 if (arguments.length) {
19079 _rows = _;
19080 return _chart;
19081 }
19082 if (_rows) {
19083 return _rows;
19084 }
19085 var rowValues = _chart.data().map(_chart.valueAccessor());
19086 rowValues.sort(d3.ascending);
19087 return d3.scale.ordinal().domain(rowValues.filter(uniq));
19088 };
19089
19090 /**
19091 #### .cols([keys])
19092 Gets or sets the keys used to create the columns of the heatmap, as an array. By default, all
19093 the values will be fetched from the data using the key accessor, and they will be sorted in
19094 ascending order.
19095 **/
19096 _chart.cols = function (_) {
19097 if (arguments.length) {
19098 _cols = _;
19099 return _chart;
19100 }
19101 if (_cols) {
19102 return _cols;
19103 }
19104 var colValues = _chart.data().map(_chart.keyAccessor());
19105 colValues.sort(d3.ascending);
19106 return d3.scale.ordinal().domain(colValues.filter(uniq));
19107 };
19108
19109 _chart._doRender = function () {
19110 _chart.resetSvg();
19111
19112 _chartBody = _chart.svg()
19113 .append('g')
19114 .attr('class', 'heatmap')
19115 .attr('transform', 'translate(' + _chart.margins().left + ',' + _chart.margins().top + ')');
19116
19117 return _chart._doRedraw();
19118 };
19119
19120 _chart._doRedraw = function () {
19121 var rows = _chart.rows(),
19122 cols = _chart.cols(),
19123 rowCount = rows.domain().length,
19124 colCount = cols.domain().length,
19125 boxWidth = Math.floor(_chart.effectiveWidth() / colCount),
19126 boxHeight = Math.floor(_chart.effectiveHeight() / rowCount);
19127
19128 cols.rangeRoundBands([0, _chart.effectiveWidth()]);
19129 rows.rangeRoundBands([_chart.effectiveHeight(), 0]);
19130
19131 var boxes = _chartBody.selectAll('g.box-group').data(_chart.data(), function (d, i) {
19132 return _chart.keyAccessor()(d, i) + '\0' + _chart.valueAccessor()(d, i);
19133 });
19134 var gEnter = boxes.enter().append('g')
19135 .attr('class', 'box-group');
19136
19137 gEnter.append('rect')
19138 .attr('class', 'heat-box')
19139 .attr('fill', 'white')
19140 .on('click', _chart.boxOnClick());
19141
19142 if (_chart.renderTitle()) {
19143 gEnter.append('title')
19144 .text(_chart.title());
19145 }
19146
19147 dc.transition(boxes.selectAll('rect'), _chart.transitionDuration())
19148 .attr('x', function (d, i) { return cols(_chart.keyAccessor()(d, i)); })
19149 .attr('y', function (d, i) { return rows(_chart.valueAccessor()(d, i)); })
19150 .attr('rx', _xBorderRadius)
19151 .attr('ry', _yBorderRadius)
19152 .attr('fill', _chart.getColor)
19153 .attr('width', boxWidth)
19154 .attr('height', boxHeight);
19155
19156 boxes.exit().remove();
19157
19158 var gCols = _chartBody.selectAll('g.cols');
19159 if (gCols.empty()) {
19160 gCols = _chartBody.append('g').attr('class', 'cols axis');
19161 }
19162 var gColsText = gCols.selectAll('text').data(cols.domain());
19163 gColsText.enter().append('text')
19164 .attr('x', function (d) { return cols(d) + boxWidth / 2; })
19165 .style('text-anchor', 'middle')
19166 .attr('y', _chart.effectiveHeight())
19167 .attr('dy', 12)
19168 .on('click', _chart.xAxisOnClick())
19169 .text(function (d) { return d; });
19170 dc.transition(gColsText, _chart.transitionDuration())
19171 .text(function (d) { return d; })
19172 .attr('x', function (d) { return cols(d) + boxWidth / 2; });
19173 gColsText.exit().remove();
19174 var gRows = _chartBody.selectAll('g.rows');
19175 if (gRows.empty()) {
19176 gRows = _chartBody.append('g').attr('class', 'rows axis');
19177 }
19178 var gRowsText = gRows.selectAll('text').data(rows.domain());
19179 gRowsText.enter().append('text')
19180 .attr('dy', 6)
19181 .style('text-anchor', 'end')
19182 .attr('x', 0)
19183 .attr('dx', -2)
19184 .on('click', _chart.yAxisOnClick())
19185 .text(function (d) { return d; });
19186 dc.transition(gRowsText, _chart.transitionDuration())
19187 .text(function (d) { return d; })
19188 .attr('y', function (d) { return rows(d) + boxHeight / 2; });
19189 gRowsText.exit().remove();
19190
19191 if (_chart.hasFilter()) {
19192 _chart.selectAll('g.box-group').each(function (d) {
19193 if (_chart.isSelectedNode(d)) {
19194 _chart.highlightSelected(this);
19195 } else {
19196 _chart.fadeDeselected(this);
19197 }
19198 });
19199 } else {
19200 _chart.selectAll('g.box-group').each(function () {
19201 _chart.resetHighlight(this);
19202 });
19203 }
19204 return _chart;
19205 };
19206 /**
19207 #### .boxOnClick([handler])
19208 Gets or sets the handler that fires when an individual cell is clicked in the heatmap.
19209 By default, filtering of the cell will be toggled.
19210 **/
19211 _chart.boxOnClick = function (f) {
19212 if (!arguments.length) {
19213 return _boxOnClick;
19214 }
19215 _boxOnClick = f;
19216 return _chart;
19217 };
19218
19219 /**
19220 #### .xAxisOnClick([handler])
19221 Gets or sets the handler that fires when a column tick is clicked in the x axis.
19222 By default, if any cells in the column are unselected, the whole column will be selected,
19223 otherwise the whole column will be unselected.
19224 **/
19225 _chart.xAxisOnClick = function (f) {
19226 if (!arguments.length) {
19227 return _xAxisOnClick;
19228 }
19229 _xAxisOnClick = f;
19230 return _chart;
19231 };
19232
19233 /**
19234 #### .yAxisOnClick([handler])
19235 Gets or sets the handler that fires when a row tick is clicked in the y axis.
19236 By default, if any cells in the row are unselected, the whole row will be selected,
19237 otherwise the whole row will be unselected.
19238 **/
19239 _chart.yAxisOnClick = function (f) {
19240 if (!arguments.length) {
19241 return _yAxisOnClick;
19242 }
19243 _yAxisOnClick = f;
19244 return _chart;
19245 };
19246
19247 /**
19248 #### .xBorderRadius([value])
19249 Gets or sets the X border radius. Set to 0 to get full rectangles. Default: 6.75
19250 */
19251 _chart.xBorderRadius = function (d) {
19252 if (!arguments.length) {
19253 return _xBorderRadius;
19254 }
19255 _xBorderRadius = d;
19256 return _chart;
19257 };
19258
19259 /**
19260 #### .xBorderRadius([value])
19261 Gets or sets the Y border radius. Set to 0 to get full rectangles. Default: 6.75
19262 */
19263 _chart.yBorderRadius = function (d) {
19264 if (!arguments.length) {
19265 return _yBorderRadius;
19266 }
19267 _yBorderRadius = d;
19268 return _chart;
19269 };
19270
19271 _chart.isSelectedNode = function (d) {
19272 return _chart.hasFilter(d.key);
19273 };
19274
19275 return _chart.anchor(parent, chartGroup);
19276 };
19277
19278 // https://github.com/d3/d3-plugins/blob/master/box/box.js
19279 (function () {
19280
19281 // Inspired by http://informationandvisualization.de/blog/box-plot
19282 d3.box = function () {
19283 var width = 1,
19284 height = 1,
19285 duration = 0,
19286 domain = null,
19287 value = Number,
19288 whiskers = boxWhiskers,
19289 quartiles = boxQuartiles,
19290 tickFormat = null;
19291
19292 // For each small multiple…
19293 function box(g) {
19294 g.each(function (d, i) {
19295 d = d.map(value).sort(d3.ascending);
19296 var g = d3.select(this),
19297 n = d.length,
19298 min = d[0],
19299 max = d[n - 1];
19300
19301 // Compute quartiles. Must return exactly 3 elements.
19302 var quartileData = d.quartiles = quartiles(d);
19303
19304 // Compute whiskers. Must return exactly 2 elements, or null.
19305 var whiskerIndices = whiskers && whiskers.call(this, d, i),
19306 whiskerData = whiskerIndices && whiskerIndices.map(function (i) { return d[i]; });
19307
19308 // Compute outliers. If no whiskers are specified, all data are 'outliers'.
19309 // We compute the outliers as indices, so that we can join across transitions!
19310 var outlierIndices = whiskerIndices ?
19311 d3.range(0, whiskerIndices[0]).concat(d3.range(whiskerIndices[1] + 1, n)) : d3.range(n);
19312
19313 // Compute the new x-scale.
19314 var x1 = d3.scale.linear()
19315 .domain(domain && domain.call(this, d, i) || [min, max])
19316 .range([height, 0]);
19317
19318 // Retrieve the old x-scale, if this is an update.
19319 var x0 = this.__chart__ || d3.scale.linear()
19320 .domain([0, Infinity])
19321 .range(x1.range());
19322
19323 // Stash the new scale.
19324 this.__chart__ = x1;
19325
19326 // Note: the box, median, and box tick elements are fixed in number,
19327 // so we only have to handle enter and update. In contrast, the outliers
19328 // and other elements are variable, so we need to exit them! Variable
19329 // elements also fade in and out.
19330
19331 // Update center line: the vertical line spanning the whiskers.
19332 var center = g.selectAll('line.center')
19333 .data(whiskerData ? [whiskerData] : []);
19334
19335 center.enter().insert('line', 'rect')
19336 .attr('class', 'center')
19337 .attr('x1', width / 2)
19338 .attr('y1', function (d) { return x0(d[0]); })
19339 .attr('x2', width / 2)
19340 .attr('y2', function (d) { return x0(d[1]); })
19341 .style('opacity', 1e-6)
19342 .transition()
19343 .duration(duration)
19344 .style('opacity', 1)
19345 .attr('y1', function (d) { return x1(d[0]); })
19346 .attr('y2', function (d) { return x1(d[1]); });
19347
19348 center.transition()
19349 .duration(duration)
19350 .style('opacity', 1)
19351 .attr('y1', function (d) { return x1(d[0]); })
19352 .attr('y2', function (d) { return x1(d[1]); });
19353
19354 center.exit().transition()
19355 .duration(duration)
19356 .style('opacity', 1e-6)
19357 .attr('y1', function (d) { return x1(d[0]); })
19358 .attr('y2', function (d) { return x1(d[1]); })
19359 .remove();
19360
19361 // Update innerquartile box.
19362 var box = g.selectAll('rect.box')
19363 .data([quartileData]);
19364
19365 box.enter().append('rect')
19366 .attr('class', 'box')
19367 .attr('x', 0)
19368 .attr('y', function (d) { return x0(d[2]); })
19369 .attr('width', width)
19370 .attr('height', function (d) { return x0(d[0]) - x0(d[2]); })
19371 .transition()
19372 .duration(duration)
19373 .attr('y', function (d) { return x1(d[2]); })
19374 .attr('height', function (d) { return x1(d[0]) - x1(d[2]); });
19375
19376 box.transition()
19377 .duration(duration)
19378 .attr('y', function (d) { return x1(d[2]); })
19379 .attr('height', function (d) { return x1(d[0]) - x1(d[2]); });
19380
19381 // Update median line.
19382 var medianLine = g.selectAll('line.median')
19383 .data([quartileData[1]]);
19384
19385 medianLine.enter().append('line')
19386 .attr('class', 'median')
19387 .attr('x1', 0)
19388 .attr('y1', x0)
19389 .attr('x2', width)
19390 .attr('y2', x0)
19391 .transition()
19392 .duration(duration)
19393 .attr('y1', x1)
19394 .attr('y2', x1);
19395
19396 medianLine.transition()
19397 .duration(duration)
19398 .attr('y1', x1)
19399 .attr('y2', x1);
19400
19401 // Update whiskers.
19402 var whisker = g.selectAll('line.whisker')
19403 .data(whiskerData || []);
19404
19405 whisker.enter().insert('line', 'circle, text')
19406 .attr('class', 'whisker')
19407 .attr('x1', 0)
19408 .attr('y1', x0)
19409 .attr('x2', width)
19410 .attr('y2', x0)
19411 .style('opacity', 1e-6)
19412 .transition()
19413 .duration(duration)
19414 .attr('y1', x1)
19415 .attr('y2', x1)
19416 .style('opacity', 1);
19417
19418 whisker.transition()
19419 .duration(duration)
19420 .attr('y1', x1)
19421 .attr('y2', x1)
19422 .style('opacity', 1);
19423
19424 whisker.exit().transition()
19425 .duration(duration)
19426 .attr('y1', x1)
19427 .attr('y2', x1)
19428 .style('opacity', 1e-6)
19429 .remove();
19430
19431 // Update outliers.
19432 var outlier = g.selectAll('circle.outlier')
19433 .data(outlierIndices, Number);
19434
19435 outlier.enter().insert('circle', 'text')
19436 .attr('class', 'outlier')
19437 .attr('r', 5)
19438 .attr('cx', width / 2)
19439 .attr('cy', function (i) { return x0(d[i]); })
19440 .style('opacity', 1e-6)
19441 .transition()
19442 .duration(duration)
19443 .attr('cy', function (i) { return x1(d[i]); })
19444 .style('opacity', 1);
19445
19446 outlier.transition()
19447 .duration(duration)
19448 .attr('cy', function (i) { return x1(d[i]); })
19449 .style('opacity', 1);
19450
19451 outlier.exit().transition()
19452 .duration(duration)
19453 .attr('cy', function (i) { return x1(d[i]); })
19454 .style('opacity', 1e-6)
19455 .remove();
19456
19457 // Compute the tick format.
19458 var format = tickFormat || x1.tickFormat(8);
19459
19460 // Update box ticks.
19461 var boxTick = g.selectAll('text.box')
19462 .data(quartileData);
19463
19464 boxTick.enter().append('text')
19465 .attr('class', 'box')
19466 .attr('dy', '.3em')
19467 .attr('dx', function (d, i) { return i & 1 ? 6 : -6; })
19468 .attr('x', function (d, i) { return i & 1 ? width : 0; })
19469 .attr('y', x0)
19470 .attr('text-anchor', function (d, i) { return i & 1 ? 'start' : 'end'; })
19471 .text(format)
19472 .transition()
19473 .duration(duration)
19474 .attr('y', x1);
19475
19476 boxTick.transition()
19477 .duration(duration)
19478 .text(format)
19479 .attr('y', x1);
19480
19481 // Update whisker ticks. These are handled separately from the box
19482 // ticks because they may or may not exist, and we want don't want
19483 // to join box ticks pre-transition with whisker ticks post-.
19484 var whiskerTick = g.selectAll('text.whisker')
19485 .data(whiskerData || []);
19486
19487 whiskerTick.enter().append('text')
19488 .attr('class', 'whisker')
19489 .attr('dy', '.3em')
19490 .attr('dx', 6)
19491 .attr('x', width)
19492 .attr('y', x0)
19493 .text(format)
19494 .style('opacity', 1e-6)
19495 .transition()
19496 .duration(duration)
19497 .attr('y', x1)
19498 .style('opacity', 1);
19499
19500 whiskerTick.transition()
19501 .duration(duration)
19502 .text(format)
19503 .attr('y', x1)
19504 .style('opacity', 1);
19505
19506 whiskerTick.exit().transition()
19507 .duration(duration)
19508 .attr('y', x1)
19509 .style('opacity', 1e-6)
19510 .remove();
19511 });
19512 d3.timer.flush();
19513 }
19514
19515 box.width = function (x) {
19516 if (!arguments.length) {
19517 return width;
19518 }
19519 width = x;
19520 return box;
19521 };
19522
19523 box.height = function (x) {
19524 if (!arguments.length) {
19525 return height;
19526 }
19527 height = x;
19528 return box;
19529 };
19530
19531 box.tickFormat = function (x) {
19532 if (!arguments.length) {
19533 return tickFormat;
19534 }
19535 tickFormat = x;
19536 return box;
19537 };
19538
19539 box.duration = function (x) {
19540 if (!arguments.length) {
19541 return duration;
19542 }
19543 duration = x;
19544 return box;
19545 };
19546
19547 box.domain = function (x) {
19548 if (!arguments.length) {
19549 return domain;
19550 }
19551 domain = x === null ? x : d3.functor(x);
19552 return box;
19553 };
19554
19555 box.value = function (x) {
19556 if (!arguments.length) {
19557 return value;
19558 }
19559 value = x;
19560 return box;
19561 };
19562
19563 box.whiskers = function (x) {
19564 if (!arguments.length) {
19565 return whiskers;
19566 }
19567 whiskers = x;
19568 return box;
19569 };
19570
19571 box.quartiles = function (x) {
19572 if (!arguments.length) {
19573 return quartiles;
19574 }
19575 quartiles = x;
19576 return box;
19577 };
19578
19579 return box;
19580 };
19581
19582 function boxWhiskers(d) {
19583 return [0, d.length - 1];
19584 }
19585
19586 function boxQuartiles(d) {
19587 return [
19588 d3.quantile(d, 0.25),
19589 d3.quantile(d, 0.5),
19590 d3.quantile(d, 0.75)
19591 ];
19592 }
19593
19594 })();
19595
19596 /**
19597 ## Box Plot
19598
19599 Includes: [Coordinate Grid Mixin](#coordinate-grid-mixin)
19600
19601 A box plot is a chart that depicts numerical data via their quartile ranges.
19602
19603 #### dc.boxPlot(parent[, chartGroup])
19604 Create a box plot instance and attach it to the given parent element.
19605
19606 Parameters:
19607 * parent : string | node | selection - any valid
19608 [d3 single selector](https://github.com/mbostock/d3/wiki/Selections#selecting-elements) representing
19609 a dom block element such as a div; or a dom element or d3 selection.
19610 * chartGroup : string (optional) - name of the chart group this chart instance should be placed in.
19611 Interaction with a chart will only trigger events and redraws within the chart's group.
19612
19613 Returns:
19614 A newly created box plot instance
19615
19616 ```js
19617 // create a box plot under #chart-container1 element using the default global chart group
19618 var boxPlot1 = dc.boxPlot('#chart-container1');
19619 // create a box plot under #chart-container2 element using chart group A
19620 var boxPlot2 = dc.boxPlot('#chart-container2', 'chartGroupA');
19621 ```
19622
19623 **/
19624 dc.boxPlot = function (parent, chartGroup) {
19625 var _chart = dc.coordinateGridMixin({});
19626
19627 // Returns a function to compute the interquartile range.
19628 function DEFAULT_WHISKERS_IQR (k) {
19629 return function (d) {
19630 var q1 = d.quartiles[0],
19631 q3 = d.quartiles[2],
19632 iqr = (q3 - q1) * k,
19633 i = -1,
19634 j = d.length;
19635 /*jshint -W116*/
19636 /*jshint -W035*/
19637 while (d[++i] < q1 - iqr) {}
19638 while (d[--j] > q3 + iqr) {}
19639 /*jshint +W116*/
19640 return [i, j];
19641 /*jshint +W035*/
19642 };
19643 }
19644
19645 var _whiskerIqrFactor = 1.5;
19646 var _whiskersIqr = DEFAULT_WHISKERS_IQR;
19647 var _whiskers = _whiskersIqr(_whiskerIqrFactor);
19648
19649 var _box = d3.box();
19650 var _tickFormat = null;
19651
19652 var _boxWidth = function (innerChartWidth, xUnits) {
19653 if (_chart.isOrdinal()) {
19654 return _chart.x().rangeBand();
19655 } else {
19656 return innerChartWidth / (1 + _chart.boxPadding()) / xUnits;
19657 }
19658 };
19659
19660 // default padding to handle min/max whisker text
19661 _chart.yAxisPadding(12);
19662
19663 // default to ordinal
19664 _chart.x(d3.scale.ordinal());
19665 _chart.xUnits(dc.units.ordinal);
19666
19667 // valueAccessor should return an array of values that can be coerced into numbers
19668 // or if data is overloaded for a static array of arrays, it should be `Number`.
19669 // Empty arrays are not included.
19670 _chart.data(function (group) {
19671 return group.all().map(function (d) {
19672 d.map = function (accessor) { return accessor.call(d, d); };
19673 return d;
19674 }).filter(function (d) {
19675 var values = _chart.valueAccessor()(d);
19676 return values.length !== 0;
19677 });
19678 });
19679
19680 /**
19681 #### .boxPadding([padding])
19682 Get or set the spacing between boxes as a fraction of box size. Valid values are within 0-1.
19683 See the [d3 docs](https://github.com/mbostock/d3/wiki/Ordinal-Scales#wiki-ordinal_rangeBands)
19684 for a visual description of how the padding is applied.
19685
19686 Default: 0.8
19687 **/
19688 _chart.boxPadding = _chart._rangeBandPadding;
19689 _chart.boxPadding(0.8);
19690
19691 /**
19692 #### .outerPadding([padding])
19693 Get or set the outer padding on an ordinal box chart. This setting has no effect on non-ordinal charts
19694 or on charts with a custom `.boxWidth`. Will pad the width by `padding * barWidth` on each side of the chart.
19695
19696 Default: 0.5
19697 **/
19698 _chart.outerPadding = _chart._outerRangeBandPadding;
19699 _chart.outerPadding(0.5);
19700
19701 /**
19702 #### .boxWidth(width || function(innerChartWidth, xUnits) { ... })
19703 Get or set the numerical width of the boxplot box. The width may also be a function taking as
19704 parameters the chart width excluding the right and left margins, as well as the number of x
19705 units.
19706 **/
19707 _chart.boxWidth = function (_) {
19708 if (!arguments.length) {
19709 return _boxWidth;
19710 }
19711 _boxWidth = d3.functor(_);
19712 return _chart;
19713 };
19714
19715 var boxTransform = function (d, i) {
19716 var xOffset = _chart.x()(_chart.keyAccessor()(d, i));
19717 return 'translate(' + xOffset + ', 0)';
19718 };
19719
19720 _chart._preprocessData = function () {
19721 if (_chart.elasticX()) {
19722 _chart.x().domain([]);
19723 }
19724 };
19725
19726 _chart.plotData = function () {
19727 var _calculatedBoxWidth = _boxWidth(_chart.effectiveWidth(), _chart.xUnitCount());
19728
19729 _box.whiskers(_whiskers)
19730 .width(_calculatedBoxWidth)
19731 .height(_chart.effectiveHeight())
19732 .value(_chart.valueAccessor())
19733 .domain(_chart.y().domain())
19734 .duration(_chart.transitionDuration())
19735 .tickFormat(_tickFormat);
19736
19737 var boxesG = _chart.chartBodyG().selectAll('g.box').data(_chart.data(), function (d) { return d.key; });
19738
19739 renderBoxes(boxesG);
19740 updateBoxes(boxesG);
19741 removeBoxes(boxesG);
19742
19743 _chart.fadeDeselectedArea();
19744 };
19745
19746 function renderBoxes(boxesG) {
19747 var boxesGEnter = boxesG.enter().append('g');
19748
19749 boxesGEnter
19750 .attr('class', 'box')
19751 .attr('transform', boxTransform)
19752 .call(_box)
19753 .on('click', function (d) {
19754 _chart.filter(d.key);
19755 _chart.redrawGroup();
19756 });
19757 }
19758
19759 function updateBoxes(boxesG) {
19760 dc.transition(boxesG, _chart.transitionDuration())
19761 .attr('transform', boxTransform)
19762 .call(_box)
19763 .each(function () {
19764 d3.select(this).select('rect.box').attr('fill', _chart.getColor);
19765 });
19766 }
19767
19768 function removeBoxes(boxesG) {
19769 boxesG.exit().remove().call(_box);
19770 }
19771
19772 _chart.fadeDeselectedArea = function () {
19773 if (_chart.hasFilter()) {
19774 _chart.g().selectAll('g.box').each(function (d) {
19775 if (_chart.isSelectedNode(d)) {
19776 _chart.highlightSelected(this);
19777 } else {
19778 _chart.fadeDeselected(this);
19779 }
19780 });
19781 } else {
19782 _chart.g().selectAll('g.box').each(function () {
19783 _chart.resetHighlight(this);
19784 });
19785 }
19786 };
19787
19788 _chart.isSelectedNode = function (d) {
19789 return _chart.hasFilter(d.key);
19790 };
19791
19792 _chart.yAxisMin = function () {
19793 var min = d3.min(_chart.data(), function (e) {
19794 return d3.min(_chart.valueAccessor()(e));
19795 });
19796 return dc.utils.subtract(min, _chart.yAxisPadding());
19797 };
19798
19799 _chart.yAxisMax = function () {
19800 var max = d3.max(_chart.data(), function (e) {
19801 return d3.max(_chart.valueAccessor()(e));
19802 });
19803 return dc.utils.add(max, _chart.yAxisPadding());
19804 };
19805
19806 /**
19807 #### .tickFormat()
19808 Set the numerical format of the boxplot median, whiskers and quartile labels. Defaults to
19809 integer formatting.
19810 ```js
19811 // format ticks to 2 decimal places
19812 chart.tickFormat(d3.format('.2f'));
19813 ```
19814 **/
19815 _chart.tickFormat = function (x) {
19816 if (!arguments.length) {
19817 return _tickFormat;
19818 }
19819 _tickFormat = x;
19820 return _chart;
19821 };
19822
19823 return _chart.anchor(parent, chartGroup);
19824 };
19825
19826 // Renamed functions
19827
19828 dc.abstractBubbleChart = dc.bubbleMixin;
19829 dc.baseChart = dc.baseMixin;
19830 dc.capped = dc.capMixin;
19831 dc.colorChart = dc.colorMixin;
19832 dc.coordinateGridChart = dc.coordinateGridMixin;
19833 dc.marginable = dc.marginMixin;
19834 dc.stackableChart = dc.stackMixin;
19835
19836 // Expose d3 and crossfilter, so that clients in browserify
19837 // case can obtain them if they need them.
19838 dc.d3 = d3;
19839 dc.crossfilter = crossfilter;
19840
19841 return dc;}
19842 if(typeof define === "function" && define.amd) {
19843 define(["d3", "crossfilter"], _dc);
19844 } else if(typeof module === "object" && module.exports) {
19845 var _d3 = require('d3');
19846 var _crossfilter = require('crossfilter');
19847 // When using npm + browserify, 'crossfilter' is a function,
19848 // since package.json specifies index.js as main function, and it
19849 // does special handling. When using bower + browserify,
19850 // there's no main in bower.json (in fact, there's no bower.json),
19851 // so we need to fix it.
19852 if (typeof _crossfilter !== "function") {
19853 _crossfilter = _crossfilter.crossfilter;
19854 }
19855 module.exports = _dc(_d3, _crossfilter);
19856 } else {
19857 this.dc = _dc(d3, crossfilter);
19858 }
19859 }
19860 )();
19861 </script>
19862
19863 <script type="text/javascript">
19864
19865 // ### Create Chart Objects
19866 // Create chart objects assocated with the container elements identified by the css selector.
19867 // Note: It is often a good idea to have these objects accessible at the global scope so that they can be modified or
19868 // filtered by other page controls.
19869 var ringCountChart = dc.barChart("#chart-bar-ring"),
19870 pdbCountChart = dc.rowChart("#chart-row-pdb");
19871
19872 //### Load your data
19873 //Data can be loaded through regular means with your
19874 //favorite javascript library
19875 //
19876 //```javascript
19877 //d3.csv('data.csv', function(data) {...};
19878 //d3.json('data.json', function(data) {...};
19879 //jQuery.getJson('data.json', function(data){...});
19880 //```
19881 //d3.json('pucker_table2.json', function(error,data) {
19882
19883 var data = [
19884 {
19885 "contextconformer": "C4A|C|C1A",
19886 "resname": "CTR",
19887 "resid": 211,
19888 "chain": "A",
19889 "pdbid": "example-pdb-4ENG",
19890 "ringsize": 6,
19891 "origconformer": "4C1",
19892 "puckercoords": [
19893 "-35.39",
19894 "-38.18",
19895 "-30.29"
19896 ],
19897 "conformer": "4C1",
19898 "ringorder": [
19899 "C3A",
19900 "C4A",
19901 "C5A",
19902 "O5A",
19903 "C1A",
19904 "C2A"
19905 ]
19906 },
19907 {
19908 "contextconformer": "C4B|C|C1B",
19909 "resname": "CTR",
19910 "resid": 211,
19911 "chain": "A",
19912 "pdbid": "example-pdb-4ENG",
19913 "ringsize": 6,
19914 "origconformer": "4C1",
19915 "puckercoords": [
19916 "-36.82",
19917 "-37.04",
19918 "-29.22"
19919 ],
19920 "conformer": "4C1",
19921 "ringorder": [
19922 "C3B",
19923 "C4B",
19924 "C5B",
19925 "O5B",
19926 "C1B",
19927 "C2B"
19928 ]
19929 },
19930 {
19931 "contextconformer": "C4C|C|C1C",
19932 "resname": "CTR",
19933 "resid": 211,
19934 "chain": "A",
19935 "pdbid": "example-pdb-4ENG",
19936 "ringsize": 6,
19937 "origconformer": "4C1",
19938 "puckercoords": [
19939 "-31.42",
19940 "-41.33",
19941 "-32.69"
19942 ],
19943 "conformer": "4C1",
19944 "ringorder": [
19945 "C3C",
19946 "C4C",
19947 "C5C",
19948 "O5C",
19949 "C1C",
19950 "C2C"
19951 ]
19952 },
19953 {
19954 "contextconformer": "C4A|C|C1A",
19955 "resname": "CTR",
19956 "resid": 212,
19957 "chain": "A",
19958 "pdbid": "example-pdb-4ENG",
19959 "ringsize": 6,
19960 "origconformer": "4C1",
19961 "puckercoords": [
19962 "-33.97",
19963 "-37.84",
19964 "-32.04"
19965 ],
19966 "conformer": "4C1",
19967 "ringorder": [
19968 "C3A",
19969 "C4A",
19970 "C5A",
19971 "O5A",
19972 "C1A",
19973 "C2A"
19974 ]
19975 },
19976 {
19977 "contextconformer": "C4B|C|C1B",
19978 "resname": "CTR",
19979 "resid": 212,
19980 "chain": "A",
19981 "pdbid": "example-pdb-4ENG",
19982 "ringsize": 6,
19983 "origconformer": "4C1",
19984 "puckercoords": [
19985 "-23.66",
19986 "-39.91",
19987 "-37.59"
19988 ],
19989 "conformer": "4C1",
19990 "ringorder": [
19991 "C3B",
19992 "C4B",
19993 "C5B",
19994 "O5B",
19995 "C1B",
19996 "C2B"
19997 ]
19998 },
19999 {
20000 "contextconformer": "C2C|H|C1C",
20001 "resname": "CTR",
20002 "resid": 212,
20003 "chain": "A",
20004 "pdbid": "example-pdb-4ENG",
20005 "ringsize": 6,
20006 "origconformer": "4C1",
20007 "puckercoords": [
20008 "-27.59",
20009 "-47.95",
20010 "-31.47"
20011 ],
20012 "conformer": "2H1",
20013 "ringorder": [
20014 "C3C",
20015 "C4C",
20016 "C5C",
20017 "O5C",
20018 "C1C",
20019 "C2C"
20020 ]
20021 },
20022 {
20023 "contextconformer": "C46|E|",
20024 "resname": "BCD",
20025 "resid": 1403,
20026 "chain": "A",
20027 "pdbid": "bcd.pdb",
20028 "ringsize": 6,
20029 "origconformer": "4E",
20030 "puckercoords": [
20031 "-49.01",
20032 "43.18",
20033 "-58.10"
20034 ],
20035 "conformer": "4E",
20036 "ringorder": [
20037 "C36",
20038 "C46",
20039 "C56",
20040 "O56",
20041 "C16",
20042 "C26"
20043 ]
20044 },
20045 {
20046 "contextconformer": "C15C45|B|",
20047 "resname": "BCD",
20048 "resid": 1403,
20049 "chain": "A",
20050 "pdbid": "bcd.pdb",
20051 "ringsize": 6,
20052 "origconformer": "14B",
20053 "puckercoords": [
20054 "-49.88",
20055 "60.71",
20056 "-25.47"
20057 ],
20058 "conformer": "14B",
20059 "ringorder": [
20060 "C35",
20061 "C45",
20062 "C55",
20063 "O55",
20064 "C15",
20065 "C25"
20066 ]
20067 },
20068 {
20069 "contextconformer": "C14|S|C54",
20070 "resname": "BCD",
20071 "resid": 1403,
20072 "chain": "A",
20073 "pdbid": "bcd.pdb",
20074 "ringsize": 6,
20075 "origconformer": "1S5",
20076 "puckercoords": [
20077 "-55.88",
20078 "47.15",
20079 "-31.89"
20080 ],
20081 "conformer": "1S5",
20082 "ringorder": [
20083 "C34",
20084 "C44",
20085 "C54",
20086 "O54",
20087 "C14",
20088 "C24"
20089 ]
20090 },
20091 {
20092 "contextconformer": "C13|S|C33",
20093 "resname": "BCD",
20094 "resid": 1403,
20095 "chain": "A",
20096 "pdbid": "bcd.pdb",
20097 "ringsize": 6,
20098 "origconformer": "1S3",
20099 "puckercoords": [
20100 "-12.03",
20101 "67.62",
20102 "-53.26"
20103 ],
20104 "conformer": "1S3",
20105 "ringorder": [
20106 "C33",
20107 "C43",
20108 "C53",
20109 "O53",
20110 "C13",
20111 "C23"
20112 ]
20113 },
20114 {
20115 "contextconformer": "C12|S|C52",
20116 "resname": "BCD",
20117 "resid": 1403,
20118 "chain": "A",
20119 "pdbid": "bcd.pdb",
20120 "ringsize": 6,
20121 "origconformer": "1S5",
20122 "puckercoords": [
20123 "-64.39",
20124 "43.65",
20125 "-5.11"
20126 ],
20127 "conformer": "1S5",
20128 "ringorder": [
20129 "C32",
20130 "C42",
20131 "C52",
20132 "O52",
20133 "C12",
20134 "C22"
20135 ]
20136 },
20137 {
20138 "contextconformer": "C47|C|C17",
20139 "resname": "BCD",
20140 "resid": 1403,
20141 "chain": "A",
20142 "pdbid": "bcd.pdb",
20143 "ringsize": 6,
20144 "origconformer": "4C1",
20145 "puckercoords": [
20146 "-30.55",
20147 "-33.09",
20148 "-47.08"
20149 ],
20150 "conformer": "4C1",
20151 "ringorder": [
20152 "C37",
20153 "C47",
20154 "C57",
20155 "O57",
20156 "C17",
20157 "C27"
20158 ]
20159 },
20160 {
20161 "contextconformer": "C41|H|C51",
20162 "resname": "BCD",
20163 "resid": 1403,
20164 "chain": "A",
20165 "pdbid": "bcd.pdb",
20166 "ringsize": 6,
20167 "origconformer": "4C1",
20168 "puckercoords": [
20169 "-55.66",
20170 "-17.72",
20171 "-25.25"
20172 ],
20173 "conformer": "4H5",
20174 "ringorder": [
20175 "C31",
20176 "C41",
20177 "C51",
20178 "O51",
20179 "C11",
20180 "C21"
20181 ]
20182 },
20183 {
20184 "contextconformer": "TS3",
20185 "resname": "BCD",
20186 "resid": 1403,
20187 "chain": "A",
20188 "pdbid": "bcd.pdb",
20189 "ringsize": 7,
20190 "origconformer": "TS3",
20191 "puckercoords": [
20192 "14.00",
20193 "-12.28",
20194 "4.84",
20195 "15.42"
20196 ],
20197 "conformer": "TS3",
20198 "ringorder": [
20199 "C11C21C31C41C51O51",
20200 "C12C22C32C42C52O52",
20201 "C13C23C33C43C53O53",
20202 "C14C24C34C44C54O54",
20203 "C15C25C35C45C55O55",
20204 "C16C26C36C46C56O56",
20205 "C17C27C37C47C57O57"
20206 ]
20207 },
20208 {
20209 "contextconformer": "C4'|C|C1'",
20210 "resname": "MAL",
20211 "resid": 687,
20212 "chain": "A",
20213 "pdbid": "1CXF.pdb",
20214 "ringsize": 6,
20215 "origconformer": "4C1",
20216 "puckercoords": [
20217 "-36.73",
20218 "-32.29",
20219 "-29.30"
20220 ],
20221 "conformer": "4C1",
20222 "ringorder": [
20223 "C3'",
20224 "C4'",
20225 "C5'",
20226 "O5'",
20227 "C1'",
20228 "C2'"
20229 ]
20230 },
20231 {
20232 "contextconformer": "C4|C|C1",
20233 "resname": "MAL",
20234 "resid": 687,
20235 "chain": "A",
20236 "pdbid": "1CXF.pdb",
20237 "ringsize": 6,
20238 "origconformer": "4C1",
20239 "puckercoords": [
20240 "-32.33",
20241 "-31.02",
20242 "-30.31"
20243 ],
20244 "conformer": "4C1",
20245 "ringorder": [
20246 "C3",
20247 "C4",
20248 "C5",
20249 "O5",
20250 "C1",
20251 "C2"
20252 ]
20253 },
20254 {
20255 "contextconformer": "C2D|H|C3D",
20256 "resname": "ACX",
20257 "resid": 688,
20258 "chain": "A",
20259 "pdbid": "1CXF.pdb",
20260 "ringsize": 6,
20261 "origconformer": "4C1",
20262 "puckercoords": [
20263 "-21.97",
20264 "-31.68",
20265 "-34.65"
20266 ],
20267 "conformer": "2H3",
20268 "ringorder": [
20269 "C3D",
20270 "C4D",
20271 "C5D",
20272 "O5D",
20273 "C1D",
20274 "C2D"
20275 ]
20276 },
20277 {
20278 "contextconformer": "C2E|H|C3E",
20279 "resname": "ACX",
20280 "resid": 688,
20281 "chain": "A",
20282 "pdbid": "1CXF.pdb",
20283 "ringsize": 6,
20284 "origconformer": "4C1",
20285 "puckercoords": [
20286 "-17.75",
20287 "-34.68",
20288 "-37.57"
20289 ],
20290 "conformer": "2H3",
20291 "ringorder": [
20292 "C3E",
20293 "C4E",
20294 "C5E",
20295 "O5E",
20296 "C1E",
20297 "C2E"
20298 ]
20299 },
20300 {
20301 "contextconformer": "C4B|C|C1B",
20302 "resname": "ACX",
20303 "resid": 688,
20304 "chain": "A",
20305 "pdbid": "1CXF.pdb",
20306 "ringsize": 6,
20307 "origconformer": "4C1",
20308 "puckercoords": [
20309 "-34.55",
20310 "-37.81",
20311 "-29.07"
20312 ],
20313 "conformer": "4C1",
20314 "ringorder": [
20315 "C3B",
20316 "C4B",
20317 "C5B",
20318 "O5B",
20319 "C1B",
20320 "C2B"
20321 ]
20322 },
20323 {
20324 "contextconformer": "C4A|C|C1A",
20325 "resname": "ACX",
20326 "resid": 688,
20327 "chain": "A",
20328 "pdbid": "1CXF.pdb",
20329 "ringsize": 6,
20330 "origconformer": "4C1",
20331 "puckercoords": [
20332 "-35.62",
20333 "-28.65",
20334 "-33.39"
20335 ],
20336 "conformer": "4C1",
20337 "ringorder": [
20338 "C3A",
20339 "C4A",
20340 "C5A",
20341 "O5A",
20342 "C1A",
20343 "C2A"
20344 ]
20345 },
20346 {
20347 "contextconformer": "C4C|C|C1C",
20348 "resname": "ACX",
20349 "resid": 688,
20350 "chain": "A",
20351 "pdbid": "1CXF.pdb",
20352 "ringsize": 6,
20353 "origconformer": "4C1",
20354 "puckercoords": [
20355 "-26.33",
20356 "-39.11",
20357 "-29.79"
20358 ],
20359 "conformer": "4C1",
20360 "ringorder": [
20361 "C3C",
20362 "C4C",
20363 "C5C",
20364 "O5C",
20365 "C1C",
20366 "C2C"
20367 ]
20368 },
20369 {
20370 "contextconformer": "C2F|H|C1F",
20371 "resname": "ACX",
20372 "resid": 688,
20373 "chain": "A",
20374 "pdbid": "1CXF.pdb",
20375 "ringsize": 6,
20376 "origconformer": "4C1",
20377 "puckercoords": [
20378 "-23.27",
20379 "-39.92",
20380 "-32.61"
20381 ],
20382 "conformer": "2H1",
20383 "ringorder": [
20384 "C3F",
20385 "C4F",
20386 "C5F",
20387 "O5F",
20388 "C1F",
20389 "C2F"
20390 ]
20391 },
20392 {
20393 "contextconformer": "|P|",
20394 "resname": "ACX",
20395 "resid": 688,
20396 "chain": "A",
20397 "pdbid": "1CXF.pdb",
20398 "ringsize": 6,
20399 "origconformer": "P",
20400 "puckercoords": [
20401 "-1.21",
20402 "0.16",
20403 "9.59"
20404 ],
20405 "conformer": "P",
20406 "ringorder": [
20407 "C1AC2AC3AC4AC5AO5A",
20408 "C1BC2BC3BC4BC5BO5B",
20409 "C1CC2CC3CC4CC5CO5C",
20410 "C1DC2DC3DC4DC5DO5D",
20411 "C1EC2EC3EC4EC5EO5E",
20412 "C1FC2FC3FC4FC5FO5F"
20413 ]
20414 },
20415 {
20416 "contextconformer": "C4D|C|C1D",
20417 "resname": "ACX",
20418 "resid": 689,
20419 "chain": "A",
20420 "pdbid": "1CXF.pdb",
20421 "ringsize": 6,
20422 "origconformer": "4C1",
20423 "puckercoords": [
20424 "-28.16",
20425 "-33.78",
20426 "-36.69"
20427 ],
20428 "conformer": "4C1",
20429 "ringorder": [
20430 "C3D",
20431 "C4D",
20432 "C5D",
20433 "O5D",
20434 "C1D",
20435 "C2D"
20436 ]
20437 },
20438 {
20439 "contextconformer": "C4E|C|C1E",
20440 "resname": "ACX",
20441 "resid": 689,
20442 "chain": "A",
20443 "pdbid": "1CXF.pdb",
20444 "ringsize": 6,
20445 "origconformer": "4C1",
20446 "puckercoords": [
20447 "-30.39",
20448 "-39.03",
20449 "-31.50"
20450 ],
20451 "conformer": "4C1",
20452 "ringorder": [
20453 "C3E",
20454 "C4E",
20455 "C5E",
20456 "O5E",
20457 "C1E",
20458 "C2E"
20459 ]
20460 },
20461 {
20462 "contextconformer": "O5B|H|C1B",
20463 "resname": "ACX",
20464 "resid": 689,
20465 "chain": "A",
20466 "pdbid": "1CXF.pdb",
20467 "ringsize": 6,
20468 "origconformer": "4C1",
20469 "puckercoords": [
20470 "-30.40",
20471 "-41.45",
20472 "-24.24"
20473 ],
20474 "conformer": "6H1",
20475 "ringorder": [
20476 "C3B",
20477 "C4B",
20478 "C5B",
20479 "O5B",
20480 "C1B",
20481 "C2B"
20482 ]
20483 },
20484 {
20485 "contextconformer": "C2A|H|C1A",
20486 "resname": "ACX",
20487 "resid": 689,
20488 "chain": "A",
20489 "pdbid": "1CXF.pdb",
20490 "ringsize": 6,
20491 "origconformer": "4C1",
20492 "puckercoords": [
20493 "-21.99",
20494 "-38.95",
20495 "-30.36"
20496 ],
20497 "conformer": "2H1",
20498 "ringorder": [
20499 "C3A",
20500 "C4A",
20501 "C5A",
20502 "O5A",
20503 "C1A",
20504 "C2A"
20505 ]
20506 },
20507 {
20508 "contextconformer": "C4C|C|C1C",
20509 "resname": "ACX",
20510 "resid": 689,
20511 "chain": "A",
20512 "pdbid": "1CXF.pdb",
20513 "ringsize": 6,
20514 "origconformer": "4C1",
20515 "puckercoords": [
20516 "-26.53",
20517 "-42.79",
20518 "-33.89"
20519 ],
20520 "conformer": "4C1",
20521 "ringorder": [
20522 "C3C",
20523 "C4C",
20524 "C5C",
20525 "O5C",
20526 "C1C",
20527 "C2C"
20528 ]
20529 },
20530 {
20531 "contextconformer": "C2F|H|C1F",
20532 "resname": "ACX",
20533 "resid": 689,
20534 "chain": "A",
20535 "pdbid": "1CXF.pdb",
20536 "ringsize": 6,
20537 "origconformer": "4C1",
20538 "puckercoords": [
20539 "-21.92",
20540 "-42.21",
20541 "-25.15"
20542 ],
20543 "conformer": "2H1",
20544 "ringorder": [
20545 "C3F",
20546 "C4F",
20547 "C5F",
20548 "O5F",
20549 "C1F",
20550 "C2F"
20551 ]
20552 },
20553 {
20554 "contextconformer": "|P|",
20555 "resname": "ACX",
20556 "resid": 689,
20557 "chain": "A",
20558 "pdbid": "1CXF.pdb",
20559 "ringsize": 6,
20560 "origconformer": "P",
20561 "puckercoords": [
20562 "6.61",
20563 "-6.67",
20564 "13.64"
20565 ],
20566 "conformer": "P",
20567 "ringorder": [
20568 "C1AC2AC3AC4AC5AO5A",
20569 "C1BC2BC3BC4BC5BO5B",
20570 "C1CC2CC3CC4CC5CO5C",
20571 "C1DC2DC3DC4DC5DO5D",
20572 "C1EC2EC3EC4EC5EO5E",
20573 "C1FC2FC3FC4FC5FO5F"
20574 ]
20575 },
20576 {
20577 "contextconformer": "C2|H|C3",
20578 "resname": "GLC",
20579 "resid": 692,
20580 "chain": "A",
20581 "pdbid": "1CXF.pdb",
20582 "ringsize": 6,
20583 "origconformer": "4C1",
20584 "puckercoords": [
20585 "-21.92",
20586 "-23.11",
20587 "-39.86"
20588 ],
20589 "conformer": "2H3",
20590 "ringorder": [
20591 "C3",
20592 "C4",
20593 "C5",
20594 "O5",
20595 "C1",
20596 "C2"
20597 ]
20598 },
20599 {
20600 "contextconformer": "C2|H|C3",
20601 "resname": "GLC",
20602 "resid": 693,
20603 "chain": "A",
20604 "pdbid": "1CXF.pdb",
20605 "ringsize": 6,
20606 "origconformer": "4C1",
20607 "puckercoords": [
20608 "-23.21",
20609 "-27.35",
20610 "-45.33"
20611 ],
20612 "conformer": "2H3",
20613 "ringorder": [
20614 "C3",
20615 "C4",
20616 "C5",
20617 "O5",
20618 "C1",
20619 "C2"
20620 ]
20621 },
20622 {
20623 "contextconformer": "C4|H|C5",
20624 "resname": "GLC",
20625 "resid": 694,
20626 "chain": "A",
20627 "pdbid": "1CXF.pdb",
20628 "ringsize": 6,
20629 "origconformer": "4C1",
20630 "puckercoords": [
20631 "-35.13",
20632 "-19.34",
20633 "-33.50"
20634 ],
20635 "conformer": "4H5",
20636 "ringorder": [
20637 "C3",
20638 "C4",
20639 "C5",
20640 "O5",
20641 "C1",
20642 "C2"
20643 ]
20644 },
20645 {
20646 "contextconformer": "C4|C|C1",
20647 "resname": "GLC",
20648 "resid": 695,
20649 "chain": "A",
20650 "pdbid": "1CXF.pdb",
20651 "ringsize": 6,
20652 "origconformer": "4C1",
20653 "puckercoords": [
20654 "-35.92",
20655 "-25.59",
20656 "-39.09"
20657 ],
20658 "conformer": "4C1",
20659 "ringorder": [
20660 "C3",
20661 "C4",
20662 "C5",
20663 "O5",
20664 "C1",
20665 "C2"
20666 ]
20667 }
20668 ]
20669
20670 console.log('data :' + data);
20671 // data.forEach(function(d) {
20672 // d.pdbid = d.pdbid;
20673 // d.resname = d.resname;
20674 // d.conformer = d.conformer;
20675 //
20676 // });
20677 //### Create Crossfilter Dimensions and Groups
20678 //See the [crossfilter API](https://github.com/square/crossfilter/wiki/API-Reference) for reference.
20679 var ndx = crossfilter(data);
20680 //var all = ndx.groupAll();
20681
20682
20683 // dimension by ring
20684 var ringDim = ndx.dimension(function (d) {
20685 return d.ringsize;
20686 });
20687 // dimension by pdb
20688 var pdbDim = ndx.dimension(function (d) {
20689 return d.pdbid;
20690 });
20691
20692
20693 // countperPDB = pdbDim.group().reduceSum(function(d) {return +d.Spent;}),
20694 // countperRes = resnameDim.group().reduceSum(function(d) {return +d.Spent;}),
20695 // countperPDB = pdbDim.group().reduceSum(function(d) {return d.ringsize;}),
20696 // countperRes = resnameDim.group().reduceSum(function(d) {return d.ringsize;});
20697 countperRing = ringDim.group().reduceCount(),
20698 countperPDB = pdbDim.group().reduceCount(),
20699 //countperPDB = pdbDim.group().reduceSum(function(d) {return d.ringsize;});
20700
20701 //### Define Chart Attributes
20702 //Define chart attributes using fluent methods. See the
20703 // [dc API Reference](https://github.com/dc-js/dc.js/blob/master/web/docs/api-latest.md) for more information
20704 //
20705
20706 ringCountChart
20707 .width(350).height(200)
20708 .dimension(ringDim)
20709 .group(countperRing)
20710 .x(d3.scale.linear().domain([0,10]))
20711 .elasticY(true);
20712 ringCountChart.xAxis().tickFormat(function(d) {return d}); // convert back to base unit
20713 ringCountChart.yAxis().ticks(2);
20714
20715
20716 pdbCountChart
20717 .width(350).height(200)
20718 .dimension(pdbDim)
20719 .group(countperPDB)
20720 .elasticX(true);
20721
20722
20723
20724
20725 dc.renderAll();
20726 //}); // END d3 json data load
20727
20728 </script>
20729
20730 </body>
20731 </html>
20732 """
20733 out.write(output)
20734
20735 except Exception as e:
20736 raise e
20737 finally:
20738 out.close()
20739