UNPKG

99.4 kBJavaScriptView Raw
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3 typeof define === 'function' && define.amd ? define(['exports'], factory) :
4 (factory((global.controls = global.controls || {})));
5}(this, (function (exports) { 'use strict';
6
7var xhtml = "http://www.w3.org/1999/xhtml";
8
9var namespaces = {
10 svg: "http://www.w3.org/2000/svg",
11 xhtml: xhtml,
12 xlink: "http://www.w3.org/1999/xlink",
13 xml: "http://www.w3.org/XML/1998/namespace",
14 xmlns: "http://www.w3.org/2000/xmlns/"
15};
16
17var namespace = function(name) {
18 var prefix = name += "", i = prefix.indexOf(":");
19 if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
20 return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name;
21};
22
23function creatorInherit(name) {
24 return function() {
25 var document = this.ownerDocument,
26 uri = this.namespaceURI;
27 return uri === xhtml && document.documentElement.namespaceURI === xhtml
28 ? document.createElement(name)
29 : document.createElementNS(uri, name);
30 };
31}
32
33function creatorFixed(fullname) {
34 return function() {
35 return this.ownerDocument.createElementNS(fullname.space, fullname.local);
36 };
37}
38
39var creator = function(name) {
40 var fullname = namespace(name);
41 return (fullname.local
42 ? creatorFixed
43 : creatorInherit)(fullname);
44};
45
46var matcher = function(selector) {
47 return function() {
48 return this.matches(selector);
49 };
50};
51
52if (typeof document !== "undefined") {
53 var element = document.documentElement;
54 if (!element.matches) {
55 var vendorMatches = element.webkitMatchesSelector
56 || element.msMatchesSelector
57 || element.mozMatchesSelector
58 || element.oMatchesSelector;
59 matcher = function(selector) {
60 return function() {
61 return vendorMatches.call(this, selector);
62 };
63 };
64 }
65}
66
67var matcher$1 = matcher;
68
69var filterEvents = {};
70
71var event = null;
72
73if (typeof document !== "undefined") {
74 var element$1 = document.documentElement;
75 if (!("onmouseenter" in element$1)) {
76 filterEvents = {mouseenter: "mouseover", mouseleave: "mouseout"};
77 }
78}
79
80function filterContextListener(listener, index, group) {
81 listener = contextListener(listener, index, group);
82 return function(event) {
83 var related = event.relatedTarget;
84 if (!related || (related !== this && !(related.compareDocumentPosition(this) & 8))) {
85 listener.call(this, event);
86 }
87 };
88}
89
90function contextListener(listener, index, group) {
91 return function(event1) {
92 var event0 = event; // Events can be reentrant (e.g., focus).
93 event = event1;
94 try {
95 listener.call(this, this.__data__, index, group);
96 } finally {
97 event = event0;
98 }
99 };
100}
101
102function parseTypenames(typenames) {
103 return typenames.trim().split(/^|\s+/).map(function(t) {
104 var name = "", i = t.indexOf(".");
105 if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
106 return {type: t, name: name};
107 });
108}
109
110function onRemove(typename) {
111 return function() {
112 var on = this.__on;
113 if (!on) return;
114 for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
115 if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
116 this.removeEventListener(o.type, o.listener, o.capture);
117 } else {
118 on[++i] = o;
119 }
120 }
121 if (++i) on.length = i;
122 else delete this.__on;
123 };
124}
125
126function onAdd(typename, value, capture) {
127 var wrap = filterEvents.hasOwnProperty(typename.type) ? filterContextListener : contextListener;
128 return function(d, i, group) {
129 var on = this.__on, o, listener = wrap(value, i, group);
130 if (on) for (var j = 0, m = on.length; j < m; ++j) {
131 if ((o = on[j]).type === typename.type && o.name === typename.name) {
132 this.removeEventListener(o.type, o.listener, o.capture);
133 this.addEventListener(o.type, o.listener = listener, o.capture = capture);
134 o.value = value;
135 return;
136 }
137 }
138 this.addEventListener(typename.type, listener, capture);
139 o = {type: typename.type, name: typename.name, value: value, listener: listener, capture: capture};
140 if (!on) this.__on = [o];
141 else on.push(o);
142 };
143}
144
145var selection_on = function(typename, value, capture) {
146 var typenames = parseTypenames(typename + ""), i, n = typenames.length, t;
147
148 if (arguments.length < 2) {
149 var on = this.node().__on;
150 if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
151 for (i = 0, o = on[j]; i < n; ++i) {
152 if ((t = typenames[i]).type === o.type && t.name === o.name) {
153 return o.value;
154 }
155 }
156 }
157 return;
158 }
159
160 on = value ? onAdd : onRemove;
161 if (capture == null) capture = false;
162 for (i = 0; i < n; ++i) this.each(on(typenames[i], value, capture));
163 return this;
164};
165
166var sourceEvent = function() {
167 var current = event, source;
168 while (source = current.sourceEvent) current = source;
169 return current;
170};
171
172var point = function(node, event) {
173 var svg = node.ownerSVGElement || node;
174
175 if (svg.createSVGPoint) {
176 var point = svg.createSVGPoint();
177 point.x = event.clientX, point.y = event.clientY;
178 point = point.matrixTransform(node.getScreenCTM().inverse());
179 return [point.x, point.y];
180 }
181
182 var rect = node.getBoundingClientRect();
183 return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
184};
185
186var d3_mouse = function(node) {
187 var event = sourceEvent();
188 if (event.changedTouches) event = event.changedTouches[0];
189 return point(node, event);
190};
191
192function none() {}
193
194var selector = function(selector) {
195 return selector == null ? none : function() {
196 return this.querySelector(selector);
197 };
198};
199
200var selection_select = function(select) {
201 if (typeof select !== "function") select = selector(select);
202
203 for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
204 for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
205 if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
206 if ("__data__" in node) subnode.__data__ = node.__data__;
207 subgroup[i] = subnode;
208 }
209 }
210 }
211
212 return new Selection(subgroups, this._parents);
213};
214
215function empty() {
216 return [];
217}
218
219var selectorAll = function(selector) {
220 return selector == null ? empty : function() {
221 return this.querySelectorAll(selector);
222 };
223};
224
225var selection_selectAll = function(select) {
226 if (typeof select !== "function") select = selectorAll(select);
227
228 for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
229 for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
230 if (node = group[i]) {
231 subgroups.push(select.call(node, node.__data__, i, group));
232 parents.push(node);
233 }
234 }
235 }
236
237 return new Selection(subgroups, parents);
238};
239
240var selection_filter = function(match) {
241 if (typeof match !== "function") match = matcher$1(match);
242
243 for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
244 for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
245 if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
246 subgroup.push(node);
247 }
248 }
249 }
250
251 return new Selection(subgroups, this._parents);
252};
253
254var sparse = function(update) {
255 return new Array(update.length);
256};
257
258var selection_enter = function() {
259 return new Selection(this._enter || this._groups.map(sparse), this._parents);
260};
261
262function EnterNode(parent, datum) {
263 this.ownerDocument = parent.ownerDocument;
264 this.namespaceURI = parent.namespaceURI;
265 this._next = null;
266 this._parent = parent;
267 this.__data__ = datum;
268}
269
270EnterNode.prototype = {
271 constructor: EnterNode,
272 appendChild: function(child) { return this._parent.insertBefore(child, this._next); },
273 insertBefore: function(child, next) { return this._parent.insertBefore(child, next); },
274 querySelector: function(selector) { return this._parent.querySelector(selector); },
275 querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); }
276};
277
278var constant = function(x) {
279 return function() {
280 return x;
281 };
282};
283
284var keyPrefix = "$"; // Protect against keys like “__proto__”.
285
286function bindIndex(parent, group, enter, update, exit, data) {
287 var i = 0,
288 node,
289 groupLength = group.length,
290 dataLength = data.length;
291
292 // Put any non-null nodes that fit into update.
293 // Put any null nodes into enter.
294 // Put any remaining data into enter.
295 for (; i < dataLength; ++i) {
296 if (node = group[i]) {
297 node.__data__ = data[i];
298 update[i] = node;
299 } else {
300 enter[i] = new EnterNode(parent, data[i]);
301 }
302 }
303
304 // Put any non-null nodes that don’t fit into exit.
305 for (; i < groupLength; ++i) {
306 if (node = group[i]) {
307 exit[i] = node;
308 }
309 }
310}
311
312function bindKey(parent, group, enter, update, exit, data, key) {
313 var i,
314 node,
315 nodeByKeyValue = {},
316 groupLength = group.length,
317 dataLength = data.length,
318 keyValues = new Array(groupLength),
319 keyValue;
320
321 // Compute the key for each node.
322 // If multiple nodes have the same key, the duplicates are added to exit.
323 for (i = 0; i < groupLength; ++i) {
324 if (node = group[i]) {
325 keyValues[i] = keyValue = keyPrefix + key.call(node, node.__data__, i, group);
326 if (keyValue in nodeByKeyValue) {
327 exit[i] = node;
328 } else {
329 nodeByKeyValue[keyValue] = node;
330 }
331 }
332 }
333
334 // Compute the key for each datum.
335 // If there a node associated with this key, join and add it to update.
336 // If there is not (or the key is a duplicate), add it to enter.
337 for (i = 0; i < dataLength; ++i) {
338 keyValue = keyPrefix + key.call(parent, data[i], i, data);
339 if (node = nodeByKeyValue[keyValue]) {
340 update[i] = node;
341 node.__data__ = data[i];
342 nodeByKeyValue[keyValue] = null;
343 } else {
344 enter[i] = new EnterNode(parent, data[i]);
345 }
346 }
347
348 // Add any remaining nodes that were not bound to data to exit.
349 for (i = 0; i < groupLength; ++i) {
350 if ((node = group[i]) && (nodeByKeyValue[keyValues[i]] === node)) {
351 exit[i] = node;
352 }
353 }
354}
355
356var selection_data = function(value, key) {
357 if (!value) {
358 data = new Array(this.size()), j = -1;
359 this.each(function(d) { data[++j] = d; });
360 return data;
361 }
362
363 var bind = key ? bindKey : bindIndex,
364 parents = this._parents,
365 groups = this._groups;
366
367 if (typeof value !== "function") value = constant(value);
368
369 for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
370 var parent = parents[j],
371 group = groups[j],
372 groupLength = group.length,
373 data = value.call(parent, parent && parent.__data__, j, parents),
374 dataLength = data.length,
375 enterGroup = enter[j] = new Array(dataLength),
376 updateGroup = update[j] = new Array(dataLength),
377 exitGroup = exit[j] = new Array(groupLength);
378
379 bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);
380
381 // Now connect the enter nodes to their following update node, such that
382 // appendChild can insert the materialized enter node before this node,
383 // rather than at the end of the parent node.
384 for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
385 if (previous = enterGroup[i0]) {
386 if (i0 >= i1) i1 = i0 + 1;
387 while (!(next = updateGroup[i1]) && ++i1 < dataLength);
388 previous._next = next || null;
389 }
390 }
391 }
392
393 update = new Selection(update, parents);
394 update._enter = enter;
395 update._exit = exit;
396 return update;
397};
398
399var selection_exit = function() {
400 return new Selection(this._exit || this._groups.map(sparse), this._parents);
401};
402
403var selection_merge = function(selection) {
404
405 for (var groups0 = this._groups, groups1 = selection._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
406 for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
407 if (node = group0[i] || group1[i]) {
408 merge[i] = node;
409 }
410 }
411 }
412
413 for (; j < m0; ++j) {
414 merges[j] = groups0[j];
415 }
416
417 return new Selection(merges, this._parents);
418};
419
420var selection_order = function() {
421
422 for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {
423 for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
424 if (node = group[i]) {
425 if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
426 next = node;
427 }
428 }
429 }
430
431 return this;
432};
433
434var selection_sort = function(compare) {
435 if (!compare) compare = ascending;
436
437 function compareNode(a, b) {
438 return a && b ? compare(a.__data__, b.__data__) : !a - !b;
439 }
440
441 for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
442 for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
443 if (node = group[i]) {
444 sortgroup[i] = node;
445 }
446 }
447 sortgroup.sort(compareNode);
448 }
449
450 return new Selection(sortgroups, this._parents).order();
451};
452
453function ascending(a, b) {
454 return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
455}
456
457var selection_call = function() {
458 var callback = arguments[0];
459 arguments[0] = this;
460 callback.apply(null, arguments);
461 return this;
462};
463
464var selection_nodes = function() {
465 var nodes = new Array(this.size()), i = -1;
466 this.each(function() { nodes[++i] = this; });
467 return nodes;
468};
469
470var selection_node = function() {
471
472 for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
473 for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
474 var node = group[i];
475 if (node) return node;
476 }
477 }
478
479 return null;
480};
481
482var selection_size = function() {
483 var size = 0;
484 this.each(function() { ++size; });
485 return size;
486};
487
488var selection_empty = function() {
489 return !this.node();
490};
491
492var selection_each = function(callback) {
493
494 for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
495 for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
496 if (node = group[i]) callback.call(node, node.__data__, i, group);
497 }
498 }
499
500 return this;
501};
502
503function attrRemove(name) {
504 return function() {
505 this.removeAttribute(name);
506 };
507}
508
509function attrRemoveNS(fullname) {
510 return function() {
511 this.removeAttributeNS(fullname.space, fullname.local);
512 };
513}
514
515function attrConstant(name, value) {
516 return function() {
517 this.setAttribute(name, value);
518 };
519}
520
521function attrConstantNS(fullname, value) {
522 return function() {
523 this.setAttributeNS(fullname.space, fullname.local, value);
524 };
525}
526
527function attrFunction(name, value) {
528 return function() {
529 var v = value.apply(this, arguments);
530 if (v == null) this.removeAttribute(name);
531 else this.setAttribute(name, v);
532 };
533}
534
535function attrFunctionNS(fullname, value) {
536 return function() {
537 var v = value.apply(this, arguments);
538 if (v == null) this.removeAttributeNS(fullname.space, fullname.local);
539 else this.setAttributeNS(fullname.space, fullname.local, v);
540 };
541}
542
543var selection_attr = function(name, value) {
544 var fullname = namespace(name);
545
546 if (arguments.length < 2) {
547 var node = this.node();
548 return fullname.local
549 ? node.getAttributeNS(fullname.space, fullname.local)
550 : node.getAttribute(fullname);
551 }
552
553 return this.each((value == null
554 ? (fullname.local ? attrRemoveNS : attrRemove) : (typeof value === "function"
555 ? (fullname.local ? attrFunctionNS : attrFunction)
556 : (fullname.local ? attrConstantNS : attrConstant)))(fullname, value));
557};
558
559var defaultView = function(node) {
560 return (node.ownerDocument && node.ownerDocument.defaultView) // node is a Node
561 || (node.document && node) // node is a Window
562 || node.defaultView; // node is a Document
563};
564
565function styleRemove(name) {
566 return function() {
567 this.style.removeProperty(name);
568 };
569}
570
571function styleConstant(name, value, priority) {
572 return function() {
573 this.style.setProperty(name, value, priority);
574 };
575}
576
577function styleFunction(name, value, priority) {
578 return function() {
579 var v = value.apply(this, arguments);
580 if (v == null) this.style.removeProperty(name);
581 else this.style.setProperty(name, v, priority);
582 };
583}
584
585var selection_style = function(name, value, priority) {
586 return arguments.length > 1
587 ? this.each((value == null
588 ? styleRemove : typeof value === "function"
589 ? styleFunction
590 : styleConstant)(name, value, priority == null ? "" : priority))
591 : styleValue(this.node(), name);
592};
593
594function styleValue(node, name) {
595 return node.style.getPropertyValue(name)
596 || defaultView(node).getComputedStyle(node, null).getPropertyValue(name);
597}
598
599function propertyRemove(name) {
600 return function() {
601 delete this[name];
602 };
603}
604
605function propertyConstant(name, value) {
606 return function() {
607 this[name] = value;
608 };
609}
610
611function propertyFunction(name, value) {
612 return function() {
613 var v = value.apply(this, arguments);
614 if (v == null) delete this[name];
615 else this[name] = v;
616 };
617}
618
619var selection_property = function(name, value) {
620 return arguments.length > 1
621 ? this.each((value == null
622 ? propertyRemove : typeof value === "function"
623 ? propertyFunction
624 : propertyConstant)(name, value))
625 : this.node()[name];
626};
627
628function classArray(string) {
629 return string.trim().split(/^|\s+/);
630}
631
632function classList(node) {
633 return node.classList || new ClassList(node);
634}
635
636function ClassList(node) {
637 this._node = node;
638 this._names = classArray(node.getAttribute("class") || "");
639}
640
641ClassList.prototype = {
642 add: function(name) {
643 var i = this._names.indexOf(name);
644 if (i < 0) {
645 this._names.push(name);
646 this._node.setAttribute("class", this._names.join(" "));
647 }
648 },
649 remove: function(name) {
650 var i = this._names.indexOf(name);
651 if (i >= 0) {
652 this._names.splice(i, 1);
653 this._node.setAttribute("class", this._names.join(" "));
654 }
655 },
656 contains: function(name) {
657 return this._names.indexOf(name) >= 0;
658 }
659};
660
661function classedAdd(node, names) {
662 var list = classList(node), i = -1, n = names.length;
663 while (++i < n) list.add(names[i]);
664}
665
666function classedRemove(node, names) {
667 var list = classList(node), i = -1, n = names.length;
668 while (++i < n) list.remove(names[i]);
669}
670
671function classedTrue(names) {
672 return function() {
673 classedAdd(this, names);
674 };
675}
676
677function classedFalse(names) {
678 return function() {
679 classedRemove(this, names);
680 };
681}
682
683function classedFunction(names, value) {
684 return function() {
685 (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
686 };
687}
688
689var selection_classed = function(name, value) {
690 var names = classArray(name + "");
691
692 if (arguments.length < 2) {
693 var list = classList(this.node()), i = -1, n = names.length;
694 while (++i < n) if (!list.contains(names[i])) return false;
695 return true;
696 }
697
698 return this.each((typeof value === "function"
699 ? classedFunction : value
700 ? classedTrue
701 : classedFalse)(names, value));
702};
703
704function textRemove() {
705 this.textContent = "";
706}
707
708function textConstant(value) {
709 return function() {
710 this.textContent = value;
711 };
712}
713
714function textFunction(value) {
715 return function() {
716 var v = value.apply(this, arguments);
717 this.textContent = v == null ? "" : v;
718 };
719}
720
721var selection_text = function(value) {
722 return arguments.length
723 ? this.each(value == null
724 ? textRemove : (typeof value === "function"
725 ? textFunction
726 : textConstant)(value))
727 : this.node().textContent;
728};
729
730function htmlRemove() {
731 this.innerHTML = "";
732}
733
734function htmlConstant(value) {
735 return function() {
736 this.innerHTML = value;
737 };
738}
739
740function htmlFunction(value) {
741 return function() {
742 var v = value.apply(this, arguments);
743 this.innerHTML = v == null ? "" : v;
744 };
745}
746
747var selection_html = function(value) {
748 return arguments.length
749 ? this.each(value == null
750 ? htmlRemove : (typeof value === "function"
751 ? htmlFunction
752 : htmlConstant)(value))
753 : this.node().innerHTML;
754};
755
756function raise() {
757 if (this.nextSibling) this.parentNode.appendChild(this);
758}
759
760var selection_raise = function() {
761 return this.each(raise);
762};
763
764function lower() {
765 if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
766}
767
768var selection_lower = function() {
769 return this.each(lower);
770};
771
772var selection_append = function(name) {
773 var create = typeof name === "function" ? name : creator(name);
774 return this.select(function() {
775 return this.appendChild(create.apply(this, arguments));
776 });
777};
778
779function constantNull() {
780 return null;
781}
782
783var selection_insert = function(name, before) {
784 var create = typeof name === "function" ? name : creator(name),
785 select = before == null ? constantNull : typeof before === "function" ? before : selector(before);
786 return this.select(function() {
787 return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
788 });
789};
790
791function remove() {
792 var parent = this.parentNode;
793 if (parent) parent.removeChild(this);
794}
795
796var selection_remove = function() {
797 return this.each(remove);
798};
799
800var selection_datum = function(value) {
801 return arguments.length
802 ? this.property("__data__", value)
803 : this.node().__data__;
804};
805
806function dispatchEvent(node, type, params) {
807 var window = defaultView(node),
808 event = window.CustomEvent;
809
810 if (typeof event === "function") {
811 event = new event(type, params);
812 } else {
813 event = window.document.createEvent("Event");
814 if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;
815 else event.initEvent(type, false, false);
816 }
817
818 node.dispatchEvent(event);
819}
820
821function dispatchConstant(type, params) {
822 return function() {
823 return dispatchEvent(this, type, params);
824 };
825}
826
827function dispatchFunction(type, params) {
828 return function() {
829 return dispatchEvent(this, type, params.apply(this, arguments));
830 };
831}
832
833var selection_dispatch = function(type, params) {
834 return this.each((typeof params === "function"
835 ? dispatchFunction
836 : dispatchConstant)(type, params));
837};
838
839var root = [null];
840
841function Selection(groups, parents) {
842 this._groups = groups;
843 this._parents = parents;
844}
845
846function selection() {
847 return new Selection([[document.documentElement]], root);
848}
849
850Selection.prototype = selection.prototype = {
851 constructor: Selection,
852 select: selection_select,
853 selectAll: selection_selectAll,
854 filter: selection_filter,
855 data: selection_data,
856 enter: selection_enter,
857 exit: selection_exit,
858 merge: selection_merge,
859 order: selection_order,
860 sort: selection_sort,
861 call: selection_call,
862 nodes: selection_nodes,
863 node: selection_node,
864 size: selection_size,
865 empty: selection_empty,
866 each: selection_each,
867 attr: selection_attr,
868 style: selection_style,
869 property: selection_property,
870 classed: selection_classed,
871 text: selection_text,
872 html: selection_html,
873 raise: selection_raise,
874 lower: selection_lower,
875 append: selection_append,
876 insert: selection_insert,
877 remove: selection_remove,
878 datum: selection_datum,
879 on: selection_on,
880 dispatch: selection_dispatch
881};
882
883var d3_select = function(selector) {
884 return typeof selector === "string"
885 ? new Selection([[document.querySelector(selector)]], [document.documentElement])
886 : new Selection([[selector]], root);
887};
888
889var slice = Array.prototype.slice;
890
891var identity = function(x) {
892 return x;
893};
894
895var top = 1;
896var right = 2;
897var bottom = 3;
898var left = 4;
899var epsilon = 1e-6;
900
901function translateX(x) {
902 return "translate(" + (x + 0.5) + ",0)";
903}
904
905function translateY(y) {
906 return "translate(0," + (y + 0.5) + ")";
907}
908
909function number(scale) {
910 return function(d) {
911 return +scale(d);
912 };
913}
914
915function center(scale) {
916 var offset = Math.max(0, scale.bandwidth() - 1) / 2; // Adjust for 0.5px offset.
917 if (scale.round()) offset = Math.round(offset);
918 return function(d) {
919 return +scale(d) + offset;
920 };
921}
922
923function entering() {
924 return !this.__axis;
925}
926
927function axis(orient, scale) {
928 var tickArguments = [],
929 tickValues = null,
930 tickFormat = null,
931 tickSizeInner = 6,
932 tickSizeOuter = 6,
933 tickPadding = 3,
934 k = orient === top || orient === left ? -1 : 1,
935 x = orient === left || orient === right ? "x" : "y",
936 transform = orient === top || orient === bottom ? translateX : translateY;
937
938 function axis(context) {
939 var values = tickValues == null ? (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain()) : tickValues,
940 format = tickFormat == null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : identity) : tickFormat,
941 spacing = Math.max(tickSizeInner, 0) + tickPadding,
942 range = scale.range(),
943 range0 = +range[0] + 0.5,
944 range1 = +range[range.length - 1] + 0.5,
945 position = (scale.bandwidth ? center : number)(scale.copy()),
946 selection = context.selection ? context.selection() : context,
947 path = selection.selectAll(".domain").data([null]),
948 tick = selection.selectAll(".tick").data(values, scale).order(),
949 tickExit = tick.exit(),
950 tickEnter = tick.enter().append("g").attr("class", "tick"),
951 line = tick.select("line"),
952 text = tick.select("text");
953
954 path = path.merge(path.enter().insert("path", ".tick")
955 .attr("class", "domain")
956 .attr("stroke", "#000"));
957
958 tick = tick.merge(tickEnter);
959
960 line = line.merge(tickEnter.append("line")
961 .attr("stroke", "#000")
962 .attr(x + "2", k * tickSizeInner));
963
964 text = text.merge(tickEnter.append("text")
965 .attr("fill", "#000")
966 .attr(x, k * spacing)
967 .attr("dy", orient === top ? "0em" : orient === bottom ? "0.71em" : "0.32em"));
968
969 if (context !== selection) {
970 path = path.transition(context);
971 tick = tick.transition(context);
972 line = line.transition(context);
973 text = text.transition(context);
974
975 tickExit = tickExit.transition(context)
976 .attr("opacity", epsilon)
977 .attr("transform", function(d) { return isFinite(d = position(d)) ? transform(d) : this.getAttribute("transform"); });
978
979 tickEnter
980 .attr("opacity", epsilon)
981 .attr("transform", function(d) { var p = this.parentNode.__axis; return transform(p && isFinite(p = p(d)) ? p : position(d)); });
982 }
983
984 tickExit.remove();
985
986 path
987 .attr("d", orient === left || orient == right
988 ? "M" + k * tickSizeOuter + "," + range0 + "H0.5V" + range1 + "H" + k * tickSizeOuter
989 : "M" + range0 + "," + k * tickSizeOuter + "V0.5H" + range1 + "V" + k * tickSizeOuter);
990
991 tick
992 .attr("opacity", 1)
993 .attr("transform", function(d) { return transform(position(d)); });
994
995 line
996 .attr(x + "2", k * tickSizeInner);
997
998 text
999 .attr(x, k * spacing)
1000 .text(format);
1001
1002 selection.filter(entering)
1003 .attr("fill", "none")
1004 .attr("font-size", 10)
1005 .attr("font-family", "sans-serif")
1006 .attr("text-anchor", orient === right ? "start" : orient === left ? "end" : "middle");
1007
1008 selection
1009 .each(function() { this.__axis = position; });
1010 }
1011
1012 axis.scale = function(_) {
1013 return arguments.length ? (scale = _, axis) : scale;
1014 };
1015
1016 axis.ticks = function() {
1017 return tickArguments = slice.call(arguments), axis;
1018 };
1019
1020 axis.tickArguments = function(_) {
1021 return arguments.length ? (tickArguments = _ == null ? [] : slice.call(_), axis) : tickArguments.slice();
1022 };
1023
1024 axis.tickValues = function(_) {
1025 return arguments.length ? (tickValues = _ == null ? null : slice.call(_), axis) : tickValues && tickValues.slice();
1026 };
1027
1028 axis.tickFormat = function(_) {
1029 return arguments.length ? (tickFormat = _, axis) : tickFormat;
1030 };
1031
1032 axis.tickSize = function(_) {
1033 return arguments.length ? (tickSizeInner = tickSizeOuter = +_, axis) : tickSizeInner;
1034 };
1035
1036 axis.tickSizeInner = function(_) {
1037 return arguments.length ? (tickSizeInner = +_, axis) : tickSizeInner;
1038 };
1039
1040 axis.tickSizeOuter = function(_) {
1041 return arguments.length ? (tickSizeOuter = +_, axis) : tickSizeOuter;
1042 };
1043
1044 axis.tickPadding = function(_) {
1045 return arguments.length ? (tickPadding = +_, axis) : tickPadding;
1046 };
1047
1048 return axis;
1049}
1050
1051
1052
1053
1054
1055function axisBottom(scale) {
1056 return axis(bottom, scale);
1057}
1058
1059var ascending$1 = function(a, b) {
1060 return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
1061};
1062
1063var bisector = function(compare) {
1064 if (compare.length === 1) compare = ascendingComparator(compare);
1065 return {
1066 left: function(a, x, lo, hi) {
1067 if (lo == null) lo = 0;
1068 if (hi == null) hi = a.length;
1069 while (lo < hi) {
1070 var mid = lo + hi >>> 1;
1071 if (compare(a[mid], x) < 0) lo = mid + 1;
1072 else hi = mid;
1073 }
1074 return lo;
1075 },
1076 right: function(a, x, lo, hi) {
1077 if (lo == null) lo = 0;
1078 if (hi == null) hi = a.length;
1079 while (lo < hi) {
1080 var mid = lo + hi >>> 1;
1081 if (compare(a[mid], x) > 0) hi = mid;
1082 else lo = mid + 1;
1083 }
1084 return lo;
1085 }
1086 };
1087};
1088
1089function ascendingComparator(f) {
1090 return function(d, x) {
1091 return ascending$1(f(d), x);
1092 };
1093}
1094
1095var ascendingBisect = bisector(ascending$1);
1096var bisectRight = ascendingBisect.right;
1097
1098function pair(a, b) {
1099 return [a, b];
1100}
1101
1102var number$1 = function(x) {
1103 return x === null ? NaN : +x;
1104};
1105
1106var extent = function(values, valueof) {
1107 var n = values.length,
1108 i = -1,
1109 value,
1110 min,
1111 max;
1112
1113 if (valueof == null) {
1114 while (++i < n) { // Find the first comparable value.
1115 if ((value = values[i]) != null && value >= value) {
1116 min = max = value;
1117 while (++i < n) { // Compare the remaining values.
1118 if ((value = values[i]) != null) {
1119 if (min > value) min = value;
1120 if (max < value) max = value;
1121 }
1122 }
1123 }
1124 }
1125 }
1126
1127 else {
1128 while (++i < n) { // Find the first comparable value.
1129 if ((value = valueof(values[i], i, values)) != null && value >= value) {
1130 min = max = value;
1131 while (++i < n) { // Compare the remaining values.
1132 if ((value = valueof(values[i], i, values)) != null) {
1133 if (min > value) min = value;
1134 if (max < value) max = value;
1135 }
1136 }
1137 }
1138 }
1139 }
1140
1141 return [min, max];
1142};
1143
1144var identity$1 = function(x) {
1145 return x;
1146};
1147
1148var range = function(start, stop, step) {
1149 start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
1150
1151 var i = -1,
1152 n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
1153 range = new Array(n);
1154
1155 while (++i < n) {
1156 range[i] = start + i * step;
1157 }
1158
1159 return range;
1160};
1161
1162var e10 = Math.sqrt(50);
1163var e5 = Math.sqrt(10);
1164var e2 = Math.sqrt(2);
1165
1166var ticks = function(start, stop, count) {
1167 var reverse,
1168 i = -1,
1169 n,
1170 ticks,
1171 step;
1172
1173 stop = +stop, start = +start, count = +count;
1174 if (start === stop && count > 0) return [start];
1175 if (reverse = stop < start) n = start, start = stop, stop = n;
1176 if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return [];
1177
1178 if (step > 0) {
1179 start = Math.ceil(start / step);
1180 stop = Math.floor(stop / step);
1181 ticks = new Array(n = Math.ceil(stop - start + 1));
1182 while (++i < n) ticks[i] = (start + i) * step;
1183 } else {
1184 start = Math.floor(start * step);
1185 stop = Math.ceil(stop * step);
1186 ticks = new Array(n = Math.ceil(start - stop + 1));
1187 while (++i < n) ticks[i] = (start - i) / step;
1188 }
1189
1190 if (reverse) ticks.reverse();
1191
1192 return ticks;
1193};
1194
1195function tickIncrement(start, stop, count) {
1196 var step = (stop - start) / Math.max(0, count),
1197 power = Math.floor(Math.log(step) / Math.LN10),
1198 error = step / Math.pow(10, power);
1199 return power >= 0
1200 ? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power)
1201 : -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1);
1202}
1203
1204function tickStep(start, stop, count) {
1205 var step0 = Math.abs(stop - start) / Math.max(0, count),
1206 step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
1207 error = step0 / step1;
1208 if (error >= e10) step1 *= 10;
1209 else if (error >= e5) step1 *= 5;
1210 else if (error >= e2) step1 *= 2;
1211 return stop < start ? -step1 : step1;
1212}
1213
1214var sturges = function(values) {
1215 return Math.ceil(Math.log(values.length) / Math.LN2) + 1;
1216};
1217
1218var quantile = function(values, p, valueof) {
1219 if (valueof == null) valueof = number$1;
1220 if (!(n = values.length)) return;
1221 if ((p = +p) <= 0 || n < 2) return +valueof(values[0], 0, values);
1222 if (p >= 1) return +valueof(values[n - 1], n - 1, values);
1223 var n,
1224 i = (n - 1) * p,
1225 i0 = Math.floor(i),
1226 value0 = +valueof(values[i0], i0, values),
1227 value1 = +valueof(values[i0 + 1], i0 + 1, values);
1228 return value0 + (value1 - value0) * (i - i0);
1229};
1230
1231var min = function(values, valueof) {
1232 var n = values.length,
1233 i = -1,
1234 value,
1235 min;
1236
1237 if (valueof == null) {
1238 while (++i < n) { // Find the first comparable value.
1239 if ((value = values[i]) != null && value >= value) {
1240 min = value;
1241 while (++i < n) { // Compare the remaining values.
1242 if ((value = values[i]) != null && min > value) {
1243 min = value;
1244 }
1245 }
1246 }
1247 }
1248 }
1249
1250 else {
1251 while (++i < n) { // Find the first comparable value.
1252 if ((value = valueof(values[i], i, values)) != null && value >= value) {
1253 min = value;
1254 while (++i < n) { // Compare the remaining values.
1255 if ((value = valueof(values[i], i, values)) != null && min > value) {
1256 min = value;
1257 }
1258 }
1259 }
1260 }
1261 }
1262
1263 return min;
1264};
1265
1266function length(d) {
1267 return d.length;
1268}
1269
1270var define = function(constructor, factory, prototype) {
1271 constructor.prototype = factory.prototype = prototype;
1272 prototype.constructor = constructor;
1273};
1274
1275function extend(parent, definition) {
1276 var prototype = Object.create(parent.prototype);
1277 for (var key in definition) prototype[key] = definition[key];
1278 return prototype;
1279}
1280
1281function Color() {}
1282
1283var darker = 0.7;
1284var brighter = 1 / darker;
1285
1286var reI = "\\s*([+-]?\\d+)\\s*";
1287var reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*";
1288var reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*";
1289var reHex3 = /^#([0-9a-f]{3})$/;
1290var reHex6 = /^#([0-9a-f]{6})$/;
1291var reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$");
1292var reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$");
1293var reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$");
1294var reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$");
1295var reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$");
1296var reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
1297
1298var named = {
1299 aliceblue: 0xf0f8ff,
1300 antiquewhite: 0xfaebd7,
1301 aqua: 0x00ffff,
1302 aquamarine: 0x7fffd4,
1303 azure: 0xf0ffff,
1304 beige: 0xf5f5dc,
1305 bisque: 0xffe4c4,
1306 black: 0x000000,
1307 blanchedalmond: 0xffebcd,
1308 blue: 0x0000ff,
1309 blueviolet: 0x8a2be2,
1310 brown: 0xa52a2a,
1311 burlywood: 0xdeb887,
1312 cadetblue: 0x5f9ea0,
1313 chartreuse: 0x7fff00,
1314 chocolate: 0xd2691e,
1315 coral: 0xff7f50,
1316 cornflowerblue: 0x6495ed,
1317 cornsilk: 0xfff8dc,
1318 crimson: 0xdc143c,
1319 cyan: 0x00ffff,
1320 darkblue: 0x00008b,
1321 darkcyan: 0x008b8b,
1322 darkgoldenrod: 0xb8860b,
1323 darkgray: 0xa9a9a9,
1324 darkgreen: 0x006400,
1325 darkgrey: 0xa9a9a9,
1326 darkkhaki: 0xbdb76b,
1327 darkmagenta: 0x8b008b,
1328 darkolivegreen: 0x556b2f,
1329 darkorange: 0xff8c00,
1330 darkorchid: 0x9932cc,
1331 darkred: 0x8b0000,
1332 darksalmon: 0xe9967a,
1333 darkseagreen: 0x8fbc8f,
1334 darkslateblue: 0x483d8b,
1335 darkslategray: 0x2f4f4f,
1336 darkslategrey: 0x2f4f4f,
1337 darkturquoise: 0x00ced1,
1338 darkviolet: 0x9400d3,
1339 deeppink: 0xff1493,
1340 deepskyblue: 0x00bfff,
1341 dimgray: 0x696969,
1342 dimgrey: 0x696969,
1343 dodgerblue: 0x1e90ff,
1344 firebrick: 0xb22222,
1345 floralwhite: 0xfffaf0,
1346 forestgreen: 0x228b22,
1347 fuchsia: 0xff00ff,
1348 gainsboro: 0xdcdcdc,
1349 ghostwhite: 0xf8f8ff,
1350 gold: 0xffd700,
1351 goldenrod: 0xdaa520,
1352 gray: 0x808080,
1353 green: 0x008000,
1354 greenyellow: 0xadff2f,
1355 grey: 0x808080,
1356 honeydew: 0xf0fff0,
1357 hotpink: 0xff69b4,
1358 indianred: 0xcd5c5c,
1359 indigo: 0x4b0082,
1360 ivory: 0xfffff0,
1361 khaki: 0xf0e68c,
1362 lavender: 0xe6e6fa,
1363 lavenderblush: 0xfff0f5,
1364 lawngreen: 0x7cfc00,
1365 lemonchiffon: 0xfffacd,
1366 lightblue: 0xadd8e6,
1367 lightcoral: 0xf08080,
1368 lightcyan: 0xe0ffff,
1369 lightgoldenrodyellow: 0xfafad2,
1370 lightgray: 0xd3d3d3,
1371 lightgreen: 0x90ee90,
1372 lightgrey: 0xd3d3d3,
1373 lightpink: 0xffb6c1,
1374 lightsalmon: 0xffa07a,
1375 lightseagreen: 0x20b2aa,
1376 lightskyblue: 0x87cefa,
1377 lightslategray: 0x778899,
1378 lightslategrey: 0x778899,
1379 lightsteelblue: 0xb0c4de,
1380 lightyellow: 0xffffe0,
1381 lime: 0x00ff00,
1382 limegreen: 0x32cd32,
1383 linen: 0xfaf0e6,
1384 magenta: 0xff00ff,
1385 maroon: 0x800000,
1386 mediumaquamarine: 0x66cdaa,
1387 mediumblue: 0x0000cd,
1388 mediumorchid: 0xba55d3,
1389 mediumpurple: 0x9370db,
1390 mediumseagreen: 0x3cb371,
1391 mediumslateblue: 0x7b68ee,
1392 mediumspringgreen: 0x00fa9a,
1393 mediumturquoise: 0x48d1cc,
1394 mediumvioletred: 0xc71585,
1395 midnightblue: 0x191970,
1396 mintcream: 0xf5fffa,
1397 mistyrose: 0xffe4e1,
1398 moccasin: 0xffe4b5,
1399 navajowhite: 0xffdead,
1400 navy: 0x000080,
1401 oldlace: 0xfdf5e6,
1402 olive: 0x808000,
1403 olivedrab: 0x6b8e23,
1404 orange: 0xffa500,
1405 orangered: 0xff4500,
1406 orchid: 0xda70d6,
1407 palegoldenrod: 0xeee8aa,
1408 palegreen: 0x98fb98,
1409 paleturquoise: 0xafeeee,
1410 palevioletred: 0xdb7093,
1411 papayawhip: 0xffefd5,
1412 peachpuff: 0xffdab9,
1413 peru: 0xcd853f,
1414 pink: 0xffc0cb,
1415 plum: 0xdda0dd,
1416 powderblue: 0xb0e0e6,
1417 purple: 0x800080,
1418 rebeccapurple: 0x663399,
1419 red: 0xff0000,
1420 rosybrown: 0xbc8f8f,
1421 royalblue: 0x4169e1,
1422 saddlebrown: 0x8b4513,
1423 salmon: 0xfa8072,
1424 sandybrown: 0xf4a460,
1425 seagreen: 0x2e8b57,
1426 seashell: 0xfff5ee,
1427 sienna: 0xa0522d,
1428 silver: 0xc0c0c0,
1429 skyblue: 0x87ceeb,
1430 slateblue: 0x6a5acd,
1431 slategray: 0x708090,
1432 slategrey: 0x708090,
1433 snow: 0xfffafa,
1434 springgreen: 0x00ff7f,
1435 steelblue: 0x4682b4,
1436 tan: 0xd2b48c,
1437 teal: 0x008080,
1438 thistle: 0xd8bfd8,
1439 tomato: 0xff6347,
1440 turquoise: 0x40e0d0,
1441 violet: 0xee82ee,
1442 wheat: 0xf5deb3,
1443 white: 0xffffff,
1444 whitesmoke: 0xf5f5f5,
1445 yellow: 0xffff00,
1446 yellowgreen: 0x9acd32
1447};
1448
1449define(Color, color, {
1450 displayable: function() {
1451 return this.rgb().displayable();
1452 },
1453 toString: function() {
1454 return this.rgb() + "";
1455 }
1456});
1457
1458function color(format) {
1459 var m;
1460 format = (format + "").trim().toLowerCase();
1461 return (m = reHex3.exec(format)) ? (m = parseInt(m[1], 16), new Rgb((m >> 8 & 0xf) | (m >> 4 & 0x0f0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1)) // #f00
1462 : (m = reHex6.exec(format)) ? rgbn(parseInt(m[1], 16)) // #ff0000
1463 : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
1464 : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
1465 : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
1466 : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
1467 : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
1468 : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
1469 : named.hasOwnProperty(format) ? rgbn(named[format])
1470 : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0)
1471 : null;
1472}
1473
1474function rgbn(n) {
1475 return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
1476}
1477
1478function rgba(r, g, b, a) {
1479 if (a <= 0) r = g = b = NaN;
1480 return new Rgb(r, g, b, a);
1481}
1482
1483function rgbConvert(o) {
1484 if (!(o instanceof Color)) o = color(o);
1485 if (!o) return new Rgb;
1486 o = o.rgb();
1487 return new Rgb(o.r, o.g, o.b, o.opacity);
1488}
1489
1490function rgb(r, g, b, opacity) {
1491 return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
1492}
1493
1494function Rgb(r, g, b, opacity) {
1495 this.r = +r;
1496 this.g = +g;
1497 this.b = +b;
1498 this.opacity = +opacity;
1499}
1500
1501define(Rgb, rgb, extend(Color, {
1502 brighter: function(k) {
1503 k = k == null ? brighter : Math.pow(brighter, k);
1504 return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
1505 },
1506 darker: function(k) {
1507 k = k == null ? darker : Math.pow(darker, k);
1508 return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
1509 },
1510 rgb: function() {
1511 return this;
1512 },
1513 displayable: function() {
1514 return (0 <= this.r && this.r <= 255)
1515 && (0 <= this.g && this.g <= 255)
1516 && (0 <= this.b && this.b <= 255)
1517 && (0 <= this.opacity && this.opacity <= 1);
1518 },
1519 toString: function() {
1520 var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
1521 return (a === 1 ? "rgb(" : "rgba(")
1522 + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", "
1523 + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", "
1524 + Math.max(0, Math.min(255, Math.round(this.b) || 0))
1525 + (a === 1 ? ")" : ", " + a + ")");
1526 }
1527}));
1528
1529function hsla(h, s, l, a) {
1530 if (a <= 0) h = s = l = NaN;
1531 else if (l <= 0 || l >= 1) h = s = NaN;
1532 else if (s <= 0) h = NaN;
1533 return new Hsl(h, s, l, a);
1534}
1535
1536function hslConvert(o) {
1537 if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
1538 if (!(o instanceof Color)) o = color(o);
1539 if (!o) return new Hsl;
1540 if (o instanceof Hsl) return o;
1541 o = o.rgb();
1542 var r = o.r / 255,
1543 g = o.g / 255,
1544 b = o.b / 255,
1545 min = Math.min(r, g, b),
1546 max = Math.max(r, g, b),
1547 h = NaN,
1548 s = max - min,
1549 l = (max + min) / 2;
1550 if (s) {
1551 if (r === max) h = (g - b) / s + (g < b) * 6;
1552 else if (g === max) h = (b - r) / s + 2;
1553 else h = (r - g) / s + 4;
1554 s /= l < 0.5 ? max + min : 2 - max - min;
1555 h *= 60;
1556 } else {
1557 s = l > 0 && l < 1 ? 0 : h;
1558 }
1559 return new Hsl(h, s, l, o.opacity);
1560}
1561
1562function hsl(h, s, l, opacity) {
1563 return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
1564}
1565
1566function Hsl(h, s, l, opacity) {
1567 this.h = +h;
1568 this.s = +s;
1569 this.l = +l;
1570 this.opacity = +opacity;
1571}
1572
1573define(Hsl, hsl, extend(Color, {
1574 brighter: function(k) {
1575 k = k == null ? brighter : Math.pow(brighter, k);
1576 return new Hsl(this.h, this.s, this.l * k, this.opacity);
1577 },
1578 darker: function(k) {
1579 k = k == null ? darker : Math.pow(darker, k);
1580 return new Hsl(this.h, this.s, this.l * k, this.opacity);
1581 },
1582 rgb: function() {
1583 var h = this.h % 360 + (this.h < 0) * 360,
1584 s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
1585 l = this.l,
1586 m2 = l + (l < 0.5 ? l : 1 - l) * s,
1587 m1 = 2 * l - m2;
1588 return new Rgb(
1589 hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2),
1590 hsl2rgb(h, m1, m2),
1591 hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2),
1592 this.opacity
1593 );
1594 },
1595 displayable: function() {
1596 return (0 <= this.s && this.s <= 1 || isNaN(this.s))
1597 && (0 <= this.l && this.l <= 1)
1598 && (0 <= this.opacity && this.opacity <= 1);
1599 }
1600}));
1601
1602/* From FvD 13.37, CSS Color Module Level 3 */
1603function hsl2rgb(h, m1, m2) {
1604 return (h < 60 ? m1 + (m2 - m1) * h / 60
1605 : h < 180 ? m2
1606 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60
1607 : m1) * 255;
1608}
1609
1610var deg2rad = Math.PI / 180;
1611var rad2deg = 180 / Math.PI;
1612
1613var Kn = 18;
1614var Xn = 0.950470;
1615var Yn = 1;
1616var Zn = 1.088830;
1617var t0 = 4 / 29;
1618var t1 = 6 / 29;
1619var t2 = 3 * t1 * t1;
1620var t3 = t1 * t1 * t1;
1621
1622function labConvert(o) {
1623 if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity);
1624 if (o instanceof Hcl) {
1625 var h = o.h * deg2rad;
1626 return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity);
1627 }
1628 if (!(o instanceof Rgb)) o = rgbConvert(o);
1629 var b = rgb2xyz(o.r),
1630 a = rgb2xyz(o.g),
1631 l = rgb2xyz(o.b),
1632 x = xyz2lab((0.4124564 * b + 0.3575761 * a + 0.1804375 * l) / Xn),
1633 y = xyz2lab((0.2126729 * b + 0.7151522 * a + 0.0721750 * l) / Yn),
1634 z = xyz2lab((0.0193339 * b + 0.1191920 * a + 0.9503041 * l) / Zn);
1635 return new Lab(116 * y - 16, 500 * (x - y), 200 * (y - z), o.opacity);
1636}
1637
1638function lab(l, a, b, opacity) {
1639 return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity);
1640}
1641
1642function Lab(l, a, b, opacity) {
1643 this.l = +l;
1644 this.a = +a;
1645 this.b = +b;
1646 this.opacity = +opacity;
1647}
1648
1649define(Lab, lab, extend(Color, {
1650 brighter: function(k) {
1651 return new Lab(this.l + Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
1652 },
1653 darker: function(k) {
1654 return new Lab(this.l - Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
1655 },
1656 rgb: function() {
1657 var y = (this.l + 16) / 116,
1658 x = isNaN(this.a) ? y : y + this.a / 500,
1659 z = isNaN(this.b) ? y : y - this.b / 200;
1660 y = Yn * lab2xyz(y);
1661 x = Xn * lab2xyz(x);
1662 z = Zn * lab2xyz(z);
1663 return new Rgb(
1664 xyz2rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z), // D65 -> sRGB
1665 xyz2rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z),
1666 xyz2rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z),
1667 this.opacity
1668 );
1669 }
1670}));
1671
1672function xyz2lab(t) {
1673 return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
1674}
1675
1676function lab2xyz(t) {
1677 return t > t1 ? t * t * t : t2 * (t - t0);
1678}
1679
1680function xyz2rgb(x) {
1681 return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
1682}
1683
1684function rgb2xyz(x) {
1685 return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
1686}
1687
1688function hclConvert(o) {
1689 if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity);
1690 if (!(o instanceof Lab)) o = labConvert(o);
1691 var h = Math.atan2(o.b, o.a) * rad2deg;
1692 return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity);
1693}
1694
1695function hcl(h, c, l, opacity) {
1696 return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity);
1697}
1698
1699function Hcl(h, c, l, opacity) {
1700 this.h = +h;
1701 this.c = +c;
1702 this.l = +l;
1703 this.opacity = +opacity;
1704}
1705
1706define(Hcl, hcl, extend(Color, {
1707 brighter: function(k) {
1708 return new Hcl(this.h, this.c, this.l + Kn * (k == null ? 1 : k), this.opacity);
1709 },
1710 darker: function(k) {
1711 return new Hcl(this.h, this.c, this.l - Kn * (k == null ? 1 : k), this.opacity);
1712 },
1713 rgb: function() {
1714 return labConvert(this).rgb();
1715 }
1716}));
1717
1718var A = -0.14861;
1719var B = +1.78277;
1720var C = -0.29227;
1721var D = -0.90649;
1722var E = +1.97294;
1723var ED = E * D;
1724var EB = E * B;
1725var BC_DA = B * C - D * A;
1726
1727function cubehelixConvert(o) {
1728 if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity);
1729 if (!(o instanceof Rgb)) o = rgbConvert(o);
1730 var r = o.r / 255,
1731 g = o.g / 255,
1732 b = o.b / 255,
1733 l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB),
1734 bl = b - l,
1735 k = (E * (g - l) - C * bl) / D,
1736 s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), // NaN if l=0 or l=1
1737 h = s ? Math.atan2(k, bl) * rad2deg - 120 : NaN;
1738 return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity);
1739}
1740
1741function cubehelix(h, s, l, opacity) {
1742 return arguments.length === 1 ? cubehelixConvert(h) : new Cubehelix(h, s, l, opacity == null ? 1 : opacity);
1743}
1744
1745function Cubehelix(h, s, l, opacity) {
1746 this.h = +h;
1747 this.s = +s;
1748 this.l = +l;
1749 this.opacity = +opacity;
1750}
1751
1752define(Cubehelix, cubehelix, extend(Color, {
1753 brighter: function(k) {
1754 k = k == null ? brighter : Math.pow(brighter, k);
1755 return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
1756 },
1757 darker: function(k) {
1758 k = k == null ? darker : Math.pow(darker, k);
1759 return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
1760 },
1761 rgb: function() {
1762 var h = isNaN(this.h) ? 0 : (this.h + 120) * deg2rad,
1763 l = +this.l,
1764 a = isNaN(this.s) ? 0 : this.s * l * (1 - l),
1765 cosh = Math.cos(h),
1766 sinh = Math.sin(h);
1767 return new Rgb(
1768 255 * (l + a * (A * cosh + B * sinh)),
1769 255 * (l + a * (C * cosh + D * sinh)),
1770 255 * (l + a * (E * cosh)),
1771 this.opacity
1772 );
1773 }
1774}));
1775
1776function basis(t1, v0, v1, v2, v3) {
1777 var t2 = t1 * t1, t3 = t2 * t1;
1778 return ((1 - 3 * t1 + 3 * t2 - t3) * v0
1779 + (4 - 6 * t2 + 3 * t3) * v1
1780 + (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2
1781 + t3 * v3) / 6;
1782}
1783
1784var constant$2 = function(x) {
1785 return function() {
1786 return x;
1787 };
1788};
1789
1790function linear$1(a, d) {
1791 return function(t) {
1792 return a + t * d;
1793 };
1794}
1795
1796function exponential(a, b, y) {
1797 return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {
1798 return Math.pow(a + t * b, y);
1799 };
1800}
1801
1802function hue(a, b) {
1803 var d = b - a;
1804 return d ? linear$1(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant$2(isNaN(a) ? b : a);
1805}
1806
1807function gamma(y) {
1808 return (y = +y) === 1 ? nogamma : function(a, b) {
1809 return b - a ? exponential(a, b, y) : constant$2(isNaN(a) ? b : a);
1810 };
1811}
1812
1813function nogamma(a, b) {
1814 var d = b - a;
1815 return d ? linear$1(a, d) : constant$2(isNaN(a) ? b : a);
1816}
1817
1818var rgb$1 = ((function rgbGamma(y) {
1819 var color$$1 = gamma(y);
1820
1821 function rgb$$1(start, end) {
1822 var r = color$$1((start = rgb(start)).r, (end = rgb(end)).r),
1823 g = color$$1(start.g, end.g),
1824 b = color$$1(start.b, end.b),
1825 opacity = nogamma(start.opacity, end.opacity);
1826 return function(t) {
1827 start.r = r(t);
1828 start.g = g(t);
1829 start.b = b(t);
1830 start.opacity = opacity(t);
1831 return start + "";
1832 };
1833 }
1834
1835 rgb$$1.gamma = rgbGamma;
1836
1837 return rgb$$1;
1838}))(1);
1839
1840var array$1 = function(a, b) {
1841 var nb = b ? b.length : 0,
1842 na = a ? Math.min(nb, a.length) : 0,
1843 x = new Array(nb),
1844 c = new Array(nb),
1845 i;
1846
1847 for (i = 0; i < na; ++i) x[i] = interpolateValue(a[i], b[i]);
1848 for (; i < nb; ++i) c[i] = b[i];
1849
1850 return function(t) {
1851 for (i = 0; i < na; ++i) c[i] = x[i](t);
1852 return c;
1853 };
1854};
1855
1856var date = function(a, b) {
1857 var d = new Date;
1858 return a = +a, b -= a, function(t) {
1859 return d.setTime(a + b * t), d;
1860 };
1861};
1862
1863var number$2 = function(a, b) {
1864 return a = +a, b -= a, function(t) {
1865 return a + b * t;
1866 };
1867};
1868
1869var object = function(a, b) {
1870 var i = {},
1871 c = {},
1872 k;
1873
1874 if (a === null || typeof a !== "object") a = {};
1875 if (b === null || typeof b !== "object") b = {};
1876
1877 for (k in b) {
1878 if (k in a) {
1879 i[k] = interpolateValue(a[k], b[k]);
1880 } else {
1881 c[k] = b[k];
1882 }
1883 }
1884
1885 return function(t) {
1886 for (k in i) c[k] = i[k](t);
1887 return c;
1888 };
1889};
1890
1891var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
1892var reB = new RegExp(reA.source, "g");
1893
1894function zero(b) {
1895 return function() {
1896 return b;
1897 };
1898}
1899
1900function one(b) {
1901 return function(t) {
1902 return b(t) + "";
1903 };
1904}
1905
1906var string = function(a, b) {
1907 var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b
1908 am, // current match in a
1909 bm, // current match in b
1910 bs, // string preceding current number in b, if any
1911 i = -1, // index in s
1912 s = [], // string constants and placeholders
1913 q = []; // number interpolators
1914
1915 // Coerce inputs to strings.
1916 a = a + "", b = b + "";
1917
1918 // Interpolate pairs of numbers in a & b.
1919 while ((am = reA.exec(a))
1920 && (bm = reB.exec(b))) {
1921 if ((bs = bm.index) > bi) { // a string precedes the next number in b
1922 bs = b.slice(bi, bs);
1923 if (s[i]) s[i] += bs; // coalesce with previous string
1924 else s[++i] = bs;
1925 }
1926 if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match
1927 if (s[i]) s[i] += bm; // coalesce with previous string
1928 else s[++i] = bm;
1929 } else { // interpolate non-matching numbers
1930 s[++i] = null;
1931 q.push({i: i, x: number$2(am, bm)});
1932 }
1933 bi = reB.lastIndex;
1934 }
1935
1936 // Add remains of b.
1937 if (bi < b.length) {
1938 bs = b.slice(bi);
1939 if (s[i]) s[i] += bs; // coalesce with previous string
1940 else s[++i] = bs;
1941 }
1942
1943 // Special optimization for only a single match.
1944 // Otherwise, interpolate each of the numbers and rejoin the string.
1945 return s.length < 2 ? (q[0]
1946 ? one(q[0].x)
1947 : zero(b))
1948 : (b = q.length, function(t) {
1949 for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
1950 return s.join("");
1951 });
1952};
1953
1954var interpolateValue = function(a, b) {
1955 var t = typeof b, c;
1956 return b == null || t === "boolean" ? constant$2(b)
1957 : (t === "number" ? number$2
1958 : t === "string" ? ((c = color(b)) ? (b = c, rgb$1) : string)
1959 : b instanceof color ? rgb$1
1960 : b instanceof Date ? date
1961 : Array.isArray(b) ? array$1
1962 : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object
1963 : number$2)(a, b);
1964};
1965
1966var interpolateRound = function(a, b) {
1967 return a = +a, b -= a, function(t) {
1968 return Math.round(a + b * t);
1969 };
1970};
1971
1972// p0 = [ux0, uy0, w0]
1973// p1 = [ux1, uy1, w1]
1974
1975function cubehelix$1(hue$$1) {
1976 return (function cubehelixGamma(y) {
1977 y = +y;
1978
1979 function cubehelix$$1(start, end) {
1980 var h = hue$$1((start = cubehelix(start)).h, (end = cubehelix(end)).h),
1981 s = nogamma(start.s, end.s),
1982 l = nogamma(start.l, end.l),
1983 opacity = nogamma(start.opacity, end.opacity);
1984 return function(t) {
1985 start.h = h(t);
1986 start.s = s(t);
1987 start.l = l(Math.pow(t, y));
1988 start.opacity = opacity(t);
1989 return start + "";
1990 };
1991 }
1992
1993 cubehelix$$1.gamma = cubehelixGamma;
1994
1995 return cubehelix$$1;
1996 })(1);
1997}
1998
1999cubehelix$1(hue);
2000var cubehelixLong = cubehelix$1(nogamma);
2001
2002var array$2 = Array.prototype;
2003
2004var map$1 = array$2.map;
2005var slice$2 = array$2.slice;
2006
2007var constant$3 = function(x) {
2008 return function() {
2009 return x;
2010 };
2011};
2012
2013var number$3 = function(x) {
2014 return +x;
2015};
2016
2017var unit = [0, 1];
2018
2019function deinterpolateLinear(a, b) {
2020 return (b -= (a = +a))
2021 ? function(x) { return (x - a) / b; }
2022 : constant$3(b);
2023}
2024
2025function deinterpolateClamp(deinterpolate) {
2026 return function(a, b) {
2027 var d = deinterpolate(a = +a, b = +b);
2028 return function(x) { return x <= a ? 0 : x >= b ? 1 : d(x); };
2029 };
2030}
2031
2032function reinterpolateClamp(reinterpolate) {
2033 return function(a, b) {
2034 var r = reinterpolate(a = +a, b = +b);
2035 return function(t) { return t <= 0 ? a : t >= 1 ? b : r(t); };
2036 };
2037}
2038
2039function bimap(domain, range$$1, deinterpolate, reinterpolate) {
2040 var d0 = domain[0], d1 = domain[1], r0 = range$$1[0], r1 = range$$1[1];
2041 if (d1 < d0) d0 = deinterpolate(d1, d0), r0 = reinterpolate(r1, r0);
2042 else d0 = deinterpolate(d0, d1), r0 = reinterpolate(r0, r1);
2043 return function(x) { return r0(d0(x)); };
2044}
2045
2046function polymap(domain, range$$1, deinterpolate, reinterpolate) {
2047 var j = Math.min(domain.length, range$$1.length) - 1,
2048 d = new Array(j),
2049 r = new Array(j),
2050 i = -1;
2051
2052 // Reverse descending domains.
2053 if (domain[j] < domain[0]) {
2054 domain = domain.slice().reverse();
2055 range$$1 = range$$1.slice().reverse();
2056 }
2057
2058 while (++i < j) {
2059 d[i] = deinterpolate(domain[i], domain[i + 1]);
2060 r[i] = reinterpolate(range$$1[i], range$$1[i + 1]);
2061 }
2062
2063 return function(x) {
2064 var i = bisectRight(domain, x, 1, j) - 1;
2065 return r[i](d[i](x));
2066 };
2067}
2068
2069function copy(source, target) {
2070 return target
2071 .domain(source.domain())
2072 .range(source.range())
2073 .interpolate(source.interpolate())
2074 .clamp(source.clamp());
2075}
2076
2077// deinterpolate(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
2078// reinterpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding domain value x in [a,b].
2079function continuous(deinterpolate, reinterpolate) {
2080 var domain = unit,
2081 range$$1 = unit,
2082 interpolate$$1 = interpolateValue,
2083 clamp = false,
2084 piecewise,
2085 output,
2086 input;
2087
2088 function rescale() {
2089 piecewise = Math.min(domain.length, range$$1.length) > 2 ? polymap : bimap;
2090 output = input = null;
2091 return scale;
2092 }
2093
2094 function scale(x) {
2095 return (output || (output = piecewise(domain, range$$1, clamp ? deinterpolateClamp(deinterpolate) : deinterpolate, interpolate$$1)))(+x);
2096 }
2097
2098 scale.invert = function(y) {
2099 return (input || (input = piecewise(range$$1, domain, deinterpolateLinear, clamp ? reinterpolateClamp(reinterpolate) : reinterpolate)))(+y);
2100 };
2101
2102 scale.domain = function(_) {
2103 return arguments.length ? (domain = map$1.call(_, number$3), rescale()) : domain.slice();
2104 };
2105
2106 scale.range = function(_) {
2107 return arguments.length ? (range$$1 = slice$2.call(_), rescale()) : range$$1.slice();
2108 };
2109
2110 scale.rangeRound = function(_) {
2111 return range$$1 = slice$2.call(_), interpolate$$1 = interpolateRound, rescale();
2112 };
2113
2114 scale.clamp = function(_) {
2115 return arguments.length ? (clamp = !!_, rescale()) : clamp;
2116 };
2117
2118 scale.interpolate = function(_) {
2119 return arguments.length ? (interpolate$$1 = _, rescale()) : interpolate$$1;
2120 };
2121
2122 return rescale();
2123}
2124
2125// Computes the decimal coefficient and exponent of the specified number x with
2126// significant digits p, where x is positive and p is in [1, 21] or undefined.
2127// For example, formatDecimal(1.23) returns ["123", 0].
2128var formatDecimal = function(x, p) {
2129 if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
2130 var i, coefficient = x.slice(0, i);
2131
2132 // The string returned by toExponential either has the form \d\.\d+e[-+]\d+
2133 // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
2134 return [
2135 coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
2136 +x.slice(i + 1)
2137 ];
2138};
2139
2140var exponent = function(x) {
2141 return x = formatDecimal(Math.abs(x)), x ? x[1] : NaN;
2142};
2143
2144var formatGroup = function(grouping, thousands) {
2145 return function(value, width) {
2146 var i = value.length,
2147 t = [],
2148 j = 0,
2149 g = grouping[0],
2150 length = 0;
2151
2152 while (i > 0 && g > 0) {
2153 if (length + g + 1 > width) g = Math.max(1, width - length);
2154 t.push(value.substring(i -= g, i + g));
2155 if ((length += g + 1) > width) break;
2156 g = grouping[j = (j + 1) % grouping.length];
2157 }
2158
2159 return t.reverse().join(thousands);
2160 };
2161};
2162
2163var formatNumerals = function(numerals) {
2164 return function(value) {
2165 return value.replace(/[0-9]/g, function(i) {
2166 return numerals[+i];
2167 });
2168 };
2169};
2170
2171var formatDefault = function(x, p) {
2172 x = x.toPrecision(p);
2173
2174 out: for (var n = x.length, i = 1, i0 = -1, i1; i < n; ++i) {
2175 switch (x[i]) {
2176 case ".": i0 = i1 = i; break;
2177 case "0": if (i0 === 0) i0 = i; i1 = i; break;
2178 case "e": break out;
2179 default: if (i0 > 0) i0 = 0; break;
2180 }
2181 }
2182
2183 return i0 > 0 ? x.slice(0, i0) + x.slice(i1 + 1) : x;
2184};
2185
2186var prefixExponent;
2187
2188var formatPrefixAuto = function(x, p) {
2189 var d = formatDecimal(x, p);
2190 if (!d) return x + "";
2191 var coefficient = d[0],
2192 exponent = d[1],
2193 i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
2194 n = coefficient.length;
2195 return i === n ? coefficient
2196 : i > n ? coefficient + new Array(i - n + 1).join("0")
2197 : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i)
2198 : "0." + new Array(1 - i).join("0") + formatDecimal(x, Math.max(0, p + i - 1))[0]; // less than 1y!
2199};
2200
2201var formatRounded = function(x, p) {
2202 var d = formatDecimal(x, p);
2203 if (!d) return x + "";
2204 var coefficient = d[0],
2205 exponent = d[1];
2206 return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient
2207 : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1)
2208 : coefficient + new Array(exponent - coefficient.length + 2).join("0");
2209};
2210
2211var formatTypes = {
2212 "": formatDefault,
2213 "%": function(x, p) { return (x * 100).toFixed(p); },
2214 "b": function(x) { return Math.round(x).toString(2); },
2215 "c": function(x) { return x + ""; },
2216 "d": function(x) { return Math.round(x).toString(10); },
2217 "e": function(x, p) { return x.toExponential(p); },
2218 "f": function(x, p) { return x.toFixed(p); },
2219 "g": function(x, p) { return x.toPrecision(p); },
2220 "o": function(x) { return Math.round(x).toString(8); },
2221 "p": function(x, p) { return formatRounded(x * 100, p); },
2222 "r": formatRounded,
2223 "s": formatPrefixAuto,
2224 "X": function(x) { return Math.round(x).toString(16).toUpperCase(); },
2225 "x": function(x) { return Math.round(x).toString(16); }
2226};
2227
2228// [[fill]align][sign][symbol][0][width][,][.precision][type]
2229var re = /^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;
2230
2231function formatSpecifier(specifier) {
2232 return new FormatSpecifier(specifier);
2233}
2234
2235formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof
2236
2237function FormatSpecifier(specifier) {
2238 if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
2239
2240 var match,
2241 fill = match[1] || " ",
2242 align = match[2] || ">",
2243 sign = match[3] || "-",
2244 symbol = match[4] || "",
2245 zero = !!match[5],
2246 width = match[6] && +match[6],
2247 comma = !!match[7],
2248 precision = match[8] && +match[8].slice(1),
2249 type = match[9] || "";
2250
2251 // The "n" type is an alias for ",g".
2252 if (type === "n") comma = true, type = "g";
2253
2254 // Map invalid types to the default format.
2255 else if (!formatTypes[type]) type = "";
2256
2257 // If zero fill is specified, padding goes after sign and before digits.
2258 if (zero || (fill === "0" && align === "=")) zero = true, fill = "0", align = "=";
2259
2260 this.fill = fill;
2261 this.align = align;
2262 this.sign = sign;
2263 this.symbol = symbol;
2264 this.zero = zero;
2265 this.width = width;
2266 this.comma = comma;
2267 this.precision = precision;
2268 this.type = type;
2269}
2270
2271FormatSpecifier.prototype.toString = function() {
2272 return this.fill
2273 + this.align
2274 + this.sign
2275 + this.symbol
2276 + (this.zero ? "0" : "")
2277 + (this.width == null ? "" : Math.max(1, this.width | 0))
2278 + (this.comma ? "," : "")
2279 + (this.precision == null ? "" : "." + Math.max(0, this.precision | 0))
2280 + this.type;
2281};
2282
2283var identity$3 = function(x) {
2284 return x;
2285};
2286
2287var prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];
2288
2289var formatLocale = function(locale) {
2290 var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity$3,
2291 currency = locale.currency,
2292 decimal = locale.decimal,
2293 numerals = locale.numerals ? formatNumerals(locale.numerals) : identity$3,
2294 percent = locale.percent || "%";
2295
2296 function newFormat(specifier) {
2297 specifier = formatSpecifier(specifier);
2298
2299 var fill = specifier.fill,
2300 align = specifier.align,
2301 sign = specifier.sign,
2302 symbol = specifier.symbol,
2303 zero = specifier.zero,
2304 width = specifier.width,
2305 comma = specifier.comma,
2306 precision = specifier.precision,
2307 type = specifier.type;
2308
2309 // Compute the prefix and suffix.
2310 // For SI-prefix, the suffix is lazily computed.
2311 var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
2312 suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? percent : "";
2313
2314 // What format function should we use?
2315 // Is this an integer type?
2316 // Can this type generate exponential notation?
2317 var formatType = formatTypes[type],
2318 maybeSuffix = !type || /[defgprs%]/.test(type);
2319
2320 // Set the default precision if not specified,
2321 // or clamp the specified precision to the supported range.
2322 // For significant precision, it must be in [1, 21].
2323 // For fixed precision, it must be in [0, 20].
2324 precision = precision == null ? (type ? 6 : 12)
2325 : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))
2326 : Math.max(0, Math.min(20, precision));
2327
2328 function format(value) {
2329 var valuePrefix = prefix,
2330 valueSuffix = suffix,
2331 i, n, c;
2332
2333 if (type === "c") {
2334 valueSuffix = formatType(value) + valueSuffix;
2335 value = "";
2336 } else {
2337 value = +value;
2338
2339 // Perform the initial formatting.
2340 var valueNegative = value < 0;
2341 value = formatType(Math.abs(value), precision);
2342
2343 // If a negative value rounds to zero during formatting, treat as positive.
2344 if (valueNegative && +value === 0) valueNegative = false;
2345
2346 // Compute the prefix and suffix.
2347 valuePrefix = (valueNegative ? (sign === "(" ? sign : "-") : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
2348 valueSuffix = valueSuffix + (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + (valueNegative && sign === "(" ? ")" : "");
2349
2350 // Break the formatted value into the integer “value” part that can be
2351 // grouped, and fractional or exponential “suffix” part that is not.
2352 if (maybeSuffix) {
2353 i = -1, n = value.length;
2354 while (++i < n) {
2355 if (c = value.charCodeAt(i), 48 > c || c > 57) {
2356 valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
2357 value = value.slice(0, i);
2358 break;
2359 }
2360 }
2361 }
2362 }
2363
2364 // If the fill character is not "0", grouping is applied before padding.
2365 if (comma && !zero) value = group(value, Infinity);
2366
2367 // Compute the padding.
2368 var length = valuePrefix.length + value.length + valueSuffix.length,
2369 padding = length < width ? new Array(width - length + 1).join(fill) : "";
2370
2371 // If the fill character is "0", grouping is applied after padding.
2372 if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
2373
2374 // Reconstruct the final output based on the desired alignment.
2375 switch (align) {
2376 case "<": value = valuePrefix + value + valueSuffix + padding; break;
2377 case "=": value = valuePrefix + padding + value + valueSuffix; break;
2378 case "^": value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length); break;
2379 default: value = padding + valuePrefix + value + valueSuffix; break;
2380 }
2381
2382 return numerals(value);
2383 }
2384
2385 format.toString = function() {
2386 return specifier + "";
2387 };
2388
2389 return format;
2390 }
2391
2392 function formatPrefix(specifier, value) {
2393 var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
2394 e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
2395 k = Math.pow(10, -e),
2396 prefix = prefixes[8 + e / 3];
2397 return function(value) {
2398 return f(k * value) + prefix;
2399 };
2400 }
2401
2402 return {
2403 format: newFormat,
2404 formatPrefix: formatPrefix
2405 };
2406};
2407
2408var locale;
2409var format;
2410var formatPrefix;
2411
2412defaultLocale({
2413 decimal: ".",
2414 thousands: ",",
2415 grouping: [3],
2416 currency: ["$", ""]
2417});
2418
2419function defaultLocale(definition) {
2420 locale = formatLocale(definition);
2421 format = locale.format;
2422 formatPrefix = locale.formatPrefix;
2423 return locale;
2424}
2425
2426var precisionFixed = function(step) {
2427 return Math.max(0, -exponent(Math.abs(step)));
2428};
2429
2430var precisionPrefix = function(step, value) {
2431 return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step)));
2432};
2433
2434var precisionRound = function(step, max) {
2435 step = Math.abs(step), max = Math.abs(max) - step;
2436 return Math.max(0, exponent(max) - exponent(step)) + 1;
2437};
2438
2439var tickFormat = function(domain, count, specifier) {
2440 var start = domain[0],
2441 stop = domain[domain.length - 1],
2442 step = tickStep(start, stop, count == null ? 10 : count),
2443 precision;
2444 specifier = formatSpecifier(specifier == null ? ",f" : specifier);
2445 switch (specifier.type) {
2446 case "s": {
2447 var value = Math.max(Math.abs(start), Math.abs(stop));
2448 if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;
2449 return formatPrefix(specifier, value);
2450 }
2451 case "":
2452 case "e":
2453 case "g":
2454 case "p":
2455 case "r": {
2456 if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
2457 break;
2458 }
2459 case "f":
2460 case "%": {
2461 if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
2462 break;
2463 }
2464 }
2465 return format(specifier);
2466};
2467
2468function linearish(scale) {
2469 var domain = scale.domain;
2470
2471 scale.ticks = function(count) {
2472 var d = domain();
2473 return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
2474 };
2475
2476 scale.tickFormat = function(count, specifier) {
2477 return tickFormat(domain(), count, specifier);
2478 };
2479
2480 scale.nice = function(count) {
2481 if (count == null) count = 10;
2482
2483 var d = domain(),
2484 i0 = 0,
2485 i1 = d.length - 1,
2486 start = d[i0],
2487 stop = d[i1],
2488 step;
2489
2490 if (stop < start) {
2491 step = start, start = stop, stop = step;
2492 step = i0, i0 = i1, i1 = step;
2493 }
2494
2495 step = tickIncrement(start, stop, count);
2496
2497 if (step > 0) {
2498 start = Math.floor(start / step) * step;
2499 stop = Math.ceil(stop / step) * step;
2500 step = tickIncrement(start, stop, count);
2501 } else if (step < 0) {
2502 start = Math.ceil(start * step) / step;
2503 stop = Math.floor(stop * step) / step;
2504 step = tickIncrement(start, stop, count);
2505 }
2506
2507 if (step > 0) {
2508 d[i0] = Math.floor(start / step) * step;
2509 d[i1] = Math.ceil(stop / step) * step;
2510 domain(d);
2511 } else if (step < 0) {
2512 d[i0] = Math.ceil(start * step) / step;
2513 d[i1] = Math.floor(stop * step) / step;
2514 domain(d);
2515 }
2516
2517 return scale;
2518 };
2519
2520 return scale;
2521}
2522
2523function linear() {
2524 var scale = continuous(deinterpolateLinear, number$2);
2525
2526 scale.copy = function() {
2527 return copy(scale, linear());
2528 };
2529
2530 return linearish(scale);
2531}
2532
2533// We’re importing from an individual file rather than the top level of the d3-scale
2534// module to work around a tree-shaking issue that otherwise causes a lot of irrelevant
2535// d3-scale code to be pulled into the “full” build. See issues:
2536//
2537// https://github.com/rollup/rollup/issues/305
2538// https://github.com/rollup/rollup/issues/1208
2539//
2540// There are some associated shenanigans in rollup.config.js to accommodate this.
2541//
2542// If and when rollup manages to avoid this problem, we can revert back to the
2543// straightforward approach.
2544var VERSION = "1.3.1";
2545
2546function Slider(selector$$1) {
2547 this.container = d3_select(selector$$1);
2548
2549 this._width = null;
2550 this._height = null;
2551
2552 this._handleRadius = 15;
2553 this._channelHeight = 5;
2554 this._channelRadius = null;
2555
2556 this._handleFill = "black";
2557 this._channelFill = "#eee";
2558
2559 this._margin = { top: null, left: null, right: null };
2560
2561 this._domain = [0,1];
2562 this._value = null;
2563 this._snap = false;
2564
2565 this._scale = null;
2566 this._axis = false;
2567 this._ticks = null;
2568 this._tickFormat = null;
2569 this._tickSize = null;
2570
2571 this._label = null;
2572 this._labelSize = 18;
2573
2574 this._startLabel = null;
2575 this._startLabelBelow = false;
2576
2577 this._endLabel = null;
2578 this._endLabelBelow = false;
2579
2580 this._startEndLabelSize = 16;
2581
2582 this.handlers = { "change": [] };
2583}
2584
2585// Create accessor methods for all the _parameters defined by the constructor
2586function accessor(k) {
2587 if (k.length > 0 && k.charAt(0) == "_") {
2588 Slider.prototype[k.substr(1)] = function(v) {
2589 if (typeof v == "undefined") return this[k];
2590 this[k] = v;
2591 return this;
2592 };
2593 }
2594}
2595var s = new Slider();
2596for (var k in s) {
2597 accessor(k);
2598}
2599
2600// Special accessor function for margin
2601Slider.prototype.margin = function Slider_margin(options) {
2602 if (!options) return this._margin;
2603 for (k in options) {
2604 if (k in this._margin) this._margin[k] = options[k];
2605 else throw "Slider.margin: unrecognised option " + k;
2606 }
2607 return this;
2608};
2609
2610// Attach event handlers
2611Slider.prototype.on = function Slider_on(event$$1, handler) {
2612 if (!(event$$1 in this.handlers)) throw "Slider.on: No such event: " + event$$1;
2613 this.handlers[event$$1].push(handler);
2614 return this;
2615};
2616
2617// Fire event
2618Slider.prototype.fire = function Slider_fire(event$$1, d) {
2619 if (!(event$$1 in this.handlers)) throw "Slider.fire: No such event: " + event$$1;
2620 var handlers = this.handlers[event$$1];
2621 for (var i = 0; i < handlers.length; i++) {
2622 handlers[i].call(this, d);
2623 }
2624 return this;
2625};
2626
2627// Binary search
2628function closestValue(sorted_list, value, a, b) {
2629 if (typeof a === "undefined") a = 0;
2630 if (typeof b === "undefined") b = sorted_list.length;
2631
2632 if (b-a == 0) return value;
2633 if (b-a == 1) return sorted_list[a];
2634 if (b-a == 2) {
2635 var d1 = Math.abs(sorted_list[a] - value),
2636 d2 = Math.abs(sorted_list[a+1] - value);
2637 if (d1 <= d2) return sorted_list[a];
2638 else return sorted_list[a+1];
2639 }
2640
2641 var mid = a + Math.floor((b-a) / 2),
2642 mid_v = sorted_list[mid];
2643 pre = mid - 1,
2644 pre_v = sorted_list[pre];
2645 if (pre_v <= value && value <= mid_v) {
2646 return (Math.abs(pre_v - value) <= Math.abs(mid_v - value)) ? pre_v : mid_v;
2647 }
2648 if (mid_v <= value) return closestValue(sorted_list, value, mid, b);
2649 else return closestValue(sorted_list, value, a, mid);
2650}
2651
2652function snapTo(specification, value) {
2653 if (typeof specification == "boolean") {
2654 return specification ? Math.round(value) : value;
2655 }
2656 // Otherwise assume “specification” is a sorted array
2657 return closestValue(specification, value);
2658}
2659
2660// Draw or update the slider
2661Slider.prototype.draw = function Slider_draw() {
2662 var that = this;
2663
2664 var cw = this._width,
2665 ch = this._height;
2666
2667 var container_node = this.container.node();
2668
2669 // If the width and height have not been specified, use
2670 // the client size of the container element.
2671 if (!cw) {
2672 var r = container_node.getBoundingClientRect();
2673 // If there isn’t a bounding client rect, e.g. because
2674 // the container is display: none;, then do nothing.
2675 if (!r || r.width == 0) return this;
2676
2677 cw = r.width;
2678 ch = r.height;
2679 }
2680
2681 var channel_r = this._channelRadius == null ? this._channelHeight/2 : this._channelRadius,
2682 left_margin = (this._margin.left == null ? Math.max(this._handleRadius, channel_r) : this._margin.left),
2683 right_margin = (this._margin.right == null ? Math.max(this._handleRadius, channel_r) : this._margin.right),
2684 top_margin = this._margin.top == null ? Math.max(this._handleRadius, this._channelHeight/2) : this._margin.top,
2685 w = cw - left_margin - right_margin, // Inner width of the slider channel (excluding endcaps)
2686 channel_w = w + 2*channel_r, // Width of the slider channel (including endcaps)
2687 label_h = this._labelSize * 1.5;
2688
2689 if (this._label != null && this._margin.top == null) top_margin += label_h;
2690
2691 var slider;
2692 if (container_node.namespaceURI == "http://www.w3.org/2000/svg") {
2693 slider = this.container;
2694 }
2695 else {
2696 slider = this.container.selectAll("svg").data([{ width: cw, height: ch }]);
2697 slider.exit().remove();
2698 slider = slider.enter().append("svg").merge(slider);
2699 slider.attr("width", function(d) { return d.width; })
2700 .attr("height", function(d) { return d.height; });
2701 }
2702
2703 var g = slider.selectAll("g.slider-container").data([{left: left_margin, top: top_margin, id: this._id}]);
2704 g.exit().remove();
2705 g = g.enter().append("g").attr("class", "slider-container").merge(g);
2706 g.attr("transform", function(d) {
2707 return "translate(" + d.left + "," + d.top + ")";
2708 })
2709 .attr("id", function(d) { return d.id; });
2710
2711 this.scale = (this._scale ? this._scale() : linear()).domain(this._domain).range([0, w]);
2712
2713 if (this._value == null || this._value < this._domain[0]) this._value = this._domain[0];
2714 else if (this._value > this._domain[1]) this._value = this._domain[1];
2715
2716 if (this._snap) this._value = snapTo(this._snap, this._value);
2717
2718 var axes_data = [];
2719 if (this._axis) {
2720 var axis;
2721 if (typeof this._axis != "boolean") {
2722 axis = this._axis(this.scale);
2723 }
2724 else {
2725 axis = axisBottom().scale(this.scale).tickPadding(6);
2726 }
2727
2728 if (this._ticks) axis.ticks(this._ticks);
2729 if (this._tickFormat) axis.tickFormat(this._tickFormat);
2730 if (this._tickSize) axis.tickSize(this._tickSize);
2731 else axis.tickSize(Math.max(5, this._handleRadius - this._channelHeight - 2));
2732 axes_data.push(axis);
2733 }
2734
2735 var axes = g.selectAll(".slider-axis");
2736 var axes_enter = axes.data(axes_data).enter();
2737 axes_enter.append("g").attr("class", "slider-axis")
2738 .attr("transform", "translate(" + 0 + "," + this._channelHeight/2 + ")")
2739 .each(function(axis) { axis(d3_select(this)); });
2740 axes_enter.select(".domain").attr("fill", "none");
2741 axes_enter.selectAll(".tick line").attr("stroke", "black");
2742 axes_enter.exit().remove();
2743
2744 var channel, handle;
2745 channel = g.selectAll(".slider-channel")
2746 .data([{ width: channel_w, height: this._channelHeight, channel_r: channel_r }]);
2747 channel.exit().remove();
2748
2749 channel = channel.enter().append("rect").attr("class", "slider-channel")
2750 .attr("fill", this._channelFill)
2751 .attr("cursor", "pointer")
2752 .on("click", function() {
2753 var slider_x = Math.max(0, Math.min(w, d3_mouse(this)[0]));
2754 that._value = that.scale.invert(slider_x);
2755 if (that._snap) that._value = snapTo(that._snap, that._value);
2756 handle.attr("cx", that.scale(that._value));
2757 that.fire("change", that._value);
2758 })
2759 .merge(channel);
2760
2761 channel.attr("width", function(d) { return d.width; })
2762 .attr("height", function(d) { return d.height; })
2763 .attr("y", function(d) { return -d.height/2; })
2764 .attr("x", function(d){ return -d.channel_r; })
2765 .attr("rx", function(d) { return d.channel_r; });
2766
2767 var drag_dx_origin, drag_x_origin;
2768 function handleMousedown(event$$1) {
2769 document.addEventListener("mouseup", handleMouseup, false);
2770 document.addEventListener("mousemove", handleMousemove, false);
2771 drag_dx_origin = event$$1.clientX;
2772 drag_x_origin = that.scale(that._value);
2773 }
2774
2775 function handleMouseup() {
2776 document.removeEventListener("mouseup", handleMouseup, false);
2777 document.removeEventListener("mousemove", handleMousemove, false);
2778 }
2779
2780 function handleMousemove(event$$1) {
2781 drag(event$$1.clientX - drag_dx_origin);
2782 }
2783
2784 function handleTouchstart(event$$1) {
2785 if (event$$1.touches.length != 1) return;
2786 document.addEventListener("touchend", handleTouchend, false);
2787 document.addEventListener("touchmove", handleTouchmove, false);
2788 drag_dx_origin = event$$1.touches[0].clientX;
2789 drag_x_origin = that.scale(that._value);
2790 }
2791
2792 function handleTouchend() {
2793 document.removeEventListener("touchend", handleTouchend, false);
2794 document.removeEventListener("touchmove", handleTouchmove, false);
2795 }
2796
2797 function handleTouchmove(event$$1) {
2798 if (event$$1.touches.length != 1) return;
2799 drag(event$$1.touches[0].clientX - drag_dx_origin);
2800 }
2801
2802 function drag(dx) {
2803 var new_x = drag_x_origin + dx;
2804 var slider_x = Math.max(0, Math.min(w, new_x));
2805 var new_value = that.scale.invert(slider_x);
2806 if (that._snap) new_value = snapTo(that._snap, new_value);
2807 handle.attr("cx", that.scale(new_value));
2808 if (new_value != that._value) {
2809 that._value = new_value;
2810 that.fire("change", that._value);
2811 }
2812 }
2813
2814 handle = g.selectAll(".slider-handle").data([{ v: this._value, x: this.scale(this._value) }]);
2815 handle = handle.enter().append("circle").attr("class", "slider-handle")
2816 .attr("cursor", "col-resize")
2817 .merge(handle);
2818
2819 handle.attr("cx", function(d) { return d.x; })
2820 .attr("r", this._handleRadius)
2821 .attr("fill", this._handleFill)
2822 .on("mousedown", function() {
2823 event.preventDefault();
2824 handleMousedown(event);
2825 })
2826 .on("touchstart", function() {
2827 event.preventDefault();
2828 handleTouchstart(event);
2829 });
2830
2831 var label_data = [];
2832 if (this._label) {
2833 label_data.push({
2834 label: this._label, x: w/2, y: -label_h, font_size: this._labelSize
2835 });
2836 }
2837 var label = g.selectAll(".slider-label").data(label_data);
2838 label.exit().remove();
2839 label = label.enter()
2840 .append("text").attr("class", "slider-label")
2841 .attr("text-anchor", "middle")
2842 .attr("cursor", "default")
2843 .merge(label);
2844
2845 label
2846 .text(function(d) { return d.label; })
2847 .attr("x", function(d) { return d.x; })
2848 .attr("y", function(d) { return d.y; })
2849 .attr("font-size", this._labelSize);
2850
2851 var end_label_data = [];
2852 if (this._startLabel) {
2853 end_label_data.push({
2854 label: this._startLabel,
2855 x: this._startLabelBelow ? 0 : -(channel_r + 5 + Math.max(0, this._handleRadius - channel_r)),
2856 y: this._startLabelBelow ? (channel_r + 15) : this._startEndLabelSize/1.75 - channel_r/2,
2857 anchor: this._startLabelBelow ? "middle" : "end",
2858 font_size: this._startEndLabelSize
2859 });
2860 }
2861 if (this._endLabel) {
2862 end_label_data.push({
2863 label: this._endLabel,
2864 x: this._endLabelBelow ? w : w + (channel_r + Math.max(0, this._handleRadius - channel_r) + 5),
2865 y: this._startLabelBelow ? (channel_r + 15) : this._startEndLabelSize/1.75 - channel_r/2,
2866 anchor: this._endLabelBelow ? "middle" : "start",
2867 font_size: this._startEndLabelSize
2868 });
2869 }
2870
2871 var end_labels = g.selectAll(".slider-end-labels").data(end_label_data);
2872 end_labels.exit().remove();
2873 end_labels = end_labels.enter().append("text").attr("class", "slider-end-labels")
2874 .attr("pointer-events", "none")
2875 .merge(end_labels);
2876 end_labels
2877 .text(function(d) { return d.label; })
2878 .attr("font-size", function(d) { return d.font_size; })
2879 .attr("x", function(d) { return d.x; })
2880 .attr("y", function(d) { return d.y; })
2881 .attr("text-anchor", function(d) { return d.anchor; });
2882
2883 return this;
2884};
2885
2886Slider.prototype.update = Slider.prototype.draw;
2887
2888function Flourish_slider(selector$$1) {
2889 return new Slider(selector$$1);
2890}
2891Flourish_slider.version = VERSION;
2892
2893var css_string = ".controls-container, .controls-container * {box-sizing: border-box; } .controls-container {display: inline-block; vertical-align: bottom; } .btn-group .btn, .dropdown .current {overflow: hidden; text-overflow: ellipsis; height: 100%; white-space: nowrap } .btn-group .btn, .dropdown .current, .dropdown .list .list-item {white-space: nowrap } .slider, .slider-play {pointer-events: all; vertical-align: bottom } .btn {display: inline-block; cursor: pointer } .btn:hover {opacity: .5 } .btn.selected, .btn.selected:hover {color: #fff; cursor: default; opacity: 1; background-image: linear-gradient(transparent, rgba(0, 0, 0, .05) 40%, rgba(0, 0, 0, .1)) } .btn-group {pointer-events: all; width: auto; line-height: 0; } .btn-group .btn {font-size: 12px; border: 1px solid #ccc; background: #fff; padding: 2px 8px; color: #333; font-weight: 400; text-align: center; line-height: 18px; height: 24px; border-radius: 3px; margin: 1px 1px 1px 1px; } .btn-group .btn:hover {background: #eee; opacity: .8 } .btn-group .btn.selected, .btn-group .btn.selected:hover {opacity: 1; background: #ececec; color: #333; } @media(min-width:520px) {.btn-group .btn {font-size: 14px; height: 30px; line-height: 24px; } } .dropdown {text-align: left; pointer-events: all; display: inline-table; color: #333; font-weight: 400; font-size: 16px; position: relative } .dropdown .heading {margin-bottom: 8px; font-weight: 300 } .dropdown .main {background: #fff; padding: 0 60px 0 6px; cursor: pointer; position: relative; border: 1px solid #ccc; border-radius: 3px; height: 24px; line-height: 22px; } .dropdown .list, .dropdown .symbol {position: absolute; } .dropdown .current {width: 100%; display: inline-block; font-size: 12px; } .dropdown .symbol {width: 30px; height: 100%; right: 0; top: 0; background: 80% 40% no-repeat; background-size: auto 50%; display: inline-block } .dropdown .list {top: 100%; left: -1px; min-width: calc(100% + 2px); background: rgba(255, 255, 255, 1); padding: 0 2px; text-align: left; display: none; line-height: 24px; max-height: 160px; overflow-y: scroll; color: #333; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); } .dropdown .list .list-item {font-size: 12px; height: 24px; padding: 0 5px; } .dropdown .list .list-item:hover {cursor: pointer; background: #eee; } .dropdown.open .list {display: block; z-index: 1 } .dropdown .list .list-item.selected, .dropdown .list .list-item.selected:hover {color: #57c1fc; cursor: default; opacity: 1 } .dropdown .list .list-item.header, .dropdown .list .list-item.header:hover {font-size: 16px; letter-spacing: 1px; text-transform: uppercase; color: #888; opacity: 1; cursor: default; font-weight: 300; margin-top: 8px; } .dropdown .list .list-item.header:first-child {margin-top: 0; } .controls-container .dropdown {margin: 0 0 20px; } .controls-container .dropdown .heading {color: #333; } @media(min-width:520px) {.dropdown .list .list-item {font-size: 14px; height: 24px; } .dropdown .main {height: 30px; line-height: 28px; } .dropdown .current {font-size: 14px; } } .slider-holder {margin-bottom: 20px } .slider-play {width: 24px; height: 24px; background-repeat: no-repeat; background-size: 100% 100%; background-position: center; cursor: pointer; display: none; margin-right: 2px; } @media(min-width:520px) {.slider-play {width: 30px; height: 30px; } } .slider, .slider-holder.animatable .slider-play {display: inline-block } .slider-play:hover {opacity: .7 } .slider {height: 46px; width: 100%; bottom: 0 } .slider-holder.animatable .slider {width: calc(100% - 37px) } .slider-holder.playing .slider {pointer-events: none } .slider circle {fill: #57c1fc; } .slider .tick line {stroke: #333; } .slider text {fill: #333; } .slider .slider-end-labels {font-size: 11px; fill: #9e9e9e; } .nav-buttons {margin-bottom: 19px; } ";
2894
2895// https://stackoverflow.com/a/21626701
2896function makeBackgroundString(svg_string) {
2897 return "url('data:image/svg+xml;base64," + window.btoa(svg_string) + "')";
2898}
2899
2900var chevron_body = '<svg width="6px" height="12px" viewBox="0 0 6 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <g transform="translate(-442.000000, -44.000000)" fill="#333333"> <g id="Group" transform="translate(442.000000, 44.000000)"> <polygon id="Triangle-2" points="3 0 6 5 0 5"></polygon> <polygon id="Triangle-2-Copy" points="3 12 0 7 6 7"></polygon> </g> </g> </svg>';
2901
2902var play_body = '<svg width="25px" height="30px" viewBox="0 0 25 30" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <polygon id="Triangle" fill="#333333" stroke="none" points="25 15 0 30 0 0"></polygon> </svg>';
2903
2904var pause_body = '<svg width="26px" height="30px" viewBox="0 0 26 30" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="Group"> <rect id="Rectangle-2" x="0" y="0" width="26" height="30"></rect> <rect id="Rectangle" fill="#333333" x="2" y="2" width="9" height="26"></rect> <rect id="Rectangle-Copy" fill="#333333" x="15" y="2" width="9" height="26"></rect> </g> </g> </svg>';
2905
2906var chevron_string = makeBackgroundString(chevron_body);
2907var play_string = makeBackgroundString(play_body);
2908var pause_string = makeBackgroundString(pause_body);
2909
2910(function injectCSS(css) {
2911 if (typeof document === 'undefined') return;
2912 css = css;
2913 var head = document.head || document.getElementsByTagName('head')[0];
2914 var style$$1 = document.createElement('style');
2915 style$$1.type = 'text/css';
2916 head.appendChild(style$$1);
2917
2918 if (style$$1.styleSheet){
2919 style$$1.styleSheet.cssText = css;
2920 } else {
2921 style$$1.appendChild(document.createTextNode(css));
2922 }
2923 return;
2924})(css_string);
2925
2926var control_types = ["default", "buttons", "dropdown", "slider", "none"];
2927
2928
2929function createControlsGroup(container_selector) {
2930 var output_obj = {};
2931 var options, visible_control, current_index, current_value, width, is_animatable;
2932
2933 var props = {
2934 "control_type": "default",
2935 width: 150,
2936 "step_time": 2,
2937 "loop_time": 1.5,
2938 "handle_colour": "#333"
2939 };
2940
2941 Object.keys(props).forEach(function(key) {
2942 // Convert from snake case properties to camel case methods
2943 var methodName = key.replace(/_\w/g, function(substr) { return substr.charAt(1).toUpperCase(); });
2944 output_obj[methodName] = function(val){
2945 if (val === undefined) return props[key];
2946 props[key] = val;
2947 return output_obj;
2948 };
2949 } );
2950
2951 props.control_type = "default";
2952
2953 output_obj.controlType = function(control_type) {
2954 if (control_type === undefined) return props.control_type;
2955 props.control_type = control_types.indexOf(control_type) !== -1 ? control_type : "default";
2956 return output_obj;
2957 };
2958
2959 props.index = 0;
2960
2961 output_obj.index = function(index) {
2962 if (index === undefined) return props.index;
2963 if (!Number.isFinite(index)) throw TypeError("index must be a number greater than or equal to 0.")
2964 if (index < 0) throw RangeError("index must be greater than or equal to 0.")
2965 props.index = Math.floor(index);
2966 return output_obj;
2967 };
2968
2969 props.options = [];
2970
2971 output_obj.options = function(opts) {
2972 if (opts === undefined) return props.options.slice();
2973 props.options = Object.freeze(opts.slice());
2974 return output_obj
2975 };
2976
2977 Object.defineProperty(props, "value", {
2978 get: function() { return props.options[props.index]; },
2979 set: function() { console.warn("Nothing changed: props.value is read only"); }
2980 } );
2981
2982 output_obj.value = function(value){
2983 if (value === undefined) return props.value;
2984 var index = props.options.indexOf(value);
2985 if(index !== -1) props.index = index;
2986 else console.warn("Nothing changed: value not in options list");
2987 return output_obj;
2988 };
2989
2990 props.changeHandlers = [];
2991
2992 output_obj.on = function(event$$1, callback){
2993 if(event$$1 === "change") props.changeHandlers.push(callback.bind(output_obj));
2994 return this;
2995 };
2996
2997 function onChangeCallbacks() {
2998 var value = props.value;
2999 var index = props.index;
3000 props.changeHandlers.forEach(function(func) {
3001 func(value, index);
3002 });
3003 }
3004
3005
3006 // Grab container
3007 var container = d3_select(container_selector).classed("controls-container", true);
3008
3009 // Add top-level divs to DOM
3010 var heading = container.append("div").attr("class", "heading");
3011 var dropdown = container.append("div").attr("class", "dropdown");
3012 var slider_holder = container.append("div").attr("class", "slider-holder animatable");
3013 var button_nav = container.append("div").attr("class", "nav-buttons");
3014
3015 // Add dropdown elements to DOM
3016 var dropdown_main = dropdown.append("div").attr("class", "main");
3017 var dropdown_current = dropdown_main.append("span").attr("class", "current");
3018
3019 dropdown_main.append("span").attr("class", "symbol").style("background-image", chevron_string);
3020 var dropdown_list = dropdown.append("div").attr("class", "list");
3021
3022 // Add slider elements to DOM
3023 var slider_play_button = slider_holder.append("div").attr("class", "slider-play").style("background-image", play_string);
3024 slider_holder.append("div").attr("class","slider");
3025
3026 // Add button group to DOM
3027 var button_group = button_nav.append("div").attr("class", "btn-group");
3028
3029 var showDropdownList = function(){
3030 dropdown.classed("open", true);
3031 };
3032
3033 var hideDropdownList = function(){
3034 dropdown.classed("open", false);
3035 };
3036
3037 var toggleDropdownList = function(){
3038 dropdown.classed("open", !dropdown.classed("open"));
3039 };
3040
3041 var dropdown_node = dropdown.node();
3042 document.querySelector("body").addEventListener('click', function(event$$1) {
3043 if (!dropdown.classed("open")) return; // If already closed, nothing to close
3044 var el = event$$1.target;
3045 var parent = el.parentElement;
3046 while ( parent ) {
3047 if (el === dropdown_node) return; // We've clicked the dropdown, don't close it here
3048 el = parent;
3049 parent = el.parentElement;
3050 }
3051 hideDropdownList(); //Clicked somewhere else, hide the dropdown
3052 }, false);
3053
3054 dropdown_main.on("click", function() {
3055 toggleDropdownList();
3056 } );
3057
3058 var updateDropdown = function() {
3059 dropdown_current.text(current_value).attr("title", current_value);
3060 dropdown_list.text("")
3061 .selectAll(".list-item")
3062 .data(options)
3063 .enter()
3064 .append("div")
3065 .attr("class", "list-item")
3066 .text(function(d) { return d; })
3067 .on("click", function(d, i) {
3068 hideDropdownList();
3069 if (d3_select(this).classed("selected")) return;
3070 props.index = i;
3071 onChangeCallbacks();
3072 });
3073 };
3074
3075 var slider = Flourish_slider(container_selector + " .slider-holder .slider");
3076
3077 var sliderplayer;
3078
3079 var stopSliderPlayer = function() {
3080 if (!sliderplayer) return;
3081 clearInterval(sliderplayer);
3082 sliderplayer = undefined;
3083 slider_holder.classed("playing", false);
3084 slider_play_button.style("background-image", play_string);
3085 };
3086
3087 var setSliderPlayerMove = function(next_index) {
3088 if (next_index === 0 && !props.loop_time) {
3089 stopSliderPlayer();
3090 return;
3091 }
3092
3093 var next_time_step = 1000 * Math.abs(props.step_time) * (next_index ? 1 : props.loop_time);
3094
3095 sliderplayer = setTimeout(function() {
3096 var index = props.step_time>0 ? next_index : options.length-(1+next_index);
3097 slider.value(index).update();
3098 props.index = index;
3099 onChangeCallbacks();
3100 var ni = (next_index+1)%options.length;
3101 setSliderPlayerMove(ni);
3102 }, next_time_step);
3103 };
3104
3105 var startSliderPlayer = function() {
3106 if (!options || options.length < 2) return;
3107 var final_index = options.length - 1;
3108 var index = slider.value();
3109 var step_time = props.step_time;
3110 slider_holder.classed("playing", true);
3111 slider_play_button.style("background-image", pause_string);
3112 if (step_time > 0 && index === final_index) {
3113 index = 0;
3114 slider.value(index).update();
3115 props.index = index;
3116 onChangeCallbacks();
3117 }
3118 else if (step_time < 0 && index === 0) {
3119 index = final_index;
3120 slider.value(index).update();
3121 props.index = index;
3122 onChangeCallbacks();
3123 }
3124 var effective_index = step_time>0 ? index : options.length-(1+index);
3125 setSliderPlayerMove(effective_index + 1);
3126 };
3127
3128 slider_play_button.on("click", function() {
3129 if (slider_holder.classed("playing")) stopSliderPlayer();
3130 else if (props.step_time) startSliderPlayer();
3131 });
3132
3133 var updateSlider = function() {
3134 var w = window.innerWidth,
3135 handle_radius = w < 520 ? 12 : 15;
3136
3137 slider.domain([0, options.length - 1])
3138 .label(props.value)
3139 .value(props.index)
3140 .labelSize(w < 520 ? 12 : 14)
3141 .handleRadius(handle_radius)
3142 .channelHeight(6)
3143 .snap(true)
3144 .margin({
3145 left: handle_radius + 5,
3146 right: handle_radius,
3147 top: w < 520 ? 34 : 30
3148 })
3149 .on("change", function(index) {
3150 if (index === props.index) return;
3151 props.index = index;
3152 onChangeCallbacks();
3153 })
3154 .update();
3155 };
3156
3157
3158 var buttons;
3159
3160 var updateButtons = function() {
3161 buttons = button_group.text("").selectAll(".btn")
3162 .data(options)
3163 .enter()
3164 .append("div")
3165 .attr("class", "btn")
3166 .classed("selected", function(d,i) { return i === current_index; } )
3167 .text(function(d) { return d; })
3168 .attr("title", function(d) { return d; })
3169 .on("click", function(d, i) {
3170 if (i === props.index) return;
3171 props.index = i;
3172 onChangeCallbacks();
3173 });
3174 };
3175
3176
3177 var changeVisibleControl = function(control) {
3178 visible_control = control;
3179 dropdown.style("display", visible_control==="dropdown" ? "inline-table" : "none");
3180 slider_holder.style("display", visible_control==="slider" ? "inline-block" : "none");
3181 button_nav.style("display", visible_control==="buttons" ? "inline-block" : "none");
3182 if (visible_control !== "dropdown") hideDropdownList();
3183 if (visible_control !== "slider") stopSliderPlayer();
3184 };
3185
3186 var updateControlOptions = function() {
3187 var opts = props.options;
3188 var num_options = opts.length;
3189 if (num_options < 2) return;
3190 if (options && opts.length===options.length && opts.every(function(op, i) { return op===options[i]; })) {
3191 // If here we have multiple options that haven't changes since last call.
3192 return false;
3193 }
3194 options = Object.freeze(opts.slice());
3195 if (props.index > num_options - 1) props.index = num_options - 1;
3196 return true;
3197 };
3198
3199 var updateControlWidth = function() {
3200 if (width === props.width) return;
3201 width = props.width;
3202 var width_px = width + "px";
3203 dropdown.style("width", width_px);
3204 slider_holder.style("width", width_px);
3205 button_nav.style("width", null); //See how this works with width: auto for now - Daan
3206 return true;
3207 };
3208
3209 var updateControlAnimation = function() {
3210 if (is_animatable === !!props.step_time) {
3211 if (is_animatable) slider_play_button.style("transform", props.step_time>0 ? null : "rotate(180deg)");
3212 return;
3213 }
3214 is_animatable = !is_animatable;
3215 if (!is_animatable) {
3216 stopSliderPlayer();
3217 slider_holder.classed("animatable", false);
3218 }
3219 else {
3220 slider_holder.classed("animatable", true);
3221 slider_play_button.style("transform", props.step_time>0 ? null : "rotate(180deg)");
3222 }
3223 return true;
3224 };
3225
3226 var updateControlVisibility = function() {
3227 if (props.control_type !== "default") {
3228 changeVisibleControl(props.control_type);
3229 return;
3230 }
3231 else { // When not in list we try and fit buttons then fallback to dropdown
3232 changeVisibleControl("buttons"); // Must make visible or buttons_fit always true!
3233 var buttons_fit = buttons.nodes().every(function(el) {
3234 return el.offsetWidth >= el.scrollWidth; // https://stackoverflow.com/a/36723850
3235 });
3236 if (!buttons_fit) changeVisibleControl("dropdown");
3237 }
3238 };
3239
3240 var updateCurrentValue = function() {
3241 if (current_index === props.index && current_value === props.value) return false;
3242 var num_options = options.length;
3243 if (props.index > num_options - 1) props.index = num_options - 1;
3244 current_index = props.index;
3245 current_value = props.value;
3246 return true;
3247 };
3248
3249 var updateSliderHandleColour = function() {
3250 slider_holder.select(".slider-handle").style("fill", props.handle_colour);
3251 };
3252
3253 var updateControls = function() {
3254 // Check available options
3255 var options_updated = updateControlOptions();
3256 if (options.length < 2) {
3257 // If we have fewer than two options then hide control and finish
3258 props.index = 0;
3259 changeVisibleControl("none");
3260 updateControlVisibility();
3261 return;
3262 }
3263 // Width must be set before creating slider first time around
3264 updateControlWidth();
3265 var value_updated = updateCurrentValue();
3266 if (options_updated) { // If options have changed we need to do a big rebuild
3267 updateDropdown();
3268 updateSlider();
3269 updateButtons();
3270 }
3271 else if (value_updated) { // If only values have changed then just change a few things
3272 dropdown_current.text(current_value).attr("title", current_value);
3273 buttons.each(function(d,i) { d3_select(this).classed("selected", i===current_index); });
3274 slider.label(current_value).value(current_index);
3275 }
3276 // The rest is style
3277 updateControlVisibility();
3278 updateControlAnimation();
3279 updateSliderHandleColour();
3280 // Call slider update one last time to reflect these changes
3281 slider.update();
3282 };
3283
3284 output_obj.showDropdownList = function() { showDropdownList(); return this; };
3285 output_obj.hideDropdownList = function() { hideDropdownList(); return this; };
3286 output_obj.toggleDropdownList = function() { toggleDropdownList(); return this; };
3287 output_obj.update = function() { updateControls(); return this; };
3288
3289 return output_obj;
3290
3291}
3292
3293exports.createControlsGroup = createControlsGroup;
3294
3295Object.defineProperty(exports, '__esModule', { value: true });
3296
3297})));