UNPKG

102 kBJavaScriptView Raw
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3 typeof define === 'function' && define.amd ? define(factory) :
4 (global.controls = factory());
5}(this, (function () { '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 css_string = ".controls-container,.controls-container *{box-sizing:border-box}.button-container .button,.dropdown .current{overflow:hidden;text-overflow:ellipsis;height:100%;white-space:nowrap}.button-container .button,.dropdown .current,.dropdown .list .list-item{white-space:nowrap}.slider,.slider-play{pointer-events:all;vertical-align:bottom}.button{display:inline-block;cursor:pointer}.button:hover{opacity:.5}.button.selected,.button.selected:hover{color:#fff;cursor:default;opacity:1;background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.button-container{pointer-events:all;width:auto;line-height:0;margin-bottom:20px}.button-container.button-group{display:table;border:1px solid #ccc;width:100%;table-layout:fixed;border-radius:3px}.button-container .button{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}.button-container.button-group .button{border:none;border-left:1px solid rgba(0,0,0,.5);border-radius:0;display:table-cell;text-align:center}.button-container.button-group .button:first-child{border-radius:3px 0 0 3px}.button-container.button-group .button:last-child{border-radius:0 3px 3px 0}.button-container .button:hover{background:#eee;opacity:.8}.button-container.button-group .button:first-child{border:none}.button-container .button.selected,.button-container .button.selected:hover{opacity:1;background:#ececec;color:#333}.dropdown{pointer-events:all;display:inline-table;color:#333;font-weight:400;font-size:16px;position:relative}.dropdown .heading{margin-bottom:.4em;font-weight:300}.dropdown .main{background:#fff;padding:0 60px 0 6px;cursor:pointer;position:relative;border:1px solid #ccc;border-radius:3px;height:30px;line-height:26px}.dropdown .list,.dropdown .symbol{position:absolute}.dropdown .current{width:100%;display:inline-block;font-size:14px}.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:1.4em;max-height:160px;overflow-y:scroll;color:#333;box-shadow:0 1px 2px rgba(0,0,0,.2)}.dropdown .list .list-item{font-size:14px;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:.66em;letter-spacing:1px;text-transform:uppercase;color:#888;opacity:1;cursor:default;font-weight:300;margin-top:.5em}.dropdown .list .list-item.header:first-child{margin-top:0}.controls-container .dropdown{margin:0 0 1.5em}.controls-container .dropdown .heading{color:#333}.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}";
890
891// https://stackoverflow.com/a/21626701
892function makeBackgroundString(svg_string) {
893 return "url('data:image/svg+xml;base64," + window.btoa(svg_string) + "')";
894}
895
896var css_injected = false;
897
898function injectCSS(css) {
899 if (css_injected || typeof document === 'undefined') return;
900 css = css;
901 var head = document.head || document.getElementsByTagName('head')[0];
902 var style = document.createElement('style');
903 style.type = 'text/css';
904 head.appendChild(style);
905
906 if (style.styleSheet){
907 style.styleSheet.cssText = css;
908 } else {
909 style.appendChild(document.createTextNode(css));
910 }
911 css_injected = true;
912 return;
913}
914
915var control_types = Object.freeze(["auto-buttons", "grouped-buttons", "floating-buttons", "dropdown", "slider", "none"]);
916
917function createCore(container_selector) {
918 var output_obj = {};
919
920 var props = {
921 "step_time": 2,
922 "loop_time": 1.5,
923 "slider_handle_colour": "#333",
924 "slider_play_button": true
925 };
926
927 Object.keys(props).forEach(function(key) {
928 // Convert from snake case properties to camel case methods
929 var methodName = key.replace(/_\w/g, function(substr) { return substr.charAt(1).toUpperCase(); });
930 output_obj[methodName] = function(val){
931 if (val === undefined) return props[key];
932 props[key] = val;
933 return output_obj;
934 };
935 } );
936
937 props.type = "auto_buttons";
938
939 output_obj.type = function(type) {
940 if (type === undefined) return props.type;
941 props.type = control_types.indexOf(type) !== -1 ? type : "auto-buttons";
942 return output_obj;
943 };
944
945 Object.defineProperty(props, "control", {
946 get: function() {
947 var type = props.type;
948 return (type === "dropdown" || type === "slider" || type === "none") ? props.type : "buttons";
949 },
950 set: function() { console.warn("Nothing changed: control is read only"); }
951 } );
952
953 Object.defineProperty(props, "buttons_type", {
954 get: function() {
955 if (props.control !== "buttons") return undefined;
956 if (props.type === "auto-buttons") return "auto";
957 if (props.type === "grouped-buttons") return "grouped";
958 return "floating";
959 },
960 set: function() { console.warn("Nothing changed: button_type is read only"); }
961 } );
962
963 props.index = 0;
964
965 output_obj.index = function(index) {
966 if (index === undefined) return props.index;
967 if (!Number.isFinite(index)) throw TypeError("index must be a number greater than or equal to 0.");
968 if (index < 0) throw RangeError("index must be greater than or equal to 0.");
969 props.index = Math.floor(index);
970 return output_obj;
971 };
972
973 props.options = [];
974
975 output_obj.options = function(opts) {
976 if (opts === undefined) return props.options.slice();
977 if (!Array.isArray(opts)) throw TypeError("opts must be an array.");
978 props.options = Object.freeze(opts.slice());
979 return output_obj
980 };
981
982 Object.defineProperty(props, "value", {
983 get: function() { return props.options[props.index]; },
984 set: function() { console.warn("Nothing changed: value is read only"); }
985 } );
986
987 output_obj.value = function(value){
988 if (value === undefined) return props.value;
989 var index = props.options.indexOf(value);
990 if(index !== -1) props.index = index;
991 else console.warn("Nothing changed: value not in options list");
992 return output_obj;
993 };
994
995 Object.defineProperty(props, "width", {
996 get: function() { return container_node.getBoundingClientRect().width + "px"; },
997 set: function() { console.warn("Nothing changed: width is read only"); }
998 } );
999
1000 props.changeHandlers = [];
1001
1002 output_obj.on = function(event$$1, callback){
1003 if(event$$1 === "change") props.changeHandlers.push(callback.bind(output_obj));
1004 return output_obj;
1005 };
1006
1007 var onChangeCallbacks = function() {
1008 var value = props.value;
1009 var index = props.index;
1010 props.changeHandlers.forEach(function(func) {
1011 func(value, index);
1012 });
1013 };
1014
1015 Object.seal(props);
1016
1017 // Grab container
1018 var container = d3_select(container_selector).classed("controls-container", true);
1019 var container_node = container.node();
1020 output_obj.container = container;
1021
1022 //var heading = container.append("div").attr("class", "heading");
1023
1024 return {
1025 output_obj: output_obj,
1026 props: props,
1027 onChangeCallbacks: onChangeCallbacks,
1028 container: container,
1029 container_node: container_node,
1030 container_selector: container_selector
1031 }
1032
1033}
1034
1035function createDropdownIcon(colour) {
1036 var start_string = '<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="';
1037 var end_string = '"> <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>';
1038 return makeBackgroundString(start_string + colour + end_string);
1039}
1040
1041
1042function createDropdown(core) {
1043 var container = core.container;
1044 var props = core.props;
1045 var onChangeCallbacks = core.onChangeCallbacks;
1046
1047 // Add dropdown elements to DOM
1048 var dropdown = container.append("div").attr("class", "dropdown");
1049 var dropdown_main = dropdown.append("div").attr("class", "main");
1050 var dropdown_current = dropdown_main.append("span").attr("class", "current");
1051 dropdown_main.append("span").attr("class", "symbol").style("background-image", createDropdownIcon("#333333"));
1052 var dropdown_list = dropdown.append("div").attr("class", "list");
1053
1054 var hideDropdownList = function(){
1055 dropdown.classed("open", false);
1056 };
1057
1058 var toggleDropdownList = function(){
1059 dropdown.classed("open", !dropdown.classed("open"));
1060 };
1061
1062 var dropdown_node = dropdown.node();
1063 document.querySelector("body").addEventListener('click', function(event$$1) {
1064 if (!dropdown.classed("open")) return; // If already closed, nothing to close
1065 var el = event$$1.target;
1066 var parent = el.parentElement;
1067 while ( parent ) {
1068 if (el === dropdown_node) return; // We've clicked the dropdown, don't close it here
1069 el = parent;
1070 parent = el.parentElement;
1071 }
1072 hideDropdownList(); //Clicked somewhere else, hide the dropdown
1073 }, false);
1074
1075 dropdown_main.on("click", function() { toggleDropdownList(); } );
1076
1077 var setStyles = function() {
1078
1079 };
1080
1081 var show = function() {
1082 setStyles();
1083 dropdown.style("width", props.width)
1084 .style("display", "inline-table");
1085 };
1086
1087 var hide = function() {
1088 hideDropdownList();
1089 dropdown.style("display", "none");
1090 };
1091
1092 var setValue = function() {
1093 dropdown_current.text(props.value).attr("title", props.value);
1094 };
1095
1096 var setOptions = function() {
1097 dropdown_list.text("")
1098 .selectAll(".list-item")
1099 .data(props.options)
1100 .enter()
1101 .append("div")
1102 .attr("class", "list-item")
1103 .text(function(d) { return d; })
1104 .on("click", function(d, i) {
1105 hideDropdownList();
1106 if (d3_select(this).classed("selected")) return;
1107 props.index = i;
1108 onChangeCallbacks();
1109 });
1110 };
1111
1112 var dropdown_obj = { handle: dropdown };
1113 dropdown_obj.show = function() { show(); return dropdown_obj; };
1114 dropdown_obj.hide = function() { hide(); return dropdown_obj; };
1115 dropdown_obj.setValue = function() { setValue(); return dropdown_obj; };
1116 dropdown_obj.setOptions = function() { setOptions(); return dropdown_obj; };
1117
1118 return dropdown_obj;
1119}
1120
1121function createButtons(core, dropdown_obj) {
1122 var container = core.container;
1123 var props = core.props;
1124 var onChangeCallbacks = core.onChangeCallbacks;
1125 var button_container = container.append("div").attr("class", "button-container");
1126 var buttons, button_nodes;
1127
1128 var setStyles = function() {
1129
1130 };
1131
1132 var show = function() {
1133 setStyles();
1134 if (props.buttons_type === "floating") {
1135 button_container.style("width", null)
1136 .style("display", "inline-block")
1137 .classed("button-group", false);
1138 }
1139 else {
1140 button_container.style("width", props.width)
1141 .style("display", "table")
1142 .classed("button-group", true);
1143 if (props.buttons_type === "auto") {
1144 var buttons_fit = button_nodes.every(function(el) {
1145 return el.offsetWidth >= el.scrollWidth; // https://stackoverflow.com/a/36723850
1146 });
1147 hide();
1148 dropdown_obj.show();
1149 }
1150 }
1151 };
1152
1153 var hide = function() {
1154 button_container.style("display", "none");
1155 };
1156
1157 var setValue = function() {
1158 buttons && buttons.each(function(d,i) { d3_select(this).classed("selected", i===props.index); });
1159 };
1160
1161 var setOptions = function() {
1162 buttons = button_container.text("").selectAll(".button")
1163 .data(props.options)
1164 .enter()
1165 .append("div")
1166 .attr("class", "button")
1167 .classed("selected", function(d,i) { return i === props.index; } )
1168 .text(function(d) { return d; })
1169 .attr("title", function(d) { return d; })
1170 .on("click", function(d, i) {
1171 if (i === props.index) return;
1172 props.index = i;
1173 onChangeCallbacks();
1174 });
1175 button_nodes = buttons.nodes();
1176 };
1177
1178 var buttons_obj = { handle: button_container };
1179 buttons_obj.show = function() { show(); return buttons_obj; };
1180 buttons_obj.hide = function() { hide(); return buttons_obj; };
1181 buttons_obj.setValue = function() { setValue(); return buttons_obj; };
1182 buttons_obj.setOptions = function() { setOptions(); return buttons_obj; };
1183
1184 return buttons_obj;
1185}
1186
1187var slice = Array.prototype.slice;
1188
1189var identity = function(x) {
1190 return x;
1191};
1192
1193var top = 1;
1194var right = 2;
1195var bottom = 3;
1196var left = 4;
1197var epsilon = 1e-6;
1198
1199function translateX(x) {
1200 return "translate(" + (x + 0.5) + ",0)";
1201}
1202
1203function translateY(y) {
1204 return "translate(0," + (y + 0.5) + ")";
1205}
1206
1207function number(scale) {
1208 return function(d) {
1209 return +scale(d);
1210 };
1211}
1212
1213function center(scale) {
1214 var offset = Math.max(0, scale.bandwidth() - 1) / 2; // Adjust for 0.5px offset.
1215 if (scale.round()) offset = Math.round(offset);
1216 return function(d) {
1217 return +scale(d) + offset;
1218 };
1219}
1220
1221function entering() {
1222 return !this.__axis;
1223}
1224
1225function axis(orient, scale) {
1226 var tickArguments = [],
1227 tickValues = null,
1228 tickFormat = null,
1229 tickSizeInner = 6,
1230 tickSizeOuter = 6,
1231 tickPadding = 3,
1232 k = orient === top || orient === left ? -1 : 1,
1233 x = orient === left || orient === right ? "x" : "y",
1234 transform = orient === top || orient === bottom ? translateX : translateY;
1235
1236 function axis(context) {
1237 var values = tickValues == null ? (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain()) : tickValues,
1238 format = tickFormat == null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : identity) : tickFormat,
1239 spacing = Math.max(tickSizeInner, 0) + tickPadding,
1240 range = scale.range(),
1241 range0 = +range[0] + 0.5,
1242 range1 = +range[range.length - 1] + 0.5,
1243 position = (scale.bandwidth ? center : number)(scale.copy()),
1244 selection = context.selection ? context.selection() : context,
1245 path = selection.selectAll(".domain").data([null]),
1246 tick = selection.selectAll(".tick").data(values, scale).order(),
1247 tickExit = tick.exit(),
1248 tickEnter = tick.enter().append("g").attr("class", "tick"),
1249 line = tick.select("line"),
1250 text = tick.select("text");
1251
1252 path = path.merge(path.enter().insert("path", ".tick")
1253 .attr("class", "domain")
1254 .attr("stroke", "#000"));
1255
1256 tick = tick.merge(tickEnter);
1257
1258 line = line.merge(tickEnter.append("line")
1259 .attr("stroke", "#000")
1260 .attr(x + "2", k * tickSizeInner));
1261
1262 text = text.merge(tickEnter.append("text")
1263 .attr("fill", "#000")
1264 .attr(x, k * spacing)
1265 .attr("dy", orient === top ? "0em" : orient === bottom ? "0.71em" : "0.32em"));
1266
1267 if (context !== selection) {
1268 path = path.transition(context);
1269 tick = tick.transition(context);
1270 line = line.transition(context);
1271 text = text.transition(context);
1272
1273 tickExit = tickExit.transition(context)
1274 .attr("opacity", epsilon)
1275 .attr("transform", function(d) { return isFinite(d = position(d)) ? transform(d) : this.getAttribute("transform"); });
1276
1277 tickEnter
1278 .attr("opacity", epsilon)
1279 .attr("transform", function(d) { var p = this.parentNode.__axis; return transform(p && isFinite(p = p(d)) ? p : position(d)); });
1280 }
1281
1282 tickExit.remove();
1283
1284 path
1285 .attr("d", orient === left || orient == right
1286 ? "M" + k * tickSizeOuter + "," + range0 + "H0.5V" + range1 + "H" + k * tickSizeOuter
1287 : "M" + range0 + "," + k * tickSizeOuter + "V0.5H" + range1 + "V" + k * tickSizeOuter);
1288
1289 tick
1290 .attr("opacity", 1)
1291 .attr("transform", function(d) { return transform(position(d)); });
1292
1293 line
1294 .attr(x + "2", k * tickSizeInner);
1295
1296 text
1297 .attr(x, k * spacing)
1298 .text(format);
1299
1300 selection.filter(entering)
1301 .attr("fill", "none")
1302 .attr("font-size", 10)
1303 .attr("font-family", "sans-serif")
1304 .attr("text-anchor", orient === right ? "start" : orient === left ? "end" : "middle");
1305
1306 selection
1307 .each(function() { this.__axis = position; });
1308 }
1309
1310 axis.scale = function(_) {
1311 return arguments.length ? (scale = _, axis) : scale;
1312 };
1313
1314 axis.ticks = function() {
1315 return tickArguments = slice.call(arguments), axis;
1316 };
1317
1318 axis.tickArguments = function(_) {
1319 return arguments.length ? (tickArguments = _ == null ? [] : slice.call(_), axis) : tickArguments.slice();
1320 };
1321
1322 axis.tickValues = function(_) {
1323 return arguments.length ? (tickValues = _ == null ? null : slice.call(_), axis) : tickValues && tickValues.slice();
1324 };
1325
1326 axis.tickFormat = function(_) {
1327 return arguments.length ? (tickFormat = _, axis) : tickFormat;
1328 };
1329
1330 axis.tickSize = function(_) {
1331 return arguments.length ? (tickSizeInner = tickSizeOuter = +_, axis) : tickSizeInner;
1332 };
1333
1334 axis.tickSizeInner = function(_) {
1335 return arguments.length ? (tickSizeInner = +_, axis) : tickSizeInner;
1336 };
1337
1338 axis.tickSizeOuter = function(_) {
1339 return arguments.length ? (tickSizeOuter = +_, axis) : tickSizeOuter;
1340 };
1341
1342 axis.tickPadding = function(_) {
1343 return arguments.length ? (tickPadding = +_, axis) : tickPadding;
1344 };
1345
1346 return axis;
1347}
1348
1349
1350
1351
1352
1353function axisBottom(scale) {
1354 return axis(bottom, scale);
1355}
1356
1357var ascending$1 = function(a, b) {
1358 return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
1359};
1360
1361var bisector = function(compare) {
1362 if (compare.length === 1) compare = ascendingComparator(compare);
1363 return {
1364 left: function(a, x, lo, hi) {
1365 if (lo == null) lo = 0;
1366 if (hi == null) hi = a.length;
1367 while (lo < hi) {
1368 var mid = lo + hi >>> 1;
1369 if (compare(a[mid], x) < 0) lo = mid + 1;
1370 else hi = mid;
1371 }
1372 return lo;
1373 },
1374 right: function(a, x, lo, hi) {
1375 if (lo == null) lo = 0;
1376 if (hi == null) hi = a.length;
1377 while (lo < hi) {
1378 var mid = lo + hi >>> 1;
1379 if (compare(a[mid], x) > 0) hi = mid;
1380 else lo = mid + 1;
1381 }
1382 return lo;
1383 }
1384 };
1385};
1386
1387function ascendingComparator(f) {
1388 return function(d, x) {
1389 return ascending$1(f(d), x);
1390 };
1391}
1392
1393var ascendingBisect = bisector(ascending$1);
1394var bisectRight = ascendingBisect.right;
1395
1396function pair(a, b) {
1397 return [a, b];
1398}
1399
1400var number$1 = function(x) {
1401 return x === null ? NaN : +x;
1402};
1403
1404var extent = function(values, valueof) {
1405 var n = values.length,
1406 i = -1,
1407 value,
1408 min,
1409 max;
1410
1411 if (valueof == null) {
1412 while (++i < n) { // Find the first comparable value.
1413 if ((value = values[i]) != null && value >= value) {
1414 min = max = value;
1415 while (++i < n) { // Compare the remaining values.
1416 if ((value = values[i]) != null) {
1417 if (min > value) min = value;
1418 if (max < value) max = value;
1419 }
1420 }
1421 }
1422 }
1423 }
1424
1425 else {
1426 while (++i < n) { // Find the first comparable value.
1427 if ((value = valueof(values[i], i, values)) != null && value >= value) {
1428 min = max = value;
1429 while (++i < n) { // Compare the remaining values.
1430 if ((value = valueof(values[i], i, values)) != null) {
1431 if (min > value) min = value;
1432 if (max < value) max = value;
1433 }
1434 }
1435 }
1436 }
1437 }
1438
1439 return [min, max];
1440};
1441
1442var identity$1 = function(x) {
1443 return x;
1444};
1445
1446var range = function(start, stop, step) {
1447 start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
1448
1449 var i = -1,
1450 n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
1451 range = new Array(n);
1452
1453 while (++i < n) {
1454 range[i] = start + i * step;
1455 }
1456
1457 return range;
1458};
1459
1460var e10 = Math.sqrt(50);
1461var e5 = Math.sqrt(10);
1462var e2 = Math.sqrt(2);
1463
1464var ticks = function(start, stop, count) {
1465 var reverse,
1466 i = -1,
1467 n,
1468 ticks,
1469 step;
1470
1471 stop = +stop, start = +start, count = +count;
1472 if (start === stop && count > 0) return [start];
1473 if (reverse = stop < start) n = start, start = stop, stop = n;
1474 if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return [];
1475
1476 if (step > 0) {
1477 start = Math.ceil(start / step);
1478 stop = Math.floor(stop / step);
1479 ticks = new Array(n = Math.ceil(stop - start + 1));
1480 while (++i < n) ticks[i] = (start + i) * step;
1481 } else {
1482 start = Math.floor(start * step);
1483 stop = Math.ceil(stop * step);
1484 ticks = new Array(n = Math.ceil(start - stop + 1));
1485 while (++i < n) ticks[i] = (start - i) / step;
1486 }
1487
1488 if (reverse) ticks.reverse();
1489
1490 return ticks;
1491};
1492
1493function tickIncrement(start, stop, count) {
1494 var step = (stop - start) / Math.max(0, count),
1495 power = Math.floor(Math.log(step) / Math.LN10),
1496 error = step / Math.pow(10, power);
1497 return power >= 0
1498 ? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power)
1499 : -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1);
1500}
1501
1502function tickStep(start, stop, count) {
1503 var step0 = Math.abs(stop - start) / Math.max(0, count),
1504 step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
1505 error = step0 / step1;
1506 if (error >= e10) step1 *= 10;
1507 else if (error >= e5) step1 *= 5;
1508 else if (error >= e2) step1 *= 2;
1509 return stop < start ? -step1 : step1;
1510}
1511
1512var sturges = function(values) {
1513 return Math.ceil(Math.log(values.length) / Math.LN2) + 1;
1514};
1515
1516var quantile = function(values, p, valueof) {
1517 if (valueof == null) valueof = number$1;
1518 if (!(n = values.length)) return;
1519 if ((p = +p) <= 0 || n < 2) return +valueof(values[0], 0, values);
1520 if (p >= 1) return +valueof(values[n - 1], n - 1, values);
1521 var n,
1522 i = (n - 1) * p,
1523 i0 = Math.floor(i),
1524 value0 = +valueof(values[i0], i0, values),
1525 value1 = +valueof(values[i0 + 1], i0 + 1, values);
1526 return value0 + (value1 - value0) * (i - i0);
1527};
1528
1529var min = function(values, valueof) {
1530 var n = values.length,
1531 i = -1,
1532 value,
1533 min;
1534
1535 if (valueof == null) {
1536 while (++i < n) { // Find the first comparable value.
1537 if ((value = values[i]) != null && value >= value) {
1538 min = value;
1539 while (++i < n) { // Compare the remaining values.
1540 if ((value = values[i]) != null && min > value) {
1541 min = value;
1542 }
1543 }
1544 }
1545 }
1546 }
1547
1548 else {
1549 while (++i < n) { // Find the first comparable value.
1550 if ((value = valueof(values[i], i, values)) != null && value >= value) {
1551 min = value;
1552 while (++i < n) { // Compare the remaining values.
1553 if ((value = valueof(values[i], i, values)) != null && min > value) {
1554 min = value;
1555 }
1556 }
1557 }
1558 }
1559 }
1560
1561 return min;
1562};
1563
1564function length(d) {
1565 return d.length;
1566}
1567
1568var define = function(constructor, factory, prototype) {
1569 constructor.prototype = factory.prototype = prototype;
1570 prototype.constructor = constructor;
1571};
1572
1573function extend(parent, definition) {
1574 var prototype = Object.create(parent.prototype);
1575 for (var key in definition) prototype[key] = definition[key];
1576 return prototype;
1577}
1578
1579function Color() {}
1580
1581var darker = 0.7;
1582var brighter = 1 / darker;
1583
1584var reI = "\\s*([+-]?\\d+)\\s*";
1585var reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*";
1586var reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*";
1587var reHex3 = /^#([0-9a-f]{3})$/;
1588var reHex6 = /^#([0-9a-f]{6})$/;
1589var reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$");
1590var reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$");
1591var reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$");
1592var reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$");
1593var reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$");
1594var reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
1595
1596var named = {
1597 aliceblue: 0xf0f8ff,
1598 antiquewhite: 0xfaebd7,
1599 aqua: 0x00ffff,
1600 aquamarine: 0x7fffd4,
1601 azure: 0xf0ffff,
1602 beige: 0xf5f5dc,
1603 bisque: 0xffe4c4,
1604 black: 0x000000,
1605 blanchedalmond: 0xffebcd,
1606 blue: 0x0000ff,
1607 blueviolet: 0x8a2be2,
1608 brown: 0xa52a2a,
1609 burlywood: 0xdeb887,
1610 cadetblue: 0x5f9ea0,
1611 chartreuse: 0x7fff00,
1612 chocolate: 0xd2691e,
1613 coral: 0xff7f50,
1614 cornflowerblue: 0x6495ed,
1615 cornsilk: 0xfff8dc,
1616 crimson: 0xdc143c,
1617 cyan: 0x00ffff,
1618 darkblue: 0x00008b,
1619 darkcyan: 0x008b8b,
1620 darkgoldenrod: 0xb8860b,
1621 darkgray: 0xa9a9a9,
1622 darkgreen: 0x006400,
1623 darkgrey: 0xa9a9a9,
1624 darkkhaki: 0xbdb76b,
1625 darkmagenta: 0x8b008b,
1626 darkolivegreen: 0x556b2f,
1627 darkorange: 0xff8c00,
1628 darkorchid: 0x9932cc,
1629 darkred: 0x8b0000,
1630 darksalmon: 0xe9967a,
1631 darkseagreen: 0x8fbc8f,
1632 darkslateblue: 0x483d8b,
1633 darkslategray: 0x2f4f4f,
1634 darkslategrey: 0x2f4f4f,
1635 darkturquoise: 0x00ced1,
1636 darkviolet: 0x9400d3,
1637 deeppink: 0xff1493,
1638 deepskyblue: 0x00bfff,
1639 dimgray: 0x696969,
1640 dimgrey: 0x696969,
1641 dodgerblue: 0x1e90ff,
1642 firebrick: 0xb22222,
1643 floralwhite: 0xfffaf0,
1644 forestgreen: 0x228b22,
1645 fuchsia: 0xff00ff,
1646 gainsboro: 0xdcdcdc,
1647 ghostwhite: 0xf8f8ff,
1648 gold: 0xffd700,
1649 goldenrod: 0xdaa520,
1650 gray: 0x808080,
1651 green: 0x008000,
1652 greenyellow: 0xadff2f,
1653 grey: 0x808080,
1654 honeydew: 0xf0fff0,
1655 hotpink: 0xff69b4,
1656 indianred: 0xcd5c5c,
1657 indigo: 0x4b0082,
1658 ivory: 0xfffff0,
1659 khaki: 0xf0e68c,
1660 lavender: 0xe6e6fa,
1661 lavenderblush: 0xfff0f5,
1662 lawngreen: 0x7cfc00,
1663 lemonchiffon: 0xfffacd,
1664 lightblue: 0xadd8e6,
1665 lightcoral: 0xf08080,
1666 lightcyan: 0xe0ffff,
1667 lightgoldenrodyellow: 0xfafad2,
1668 lightgray: 0xd3d3d3,
1669 lightgreen: 0x90ee90,
1670 lightgrey: 0xd3d3d3,
1671 lightpink: 0xffb6c1,
1672 lightsalmon: 0xffa07a,
1673 lightseagreen: 0x20b2aa,
1674 lightskyblue: 0x87cefa,
1675 lightslategray: 0x778899,
1676 lightslategrey: 0x778899,
1677 lightsteelblue: 0xb0c4de,
1678 lightyellow: 0xffffe0,
1679 lime: 0x00ff00,
1680 limegreen: 0x32cd32,
1681 linen: 0xfaf0e6,
1682 magenta: 0xff00ff,
1683 maroon: 0x800000,
1684 mediumaquamarine: 0x66cdaa,
1685 mediumblue: 0x0000cd,
1686 mediumorchid: 0xba55d3,
1687 mediumpurple: 0x9370db,
1688 mediumseagreen: 0x3cb371,
1689 mediumslateblue: 0x7b68ee,
1690 mediumspringgreen: 0x00fa9a,
1691 mediumturquoise: 0x48d1cc,
1692 mediumvioletred: 0xc71585,
1693 midnightblue: 0x191970,
1694 mintcream: 0xf5fffa,
1695 mistyrose: 0xffe4e1,
1696 moccasin: 0xffe4b5,
1697 navajowhite: 0xffdead,
1698 navy: 0x000080,
1699 oldlace: 0xfdf5e6,
1700 olive: 0x808000,
1701 olivedrab: 0x6b8e23,
1702 orange: 0xffa500,
1703 orangered: 0xff4500,
1704 orchid: 0xda70d6,
1705 palegoldenrod: 0xeee8aa,
1706 palegreen: 0x98fb98,
1707 paleturquoise: 0xafeeee,
1708 palevioletred: 0xdb7093,
1709 papayawhip: 0xffefd5,
1710 peachpuff: 0xffdab9,
1711 peru: 0xcd853f,
1712 pink: 0xffc0cb,
1713 plum: 0xdda0dd,
1714 powderblue: 0xb0e0e6,
1715 purple: 0x800080,
1716 rebeccapurple: 0x663399,
1717 red: 0xff0000,
1718 rosybrown: 0xbc8f8f,
1719 royalblue: 0x4169e1,
1720 saddlebrown: 0x8b4513,
1721 salmon: 0xfa8072,
1722 sandybrown: 0xf4a460,
1723 seagreen: 0x2e8b57,
1724 seashell: 0xfff5ee,
1725 sienna: 0xa0522d,
1726 silver: 0xc0c0c0,
1727 skyblue: 0x87ceeb,
1728 slateblue: 0x6a5acd,
1729 slategray: 0x708090,
1730 slategrey: 0x708090,
1731 snow: 0xfffafa,
1732 springgreen: 0x00ff7f,
1733 steelblue: 0x4682b4,
1734 tan: 0xd2b48c,
1735 teal: 0x008080,
1736 thistle: 0xd8bfd8,
1737 tomato: 0xff6347,
1738 turquoise: 0x40e0d0,
1739 violet: 0xee82ee,
1740 wheat: 0xf5deb3,
1741 white: 0xffffff,
1742 whitesmoke: 0xf5f5f5,
1743 yellow: 0xffff00,
1744 yellowgreen: 0x9acd32
1745};
1746
1747define(Color, color, {
1748 displayable: function() {
1749 return this.rgb().displayable();
1750 },
1751 toString: function() {
1752 return this.rgb() + "";
1753 }
1754});
1755
1756function color(format) {
1757 var m;
1758 format = (format + "").trim().toLowerCase();
1759 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
1760 : (m = reHex6.exec(format)) ? rgbn(parseInt(m[1], 16)) // #ff0000
1761 : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
1762 : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
1763 : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
1764 : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
1765 : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
1766 : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
1767 : named.hasOwnProperty(format) ? rgbn(named[format])
1768 : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0)
1769 : null;
1770}
1771
1772function rgbn(n) {
1773 return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
1774}
1775
1776function rgba(r, g, b, a) {
1777 if (a <= 0) r = g = b = NaN;
1778 return new Rgb(r, g, b, a);
1779}
1780
1781function rgbConvert(o) {
1782 if (!(o instanceof Color)) o = color(o);
1783 if (!o) return new Rgb;
1784 o = o.rgb();
1785 return new Rgb(o.r, o.g, o.b, o.opacity);
1786}
1787
1788function rgb(r, g, b, opacity) {
1789 return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
1790}
1791
1792function Rgb(r, g, b, opacity) {
1793 this.r = +r;
1794 this.g = +g;
1795 this.b = +b;
1796 this.opacity = +opacity;
1797}
1798
1799define(Rgb, rgb, extend(Color, {
1800 brighter: function(k) {
1801 k = k == null ? brighter : Math.pow(brighter, k);
1802 return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
1803 },
1804 darker: function(k) {
1805 k = k == null ? darker : Math.pow(darker, k);
1806 return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
1807 },
1808 rgb: function() {
1809 return this;
1810 },
1811 displayable: function() {
1812 return (0 <= this.r && this.r <= 255)
1813 && (0 <= this.g && this.g <= 255)
1814 && (0 <= this.b && this.b <= 255)
1815 && (0 <= this.opacity && this.opacity <= 1);
1816 },
1817 toString: function() {
1818 var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
1819 return (a === 1 ? "rgb(" : "rgba(")
1820 + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", "
1821 + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", "
1822 + Math.max(0, Math.min(255, Math.round(this.b) || 0))
1823 + (a === 1 ? ")" : ", " + a + ")");
1824 }
1825}));
1826
1827function hsla(h, s, l, a) {
1828 if (a <= 0) h = s = l = NaN;
1829 else if (l <= 0 || l >= 1) h = s = NaN;
1830 else if (s <= 0) h = NaN;
1831 return new Hsl(h, s, l, a);
1832}
1833
1834function hslConvert(o) {
1835 if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
1836 if (!(o instanceof Color)) o = color(o);
1837 if (!o) return new Hsl;
1838 if (o instanceof Hsl) return o;
1839 o = o.rgb();
1840 var r = o.r / 255,
1841 g = o.g / 255,
1842 b = o.b / 255,
1843 min = Math.min(r, g, b),
1844 max = Math.max(r, g, b),
1845 h = NaN,
1846 s = max - min,
1847 l = (max + min) / 2;
1848 if (s) {
1849 if (r === max) h = (g - b) / s + (g < b) * 6;
1850 else if (g === max) h = (b - r) / s + 2;
1851 else h = (r - g) / s + 4;
1852 s /= l < 0.5 ? max + min : 2 - max - min;
1853 h *= 60;
1854 } else {
1855 s = l > 0 && l < 1 ? 0 : h;
1856 }
1857 return new Hsl(h, s, l, o.opacity);
1858}
1859
1860function hsl(h, s, l, opacity) {
1861 return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
1862}
1863
1864function Hsl(h, s, l, opacity) {
1865 this.h = +h;
1866 this.s = +s;
1867 this.l = +l;
1868 this.opacity = +opacity;
1869}
1870
1871define(Hsl, hsl, extend(Color, {
1872 brighter: function(k) {
1873 k = k == null ? brighter : Math.pow(brighter, k);
1874 return new Hsl(this.h, this.s, this.l * k, this.opacity);
1875 },
1876 darker: function(k) {
1877 k = k == null ? darker : Math.pow(darker, k);
1878 return new Hsl(this.h, this.s, this.l * k, this.opacity);
1879 },
1880 rgb: function() {
1881 var h = this.h % 360 + (this.h < 0) * 360,
1882 s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
1883 l = this.l,
1884 m2 = l + (l < 0.5 ? l : 1 - l) * s,
1885 m1 = 2 * l - m2;
1886 return new Rgb(
1887 hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2),
1888 hsl2rgb(h, m1, m2),
1889 hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2),
1890 this.opacity
1891 );
1892 },
1893 displayable: function() {
1894 return (0 <= this.s && this.s <= 1 || isNaN(this.s))
1895 && (0 <= this.l && this.l <= 1)
1896 && (0 <= this.opacity && this.opacity <= 1);
1897 }
1898}));
1899
1900/* From FvD 13.37, CSS Color Module Level 3 */
1901function hsl2rgb(h, m1, m2) {
1902 return (h < 60 ? m1 + (m2 - m1) * h / 60
1903 : h < 180 ? m2
1904 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60
1905 : m1) * 255;
1906}
1907
1908var deg2rad = Math.PI / 180;
1909var rad2deg = 180 / Math.PI;
1910
1911var Kn = 18;
1912var Xn = 0.950470;
1913var Yn = 1;
1914var Zn = 1.088830;
1915var t0 = 4 / 29;
1916var t1 = 6 / 29;
1917var t2 = 3 * t1 * t1;
1918var t3 = t1 * t1 * t1;
1919
1920function labConvert(o) {
1921 if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity);
1922 if (o instanceof Hcl) {
1923 var h = o.h * deg2rad;
1924 return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity);
1925 }
1926 if (!(o instanceof Rgb)) o = rgbConvert(o);
1927 var b = rgb2xyz(o.r),
1928 a = rgb2xyz(o.g),
1929 l = rgb2xyz(o.b),
1930 x = xyz2lab((0.4124564 * b + 0.3575761 * a + 0.1804375 * l) / Xn),
1931 y = xyz2lab((0.2126729 * b + 0.7151522 * a + 0.0721750 * l) / Yn),
1932 z = xyz2lab((0.0193339 * b + 0.1191920 * a + 0.9503041 * l) / Zn);
1933 return new Lab(116 * y - 16, 500 * (x - y), 200 * (y - z), o.opacity);
1934}
1935
1936function lab(l, a, b, opacity) {
1937 return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity);
1938}
1939
1940function Lab(l, a, b, opacity) {
1941 this.l = +l;
1942 this.a = +a;
1943 this.b = +b;
1944 this.opacity = +opacity;
1945}
1946
1947define(Lab, lab, extend(Color, {
1948 brighter: function(k) {
1949 return new Lab(this.l + Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
1950 },
1951 darker: function(k) {
1952 return new Lab(this.l - Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
1953 },
1954 rgb: function() {
1955 var y = (this.l + 16) / 116,
1956 x = isNaN(this.a) ? y : y + this.a / 500,
1957 z = isNaN(this.b) ? y : y - this.b / 200;
1958 y = Yn * lab2xyz(y);
1959 x = Xn * lab2xyz(x);
1960 z = Zn * lab2xyz(z);
1961 return new Rgb(
1962 xyz2rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z), // D65 -> sRGB
1963 xyz2rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z),
1964 xyz2rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z),
1965 this.opacity
1966 );
1967 }
1968}));
1969
1970function xyz2lab(t) {
1971 return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
1972}
1973
1974function lab2xyz(t) {
1975 return t > t1 ? t * t * t : t2 * (t - t0);
1976}
1977
1978function xyz2rgb(x) {
1979 return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
1980}
1981
1982function rgb2xyz(x) {
1983 return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
1984}
1985
1986function hclConvert(o) {
1987 if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity);
1988 if (!(o instanceof Lab)) o = labConvert(o);
1989 var h = Math.atan2(o.b, o.a) * rad2deg;
1990 return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity);
1991}
1992
1993function hcl(h, c, l, opacity) {
1994 return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity);
1995}
1996
1997function Hcl(h, c, l, opacity) {
1998 this.h = +h;
1999 this.c = +c;
2000 this.l = +l;
2001 this.opacity = +opacity;
2002}
2003
2004define(Hcl, hcl, extend(Color, {
2005 brighter: function(k) {
2006 return new Hcl(this.h, this.c, this.l + Kn * (k == null ? 1 : k), this.opacity);
2007 },
2008 darker: function(k) {
2009 return new Hcl(this.h, this.c, this.l - Kn * (k == null ? 1 : k), this.opacity);
2010 },
2011 rgb: function() {
2012 return labConvert(this).rgb();
2013 }
2014}));
2015
2016var A = -0.14861;
2017var B = +1.78277;
2018var C = -0.29227;
2019var D = -0.90649;
2020var E = +1.97294;
2021var ED = E * D;
2022var EB = E * B;
2023var BC_DA = B * C - D * A;
2024
2025function cubehelixConvert(o) {
2026 if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity);
2027 if (!(o instanceof Rgb)) o = rgbConvert(o);
2028 var r = o.r / 255,
2029 g = o.g / 255,
2030 b = o.b / 255,
2031 l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB),
2032 bl = b - l,
2033 k = (E * (g - l) - C * bl) / D,
2034 s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), // NaN if l=0 or l=1
2035 h = s ? Math.atan2(k, bl) * rad2deg - 120 : NaN;
2036 return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity);
2037}
2038
2039function cubehelix(h, s, l, opacity) {
2040 return arguments.length === 1 ? cubehelixConvert(h) : new Cubehelix(h, s, l, opacity == null ? 1 : opacity);
2041}
2042
2043function Cubehelix(h, s, l, opacity) {
2044 this.h = +h;
2045 this.s = +s;
2046 this.l = +l;
2047 this.opacity = +opacity;
2048}
2049
2050define(Cubehelix, cubehelix, extend(Color, {
2051 brighter: function(k) {
2052 k = k == null ? brighter : Math.pow(brighter, k);
2053 return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
2054 },
2055 darker: function(k) {
2056 k = k == null ? darker : Math.pow(darker, k);
2057 return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
2058 },
2059 rgb: function() {
2060 var h = isNaN(this.h) ? 0 : (this.h + 120) * deg2rad,
2061 l = +this.l,
2062 a = isNaN(this.s) ? 0 : this.s * l * (1 - l),
2063 cosh = Math.cos(h),
2064 sinh = Math.sin(h);
2065 return new Rgb(
2066 255 * (l + a * (A * cosh + B * sinh)),
2067 255 * (l + a * (C * cosh + D * sinh)),
2068 255 * (l + a * (E * cosh)),
2069 this.opacity
2070 );
2071 }
2072}));
2073
2074function basis(t1, v0, v1, v2, v3) {
2075 var t2 = t1 * t1, t3 = t2 * t1;
2076 return ((1 - 3 * t1 + 3 * t2 - t3) * v0
2077 + (4 - 6 * t2 + 3 * t3) * v1
2078 + (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2
2079 + t3 * v3) / 6;
2080}
2081
2082var constant$2 = function(x) {
2083 return function() {
2084 return x;
2085 };
2086};
2087
2088function linear$1(a, d) {
2089 return function(t) {
2090 return a + t * d;
2091 };
2092}
2093
2094function exponential(a, b, y) {
2095 return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {
2096 return Math.pow(a + t * b, y);
2097 };
2098}
2099
2100function hue(a, b) {
2101 var d = b - a;
2102 return d ? linear$1(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant$2(isNaN(a) ? b : a);
2103}
2104
2105function gamma(y) {
2106 return (y = +y) === 1 ? nogamma : function(a, b) {
2107 return b - a ? exponential(a, b, y) : constant$2(isNaN(a) ? b : a);
2108 };
2109}
2110
2111function nogamma(a, b) {
2112 var d = b - a;
2113 return d ? linear$1(a, d) : constant$2(isNaN(a) ? b : a);
2114}
2115
2116var rgb$1 = ((function rgbGamma(y) {
2117 var color$$1 = gamma(y);
2118
2119 function rgb$$1(start, end) {
2120 var r = color$$1((start = rgb(start)).r, (end = rgb(end)).r),
2121 g = color$$1(start.g, end.g),
2122 b = color$$1(start.b, end.b),
2123 opacity = nogamma(start.opacity, end.opacity);
2124 return function(t) {
2125 start.r = r(t);
2126 start.g = g(t);
2127 start.b = b(t);
2128 start.opacity = opacity(t);
2129 return start + "";
2130 };
2131 }
2132
2133 rgb$$1.gamma = rgbGamma;
2134
2135 return rgb$$1;
2136}))(1);
2137
2138var array$1 = function(a, b) {
2139 var nb = b ? b.length : 0,
2140 na = a ? Math.min(nb, a.length) : 0,
2141 x = new Array(nb),
2142 c = new Array(nb),
2143 i;
2144
2145 for (i = 0; i < na; ++i) x[i] = interpolateValue(a[i], b[i]);
2146 for (; i < nb; ++i) c[i] = b[i];
2147
2148 return function(t) {
2149 for (i = 0; i < na; ++i) c[i] = x[i](t);
2150 return c;
2151 };
2152};
2153
2154var date = function(a, b) {
2155 var d = new Date;
2156 return a = +a, b -= a, function(t) {
2157 return d.setTime(a + b * t), d;
2158 };
2159};
2160
2161var number$2 = function(a, b) {
2162 return a = +a, b -= a, function(t) {
2163 return a + b * t;
2164 };
2165};
2166
2167var object = function(a, b) {
2168 var i = {},
2169 c = {},
2170 k;
2171
2172 if (a === null || typeof a !== "object") a = {};
2173 if (b === null || typeof b !== "object") b = {};
2174
2175 for (k in b) {
2176 if (k in a) {
2177 i[k] = interpolateValue(a[k], b[k]);
2178 } else {
2179 c[k] = b[k];
2180 }
2181 }
2182
2183 return function(t) {
2184 for (k in i) c[k] = i[k](t);
2185 return c;
2186 };
2187};
2188
2189var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
2190var reB = new RegExp(reA.source, "g");
2191
2192function zero(b) {
2193 return function() {
2194 return b;
2195 };
2196}
2197
2198function one(b) {
2199 return function(t) {
2200 return b(t) + "";
2201 };
2202}
2203
2204var string = function(a, b) {
2205 var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b
2206 am, // current match in a
2207 bm, // current match in b
2208 bs, // string preceding current number in b, if any
2209 i = -1, // index in s
2210 s = [], // string constants and placeholders
2211 q = []; // number interpolators
2212
2213 // Coerce inputs to strings.
2214 a = a + "", b = b + "";
2215
2216 // Interpolate pairs of numbers in a & b.
2217 while ((am = reA.exec(a))
2218 && (bm = reB.exec(b))) {
2219 if ((bs = bm.index) > bi) { // a string precedes the next number in b
2220 bs = b.slice(bi, bs);
2221 if (s[i]) s[i] += bs; // coalesce with previous string
2222 else s[++i] = bs;
2223 }
2224 if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match
2225 if (s[i]) s[i] += bm; // coalesce with previous string
2226 else s[++i] = bm;
2227 } else { // interpolate non-matching numbers
2228 s[++i] = null;
2229 q.push({i: i, x: number$2(am, bm)});
2230 }
2231 bi = reB.lastIndex;
2232 }
2233
2234 // Add remains of b.
2235 if (bi < b.length) {
2236 bs = b.slice(bi);
2237 if (s[i]) s[i] += bs; // coalesce with previous string
2238 else s[++i] = bs;
2239 }
2240
2241 // Special optimization for only a single match.
2242 // Otherwise, interpolate each of the numbers and rejoin the string.
2243 return s.length < 2 ? (q[0]
2244 ? one(q[0].x)
2245 : zero(b))
2246 : (b = q.length, function(t) {
2247 for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
2248 return s.join("");
2249 });
2250};
2251
2252var interpolateValue = function(a, b) {
2253 var t = typeof b, c;
2254 return b == null || t === "boolean" ? constant$2(b)
2255 : (t === "number" ? number$2
2256 : t === "string" ? ((c = color(b)) ? (b = c, rgb$1) : string)
2257 : b instanceof color ? rgb$1
2258 : b instanceof Date ? date
2259 : Array.isArray(b) ? array$1
2260 : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object
2261 : number$2)(a, b);
2262};
2263
2264var interpolateRound = function(a, b) {
2265 return a = +a, b -= a, function(t) {
2266 return Math.round(a + b * t);
2267 };
2268};
2269
2270// p0 = [ux0, uy0, w0]
2271// p1 = [ux1, uy1, w1]
2272
2273function cubehelix$1(hue$$1) {
2274 return (function cubehelixGamma(y) {
2275 y = +y;
2276
2277 function cubehelix$$1(start, end) {
2278 var h = hue$$1((start = cubehelix(start)).h, (end = cubehelix(end)).h),
2279 s = nogamma(start.s, end.s),
2280 l = nogamma(start.l, end.l),
2281 opacity = nogamma(start.opacity, end.opacity);
2282 return function(t) {
2283 start.h = h(t);
2284 start.s = s(t);
2285 start.l = l(Math.pow(t, y));
2286 start.opacity = opacity(t);
2287 return start + "";
2288 };
2289 }
2290
2291 cubehelix$$1.gamma = cubehelixGamma;
2292
2293 return cubehelix$$1;
2294 })(1);
2295}
2296
2297cubehelix$1(hue);
2298var cubehelixLong = cubehelix$1(nogamma);
2299
2300var array$2 = Array.prototype;
2301
2302var map$1 = array$2.map;
2303var slice$2 = array$2.slice;
2304
2305var constant$3 = function(x) {
2306 return function() {
2307 return x;
2308 };
2309};
2310
2311var number$3 = function(x) {
2312 return +x;
2313};
2314
2315var unit = [0, 1];
2316
2317function deinterpolateLinear(a, b) {
2318 return (b -= (a = +a))
2319 ? function(x) { return (x - a) / b; }
2320 : constant$3(b);
2321}
2322
2323function deinterpolateClamp(deinterpolate) {
2324 return function(a, b) {
2325 var d = deinterpolate(a = +a, b = +b);
2326 return function(x) { return x <= a ? 0 : x >= b ? 1 : d(x); };
2327 };
2328}
2329
2330function reinterpolateClamp(reinterpolate) {
2331 return function(a, b) {
2332 var r = reinterpolate(a = +a, b = +b);
2333 return function(t) { return t <= 0 ? a : t >= 1 ? b : r(t); };
2334 };
2335}
2336
2337function bimap(domain, range$$1, deinterpolate, reinterpolate) {
2338 var d0 = domain[0], d1 = domain[1], r0 = range$$1[0], r1 = range$$1[1];
2339 if (d1 < d0) d0 = deinterpolate(d1, d0), r0 = reinterpolate(r1, r0);
2340 else d0 = deinterpolate(d0, d1), r0 = reinterpolate(r0, r1);
2341 return function(x) { return r0(d0(x)); };
2342}
2343
2344function polymap(domain, range$$1, deinterpolate, reinterpolate) {
2345 var j = Math.min(domain.length, range$$1.length) - 1,
2346 d = new Array(j),
2347 r = new Array(j),
2348 i = -1;
2349
2350 // Reverse descending domains.
2351 if (domain[j] < domain[0]) {
2352 domain = domain.slice().reverse();
2353 range$$1 = range$$1.slice().reverse();
2354 }
2355
2356 while (++i < j) {
2357 d[i] = deinterpolate(domain[i], domain[i + 1]);
2358 r[i] = reinterpolate(range$$1[i], range$$1[i + 1]);
2359 }
2360
2361 return function(x) {
2362 var i = bisectRight(domain, x, 1, j) - 1;
2363 return r[i](d[i](x));
2364 };
2365}
2366
2367function copy(source, target) {
2368 return target
2369 .domain(source.domain())
2370 .range(source.range())
2371 .interpolate(source.interpolate())
2372 .clamp(source.clamp());
2373}
2374
2375// deinterpolate(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
2376// reinterpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding domain value x in [a,b].
2377function continuous(deinterpolate, reinterpolate) {
2378 var domain = unit,
2379 range$$1 = unit,
2380 interpolate$$1 = interpolateValue,
2381 clamp = false,
2382 piecewise,
2383 output,
2384 input;
2385
2386 function rescale() {
2387 piecewise = Math.min(domain.length, range$$1.length) > 2 ? polymap : bimap;
2388 output = input = null;
2389 return scale;
2390 }
2391
2392 function scale(x) {
2393 return (output || (output = piecewise(domain, range$$1, clamp ? deinterpolateClamp(deinterpolate) : deinterpolate, interpolate$$1)))(+x);
2394 }
2395
2396 scale.invert = function(y) {
2397 return (input || (input = piecewise(range$$1, domain, deinterpolateLinear, clamp ? reinterpolateClamp(reinterpolate) : reinterpolate)))(+y);
2398 };
2399
2400 scale.domain = function(_) {
2401 return arguments.length ? (domain = map$1.call(_, number$3), rescale()) : domain.slice();
2402 };
2403
2404 scale.range = function(_) {
2405 return arguments.length ? (range$$1 = slice$2.call(_), rescale()) : range$$1.slice();
2406 };
2407
2408 scale.rangeRound = function(_) {
2409 return range$$1 = slice$2.call(_), interpolate$$1 = interpolateRound, rescale();
2410 };
2411
2412 scale.clamp = function(_) {
2413 return arguments.length ? (clamp = !!_, rescale()) : clamp;
2414 };
2415
2416 scale.interpolate = function(_) {
2417 return arguments.length ? (interpolate$$1 = _, rescale()) : interpolate$$1;
2418 };
2419
2420 return rescale();
2421}
2422
2423// Computes the decimal coefficient and exponent of the specified number x with
2424// significant digits p, where x is positive and p is in [1, 21] or undefined.
2425// For example, formatDecimal(1.23) returns ["123", 0].
2426var formatDecimal = function(x, p) {
2427 if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
2428 var i, coefficient = x.slice(0, i);
2429
2430 // The string returned by toExponential either has the form \d\.\d+e[-+]\d+
2431 // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
2432 return [
2433 coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
2434 +x.slice(i + 1)
2435 ];
2436};
2437
2438var exponent = function(x) {
2439 return x = formatDecimal(Math.abs(x)), x ? x[1] : NaN;
2440};
2441
2442var formatGroup = function(grouping, thousands) {
2443 return function(value, width) {
2444 var i = value.length,
2445 t = [],
2446 j = 0,
2447 g = grouping[0],
2448 length = 0;
2449
2450 while (i > 0 && g > 0) {
2451 if (length + g + 1 > width) g = Math.max(1, width - length);
2452 t.push(value.substring(i -= g, i + g));
2453 if ((length += g + 1) > width) break;
2454 g = grouping[j = (j + 1) % grouping.length];
2455 }
2456
2457 return t.reverse().join(thousands);
2458 };
2459};
2460
2461var formatNumerals = function(numerals) {
2462 return function(value) {
2463 return value.replace(/[0-9]/g, function(i) {
2464 return numerals[+i];
2465 });
2466 };
2467};
2468
2469var formatDefault = function(x, p) {
2470 x = x.toPrecision(p);
2471
2472 out: for (var n = x.length, i = 1, i0 = -1, i1; i < n; ++i) {
2473 switch (x[i]) {
2474 case ".": i0 = i1 = i; break;
2475 case "0": if (i0 === 0) i0 = i; i1 = i; break;
2476 case "e": break out;
2477 default: if (i0 > 0) i0 = 0; break;
2478 }
2479 }
2480
2481 return i0 > 0 ? x.slice(0, i0) + x.slice(i1 + 1) : x;
2482};
2483
2484var prefixExponent;
2485
2486var formatPrefixAuto = function(x, p) {
2487 var d = formatDecimal(x, p);
2488 if (!d) return x + "";
2489 var coefficient = d[0],
2490 exponent = d[1],
2491 i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
2492 n = coefficient.length;
2493 return i === n ? coefficient
2494 : i > n ? coefficient + new Array(i - n + 1).join("0")
2495 : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i)
2496 : "0." + new Array(1 - i).join("0") + formatDecimal(x, Math.max(0, p + i - 1))[0]; // less than 1y!
2497};
2498
2499var formatRounded = function(x, p) {
2500 var d = formatDecimal(x, p);
2501 if (!d) return x + "";
2502 var coefficient = d[0],
2503 exponent = d[1];
2504 return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient
2505 : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1)
2506 : coefficient + new Array(exponent - coefficient.length + 2).join("0");
2507};
2508
2509var formatTypes = {
2510 "": formatDefault,
2511 "%": function(x, p) { return (x * 100).toFixed(p); },
2512 "b": function(x) { return Math.round(x).toString(2); },
2513 "c": function(x) { return x + ""; },
2514 "d": function(x) { return Math.round(x).toString(10); },
2515 "e": function(x, p) { return x.toExponential(p); },
2516 "f": function(x, p) { return x.toFixed(p); },
2517 "g": function(x, p) { return x.toPrecision(p); },
2518 "o": function(x) { return Math.round(x).toString(8); },
2519 "p": function(x, p) { return formatRounded(x * 100, p); },
2520 "r": formatRounded,
2521 "s": formatPrefixAuto,
2522 "X": function(x) { return Math.round(x).toString(16).toUpperCase(); },
2523 "x": function(x) { return Math.round(x).toString(16); }
2524};
2525
2526// [[fill]align][sign][symbol][0][width][,][.precision][type]
2527var re = /^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;
2528
2529function formatSpecifier(specifier) {
2530 return new FormatSpecifier(specifier);
2531}
2532
2533formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof
2534
2535function FormatSpecifier(specifier) {
2536 if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
2537
2538 var match,
2539 fill = match[1] || " ",
2540 align = match[2] || ">",
2541 sign = match[3] || "-",
2542 symbol = match[4] || "",
2543 zero = !!match[5],
2544 width = match[6] && +match[6],
2545 comma = !!match[7],
2546 precision = match[8] && +match[8].slice(1),
2547 type = match[9] || "";
2548
2549 // The "n" type is an alias for ",g".
2550 if (type === "n") comma = true, type = "g";
2551
2552 // Map invalid types to the default format.
2553 else if (!formatTypes[type]) type = "";
2554
2555 // If zero fill is specified, padding goes after sign and before digits.
2556 if (zero || (fill === "0" && align === "=")) zero = true, fill = "0", align = "=";
2557
2558 this.fill = fill;
2559 this.align = align;
2560 this.sign = sign;
2561 this.symbol = symbol;
2562 this.zero = zero;
2563 this.width = width;
2564 this.comma = comma;
2565 this.precision = precision;
2566 this.type = type;
2567}
2568
2569FormatSpecifier.prototype.toString = function() {
2570 return this.fill
2571 + this.align
2572 + this.sign
2573 + this.symbol
2574 + (this.zero ? "0" : "")
2575 + (this.width == null ? "" : Math.max(1, this.width | 0))
2576 + (this.comma ? "," : "")
2577 + (this.precision == null ? "" : "." + Math.max(0, this.precision | 0))
2578 + this.type;
2579};
2580
2581var identity$3 = function(x) {
2582 return x;
2583};
2584
2585var prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];
2586
2587var formatLocale = function(locale) {
2588 var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity$3,
2589 currency = locale.currency,
2590 decimal = locale.decimal,
2591 numerals = locale.numerals ? formatNumerals(locale.numerals) : identity$3,
2592 percent = locale.percent || "%";
2593
2594 function newFormat(specifier) {
2595 specifier = formatSpecifier(specifier);
2596
2597 var fill = specifier.fill,
2598 align = specifier.align,
2599 sign = specifier.sign,
2600 symbol = specifier.symbol,
2601 zero = specifier.zero,
2602 width = specifier.width,
2603 comma = specifier.comma,
2604 precision = specifier.precision,
2605 type = specifier.type;
2606
2607 // Compute the prefix and suffix.
2608 // For SI-prefix, the suffix is lazily computed.
2609 var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
2610 suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? percent : "";
2611
2612 // What format function should we use?
2613 // Is this an integer type?
2614 // Can this type generate exponential notation?
2615 var formatType = formatTypes[type],
2616 maybeSuffix = !type || /[defgprs%]/.test(type);
2617
2618 // Set the default precision if not specified,
2619 // or clamp the specified precision to the supported range.
2620 // For significant precision, it must be in [1, 21].
2621 // For fixed precision, it must be in [0, 20].
2622 precision = precision == null ? (type ? 6 : 12)
2623 : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))
2624 : Math.max(0, Math.min(20, precision));
2625
2626 function format(value) {
2627 var valuePrefix = prefix,
2628 valueSuffix = suffix,
2629 i, n, c;
2630
2631 if (type === "c") {
2632 valueSuffix = formatType(value) + valueSuffix;
2633 value = "";
2634 } else {
2635 value = +value;
2636
2637 // Perform the initial formatting.
2638 var valueNegative = value < 0;
2639 value = formatType(Math.abs(value), precision);
2640
2641 // If a negative value rounds to zero during formatting, treat as positive.
2642 if (valueNegative && +value === 0) valueNegative = false;
2643
2644 // Compute the prefix and suffix.
2645 valuePrefix = (valueNegative ? (sign === "(" ? sign : "-") : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
2646 valueSuffix = valueSuffix + (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + (valueNegative && sign === "(" ? ")" : "");
2647
2648 // Break the formatted value into the integer “value” part that can be
2649 // grouped, and fractional or exponential “suffix” part that is not.
2650 if (maybeSuffix) {
2651 i = -1, n = value.length;
2652 while (++i < n) {
2653 if (c = value.charCodeAt(i), 48 > c || c > 57) {
2654 valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
2655 value = value.slice(0, i);
2656 break;
2657 }
2658 }
2659 }
2660 }
2661
2662 // If the fill character is not "0", grouping is applied before padding.
2663 if (comma && !zero) value = group(value, Infinity);
2664
2665 // Compute the padding.
2666 var length = valuePrefix.length + value.length + valueSuffix.length,
2667 padding = length < width ? new Array(width - length + 1).join(fill) : "";
2668
2669 // If the fill character is "0", grouping is applied after padding.
2670 if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
2671
2672 // Reconstruct the final output based on the desired alignment.
2673 switch (align) {
2674 case "<": value = valuePrefix + value + valueSuffix + padding; break;
2675 case "=": value = valuePrefix + padding + value + valueSuffix; break;
2676 case "^": value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length); break;
2677 default: value = padding + valuePrefix + value + valueSuffix; break;
2678 }
2679
2680 return numerals(value);
2681 }
2682
2683 format.toString = function() {
2684 return specifier + "";
2685 };
2686
2687 return format;
2688 }
2689
2690 function formatPrefix(specifier, value) {
2691 var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
2692 e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
2693 k = Math.pow(10, -e),
2694 prefix = prefixes[8 + e / 3];
2695 return function(value) {
2696 return f(k * value) + prefix;
2697 };
2698 }
2699
2700 return {
2701 format: newFormat,
2702 formatPrefix: formatPrefix
2703 };
2704};
2705
2706var locale;
2707var format;
2708var formatPrefix;
2709
2710defaultLocale({
2711 decimal: ".",
2712 thousands: ",",
2713 grouping: [3],
2714 currency: ["$", ""]
2715});
2716
2717function defaultLocale(definition) {
2718 locale = formatLocale(definition);
2719 format = locale.format;
2720 formatPrefix = locale.formatPrefix;
2721 return locale;
2722}
2723
2724var precisionFixed = function(step) {
2725 return Math.max(0, -exponent(Math.abs(step)));
2726};
2727
2728var precisionPrefix = function(step, value) {
2729 return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step)));
2730};
2731
2732var precisionRound = function(step, max) {
2733 step = Math.abs(step), max = Math.abs(max) - step;
2734 return Math.max(0, exponent(max) - exponent(step)) + 1;
2735};
2736
2737var tickFormat = function(domain, count, specifier) {
2738 var start = domain[0],
2739 stop = domain[domain.length - 1],
2740 step = tickStep(start, stop, count == null ? 10 : count),
2741 precision;
2742 specifier = formatSpecifier(specifier == null ? ",f" : specifier);
2743 switch (specifier.type) {
2744 case "s": {
2745 var value = Math.max(Math.abs(start), Math.abs(stop));
2746 if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;
2747 return formatPrefix(specifier, value);
2748 }
2749 case "":
2750 case "e":
2751 case "g":
2752 case "p":
2753 case "r": {
2754 if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
2755 break;
2756 }
2757 case "f":
2758 case "%": {
2759 if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
2760 break;
2761 }
2762 }
2763 return format(specifier);
2764};
2765
2766function linearish(scale) {
2767 var domain = scale.domain;
2768
2769 scale.ticks = function(count) {
2770 var d = domain();
2771 return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
2772 };
2773
2774 scale.tickFormat = function(count, specifier) {
2775 return tickFormat(domain(), count, specifier);
2776 };
2777
2778 scale.nice = function(count) {
2779 if (count == null) count = 10;
2780
2781 var d = domain(),
2782 i0 = 0,
2783 i1 = d.length - 1,
2784 start = d[i0],
2785 stop = d[i1],
2786 step;
2787
2788 if (stop < start) {
2789 step = start, start = stop, stop = step;
2790 step = i0, i0 = i1, i1 = step;
2791 }
2792
2793 step = tickIncrement(start, stop, count);
2794
2795 if (step > 0) {
2796 start = Math.floor(start / step) * step;
2797 stop = Math.ceil(stop / step) * step;
2798 step = tickIncrement(start, stop, count);
2799 } else if (step < 0) {
2800 start = Math.ceil(start * step) / step;
2801 stop = Math.floor(stop * step) / step;
2802 step = tickIncrement(start, stop, count);
2803 }
2804
2805 if (step > 0) {
2806 d[i0] = Math.floor(start / step) * step;
2807 d[i1] = Math.ceil(stop / step) * step;
2808 domain(d);
2809 } else if (step < 0) {
2810 d[i0] = Math.ceil(start * step) / step;
2811 d[i1] = Math.floor(stop * step) / step;
2812 domain(d);
2813 }
2814
2815 return scale;
2816 };
2817
2818 return scale;
2819}
2820
2821function linear() {
2822 var scale = continuous(deinterpolateLinear, number$2);
2823
2824 scale.copy = function() {
2825 return copy(scale, linear());
2826 };
2827
2828 return linearish(scale);
2829}
2830
2831// We’re importing from an individual file rather than the top level of the d3-scale
2832// module to work around a tree-shaking issue that otherwise causes a lot of irrelevant
2833// d3-scale code to be pulled into the “full” build. See issues:
2834//
2835// https://github.com/rollup/rollup/issues/305
2836// https://github.com/rollup/rollup/issues/1208
2837//
2838// There are some associated shenanigans in rollup.config.js to accommodate this.
2839//
2840// If and when rollup manages to avoid this problem, we can revert back to the
2841// straightforward approach.
2842var VERSION = "1.3.1";
2843
2844function Slider(selector$$1) {
2845 this.container = d3_select(selector$$1);
2846
2847 this._width = null;
2848 this._height = null;
2849
2850 this._handleRadius = 15;
2851 this._channelHeight = 5;
2852 this._channelRadius = null;
2853
2854 this._handleFill = "black";
2855 this._channelFill = "#eee";
2856
2857 this._margin = { top: null, left: null, right: null };
2858
2859 this._domain = [0,1];
2860 this._value = null;
2861 this._snap = false;
2862
2863 this._scale = null;
2864 this._axis = false;
2865 this._ticks = null;
2866 this._tickFormat = null;
2867 this._tickSize = null;
2868
2869 this._label = null;
2870 this._labelSize = 18;
2871
2872 this._startLabel = null;
2873 this._startLabelBelow = false;
2874
2875 this._endLabel = null;
2876 this._endLabelBelow = false;
2877
2878 this._startEndLabelSize = 16;
2879
2880 this.handlers = { "change": [] };
2881}
2882
2883// Create accessor methods for all the _parameters defined by the constructor
2884function accessor(k) {
2885 if (k.length > 0 && k.charAt(0) == "_") {
2886 Slider.prototype[k.substr(1)] = function(v) {
2887 if (typeof v == "undefined") return this[k];
2888 this[k] = v;
2889 return this;
2890 };
2891 }
2892}
2893var s = new Slider();
2894for (var k in s) {
2895 accessor(k);
2896}
2897
2898// Special accessor function for margin
2899Slider.prototype.margin = function Slider_margin(options) {
2900 if (!options) return this._margin;
2901 for (k in options) {
2902 if (k in this._margin) this._margin[k] = options[k];
2903 else throw "Slider.margin: unrecognised option " + k;
2904 }
2905 return this;
2906};
2907
2908// Attach event handlers
2909Slider.prototype.on = function Slider_on(event$$1, handler) {
2910 if (!(event$$1 in this.handlers)) throw "Slider.on: No such event: " + event$$1;
2911 this.handlers[event$$1].push(handler);
2912 return this;
2913};
2914
2915// Fire event
2916Slider.prototype.fire = function Slider_fire(event$$1, d) {
2917 if (!(event$$1 in this.handlers)) throw "Slider.fire: No such event: " + event$$1;
2918 var handlers = this.handlers[event$$1];
2919 for (var i = 0; i < handlers.length; i++) {
2920 handlers[i].call(this, d);
2921 }
2922 return this;
2923};
2924
2925// Binary search
2926function closestValue(sorted_list, value, a, b) {
2927 if (typeof a === "undefined") a = 0;
2928 if (typeof b === "undefined") b = sorted_list.length;
2929
2930 if (b-a == 0) return value;
2931 if (b-a == 1) return sorted_list[a];
2932 if (b-a == 2) {
2933 var d1 = Math.abs(sorted_list[a] - value),
2934 d2 = Math.abs(sorted_list[a+1] - value);
2935 if (d1 <= d2) return sorted_list[a];
2936 else return sorted_list[a+1];
2937 }
2938
2939 var mid = a + Math.floor((b-a) / 2),
2940 mid_v = sorted_list[mid];
2941 pre = mid - 1,
2942 pre_v = sorted_list[pre];
2943 if (pre_v <= value && value <= mid_v) {
2944 return (Math.abs(pre_v - value) <= Math.abs(mid_v - value)) ? pre_v : mid_v;
2945 }
2946 if (mid_v <= value) return closestValue(sorted_list, value, mid, b);
2947 else return closestValue(sorted_list, value, a, mid);
2948}
2949
2950function snapTo(specification, value) {
2951 if (typeof specification == "boolean") {
2952 return specification ? Math.round(value) : value;
2953 }
2954 // Otherwise assume “specification” is a sorted array
2955 return closestValue(specification, value);
2956}
2957
2958// Draw or update the slider
2959Slider.prototype.draw = function Slider_draw() {
2960 var that = this;
2961
2962 var cw = this._width,
2963 ch = this._height;
2964
2965 var container_node = this.container.node();
2966
2967 // If the width and height have not been specified, use
2968 // the client size of the container element.
2969 if (!cw) {
2970 var r = container_node.getBoundingClientRect();
2971 // If there isn’t a bounding client rect, e.g. because
2972 // the container is display: none;, then do nothing.
2973 if (!r || r.width == 0) return this;
2974
2975 cw = r.width;
2976 ch = r.height;
2977 }
2978
2979 var channel_r = this._channelRadius == null ? this._channelHeight/2 : this._channelRadius,
2980 left_margin = (this._margin.left == null ? Math.max(this._handleRadius, channel_r) : this._margin.left),
2981 right_margin = (this._margin.right == null ? Math.max(this._handleRadius, channel_r) : this._margin.right),
2982 top_margin = this._margin.top == null ? Math.max(this._handleRadius, this._channelHeight/2) : this._margin.top,
2983 w = cw - left_margin - right_margin, // Inner width of the slider channel (excluding endcaps)
2984 channel_w = w + 2*channel_r, // Width of the slider channel (including endcaps)
2985 label_h = this._labelSize * 1.5;
2986
2987 if (this._label != null && this._margin.top == null) top_margin += label_h;
2988
2989 var slider;
2990 if (container_node.namespaceURI == "http://www.w3.org/2000/svg") {
2991 slider = this.container;
2992 }
2993 else {
2994 slider = this.container.selectAll("svg").data([{ width: cw, height: ch }]);
2995 slider.exit().remove();
2996 slider = slider.enter().append("svg").merge(slider);
2997 slider.attr("width", function(d) { return d.width; })
2998 .attr("height", function(d) { return d.height; });
2999 }
3000
3001 var g = slider.selectAll("g.slider-container").data([{left: left_margin, top: top_margin, id: this._id}]);
3002 g.exit().remove();
3003 g = g.enter().append("g").attr("class", "slider-container").merge(g);
3004 g.attr("transform", function(d) {
3005 return "translate(" + d.left + "," + d.top + ")";
3006 })
3007 .attr("id", function(d) { return d.id; });
3008
3009 this.scale = (this._scale ? this._scale() : linear()).domain(this._domain).range([0, w]);
3010
3011 if (this._value == null || this._value < this._domain[0]) this._value = this._domain[0];
3012 else if (this._value > this._domain[1]) this._value = this._domain[1];
3013
3014 if (this._snap) this._value = snapTo(this._snap, this._value);
3015
3016 var axes_data = [];
3017 if (this._axis) {
3018 var axis;
3019 if (typeof this._axis != "boolean") {
3020 axis = this._axis(this.scale);
3021 }
3022 else {
3023 axis = axisBottom().scale(this.scale).tickPadding(6);
3024 }
3025
3026 if (this._ticks) axis.ticks(this._ticks);
3027 if (this._tickFormat) axis.tickFormat(this._tickFormat);
3028 if (this._tickSize) axis.tickSize(this._tickSize);
3029 else axis.tickSize(Math.max(5, this._handleRadius - this._channelHeight - 2));
3030 axes_data.push(axis);
3031 }
3032
3033 var axes = g.selectAll(".slider-axis");
3034 var axes_enter = axes.data(axes_data).enter();
3035 axes_enter.append("g").attr("class", "slider-axis")
3036 .attr("transform", "translate(" + 0 + "," + this._channelHeight/2 + ")")
3037 .each(function(axis) { axis(d3_select(this)); });
3038 axes_enter.select(".domain").attr("fill", "none");
3039 axes_enter.selectAll(".tick line").attr("stroke", "black");
3040 axes_enter.exit().remove();
3041
3042 var channel, handle;
3043 channel = g.selectAll(".slider-channel")
3044 .data([{ width: channel_w, height: this._channelHeight, channel_r: channel_r }]);
3045 channel.exit().remove();
3046
3047 channel = channel.enter().append("rect").attr("class", "slider-channel")
3048 .attr("fill", this._channelFill)
3049 .attr("cursor", "pointer")
3050 .on("click", function() {
3051 var slider_x = Math.max(0, Math.min(w, d3_mouse(this)[0]));
3052 that._value = that.scale.invert(slider_x);
3053 if (that._snap) that._value = snapTo(that._snap, that._value);
3054 handle.attr("cx", that.scale(that._value));
3055 that.fire("change", that._value);
3056 })
3057 .merge(channel);
3058
3059 channel.attr("width", function(d) { return d.width; })
3060 .attr("height", function(d) { return d.height; })
3061 .attr("y", function(d) { return -d.height/2; })
3062 .attr("x", function(d){ return -d.channel_r; })
3063 .attr("rx", function(d) { return d.channel_r; });
3064
3065 var drag_dx_origin, drag_x_origin;
3066 function handleMousedown(event$$1) {
3067 document.addEventListener("mouseup", handleMouseup, false);
3068 document.addEventListener("mousemove", handleMousemove, false);
3069 drag_dx_origin = event$$1.clientX;
3070 drag_x_origin = that.scale(that._value);
3071 }
3072
3073 function handleMouseup() {
3074 document.removeEventListener("mouseup", handleMouseup, false);
3075 document.removeEventListener("mousemove", handleMousemove, false);
3076 }
3077
3078 function handleMousemove(event$$1) {
3079 drag(event$$1.clientX - drag_dx_origin);
3080 }
3081
3082 function handleTouchstart(event$$1) {
3083 if (event$$1.touches.length != 1) return;
3084 document.addEventListener("touchend", handleTouchend, false);
3085 document.addEventListener("touchmove", handleTouchmove, false);
3086 drag_dx_origin = event$$1.touches[0].clientX;
3087 drag_x_origin = that.scale(that._value);
3088 }
3089
3090 function handleTouchend() {
3091 document.removeEventListener("touchend", handleTouchend, false);
3092 document.removeEventListener("touchmove", handleTouchmove, false);
3093 }
3094
3095 function handleTouchmove(event$$1) {
3096 if (event$$1.touches.length != 1) return;
3097 drag(event$$1.touches[0].clientX - drag_dx_origin);
3098 }
3099
3100 function drag(dx) {
3101 var new_x = drag_x_origin + dx;
3102 var slider_x = Math.max(0, Math.min(w, new_x));
3103 var new_value = that.scale.invert(slider_x);
3104 if (that._snap) new_value = snapTo(that._snap, new_value);
3105 handle.attr("cx", that.scale(new_value));
3106 if (new_value != that._value) {
3107 that._value = new_value;
3108 that.fire("change", that._value);
3109 }
3110 }
3111
3112 handle = g.selectAll(".slider-handle").data([{ v: this._value, x: this.scale(this._value) }]);
3113 handle = handle.enter().append("circle").attr("class", "slider-handle")
3114 .attr("cursor", "col-resize")
3115 .merge(handle);
3116
3117 handle.attr("cx", function(d) { return d.x; })
3118 .attr("r", this._handleRadius)
3119 .attr("fill", this._handleFill)
3120 .on("mousedown", function() {
3121 event.preventDefault();
3122 handleMousedown(event);
3123 })
3124 .on("touchstart", function() {
3125 event.preventDefault();
3126 handleTouchstart(event);
3127 });
3128
3129 var label_data = [];
3130 if (this._label) {
3131 label_data.push({
3132 label: this._label, x: w/2, y: -label_h, font_size: this._labelSize
3133 });
3134 }
3135 var label = g.selectAll(".slider-label").data(label_data);
3136 label.exit().remove();
3137 label = label.enter()
3138 .append("text").attr("class", "slider-label")
3139 .attr("text-anchor", "middle")
3140 .attr("cursor", "default")
3141 .merge(label);
3142
3143 label
3144 .text(function(d) { return d.label; })
3145 .attr("x", function(d) { return d.x; })
3146 .attr("y", function(d) { return d.y; })
3147 .attr("font-size", this._labelSize);
3148
3149 var end_label_data = [];
3150 if (this._startLabel) {
3151 end_label_data.push({
3152 label: this._startLabel,
3153 x: this._startLabelBelow ? 0 : -(channel_r + 5 + Math.max(0, this._handleRadius - channel_r)),
3154 y: this._startLabelBelow ? (channel_r + 15) : this._startEndLabelSize/1.75 - channel_r/2,
3155 anchor: this._startLabelBelow ? "middle" : "end",
3156 font_size: this._startEndLabelSize
3157 });
3158 }
3159 if (this._endLabel) {
3160 end_label_data.push({
3161 label: this._endLabel,
3162 x: this._endLabelBelow ? w : w + (channel_r + Math.max(0, this._handleRadius - channel_r) + 5),
3163 y: this._startLabelBelow ? (channel_r + 15) : this._startEndLabelSize/1.75 - channel_r/2,
3164 anchor: this._endLabelBelow ? "middle" : "start",
3165 font_size: this._startEndLabelSize
3166 });
3167 }
3168
3169 var end_labels = g.selectAll(".slider-end-labels").data(end_label_data);
3170 end_labels.exit().remove();
3171 end_labels = end_labels.enter().append("text").attr("class", "slider-end-labels")
3172 .attr("pointer-events", "none")
3173 .merge(end_labels);
3174 end_labels
3175 .text(function(d) { return d.label; })
3176 .attr("font-size", function(d) { return d.font_size; })
3177 .attr("x", function(d) { return d.x; })
3178 .attr("y", function(d) { return d.y; })
3179 .attr("text-anchor", function(d) { return d.anchor; });
3180
3181 return this;
3182};
3183
3184Slider.prototype.update = Slider.prototype.draw;
3185
3186function Flourish_slider(selector$$1) {
3187 return new Slider(selector$$1);
3188}
3189Flourish_slider.version = VERSION;
3190
3191function createPlayButton(colour) {
3192 var start_string = '<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="';
3193 var end_string = '" stroke="none" points="25 15 0 30 0 0"></polygon> </svg>';
3194 return makeBackgroundString(start_string + colour + end_string);
3195}
3196
3197function createPauseButton(colour) {
3198 var start_string = '<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 stroke="none" stroke-width="1" fill="';
3199 var end_string = '"><rect x="2" y="2" width="9" height="26"></rect> <rect x="15" y="2" width="9" height="26"></rect> </g> </svg>';
3200 return makeBackgroundString(start_string + colour + end_string);
3201}
3202
3203
3204function createSlider(core) {
3205 var container = core.container;
3206 var props = core.props;
3207 var onChangeCallbacks = core.onChangeCallbacks;
3208 var container_selector = core.container_selector;
3209
3210 var play_string, pause_string;
3211
3212 var slider_holder = container.append("div").attr("class", "slider-holder animatable");
3213 var slider_play_button = slider_holder.append("div").attr("class", "slider-play");
3214 slider_holder.append("div").attr("class","slider");
3215
3216 var slider = Flourish_slider(container_selector + " .slider-holder .slider")
3217 .channelHeight(6)
3218 .snap(true)
3219 .on("change", function(index) {
3220 if (index === props.index) return;
3221 props.index = index;
3222 onChangeCallbacks();
3223 });
3224
3225 var sliderplayer;
3226
3227 var stopSliderPlayer = function() {
3228 if (!sliderplayer) return;
3229 clearInterval(sliderplayer);
3230 sliderplayer = undefined;
3231 slider_holder.classed("playing", false);
3232 slider_play_button.style("background-image", play_string);
3233 };
3234
3235 var setSliderPlayerMove = function(next_index) {
3236 if (next_index === 0 && !props.loop_time) {
3237 stopSliderPlayer();
3238 return;
3239 }
3240
3241 var next_time_step = 1000 * Math.abs(props.step_time) * (next_index ? 1 : props.loop_time);
3242
3243 sliderplayer = setTimeout(function() {
3244 var n_options = props.options.length;
3245 var index = props.step_time>0 ? next_index : n_options-(1+next_index);
3246 slider.value(index).update();
3247 props.index = index;
3248 onChangeCallbacks();
3249 var ni = (next_index+1)%n_options;
3250 setSliderPlayerMove(ni);
3251 }, next_time_step);
3252 };
3253
3254 var startSliderPlayer = function() {
3255 var n_options = props.options.length;
3256 if (n_options < 2) return;
3257 var final_index = n_options - 1;
3258 var index = slider.value();
3259 var step_time = props.step_time;
3260 slider_holder.classed("playing", true);
3261 slider_play_button.style("background-image", pause_string);
3262 if (step_time > 0 && index === final_index) {
3263 index = 0;
3264 slider.value(index).update();
3265 props.index = index;
3266 onChangeCallbacks();
3267 }
3268 else if (step_time < 0 && index === 0) {
3269 index = final_index;
3270 slider.value(index).update();
3271 props.index = index;
3272 onChangeCallbacks();
3273 }
3274 var effective_index = step_time>0 ? index : n_options-(1+index);
3275 setSliderPlayerMove(effective_index + 1);
3276 };
3277
3278 slider_play_button.on("click", function() {
3279 if (slider_holder.classed("playing")) stopSliderPlayer();
3280 else if (props.step_time) startSliderPlayer();
3281 });
3282
3283 var setWidths = function() {
3284 slider_holder.style("width", props.width);
3285 var w = window.innerWidth;
3286 var handle_radius = w < 520 ? 12 : 15;
3287 slider.labelSize(w < 520 ? 12 : 14)
3288 .handleRadius(handle_radius)
3289 .margin({
3290 left: handle_radius + 5,
3291 right: handle_radius,
3292 top: w < 520 ? 34 : 30
3293 });
3294 };
3295
3296 var setHandles = (function() {
3297 var handle_col;
3298 return function() {
3299 if (props.slider_play_button) {
3300 slider_holder.classed("animatable", true);
3301 slider_play_button.style("transform", props.step_time < 0 ? "rotate(180deg)" : null);
3302 }
3303 else {
3304 stopSliderPlayer();
3305 slider_holder.classed("animatable", false);
3306 }
3307 if (handle_col !== props.slider_handle_colour){
3308 handle_col = props.slider_handle_colour;
3309 slider_holder.select(".slider-handle").style("fill", handle_col);
3310 play_string = createPlayButton(handle_col);
3311 pause_string = createPauseButton(handle_col);
3312 slider_play_button.style("background-image", sliderplayer ? pause_string : play_string);
3313 }
3314 }
3315 })();
3316
3317 var setStyles = function() {
3318 setWidths();
3319 setHandles();
3320 };
3321
3322 var show = function() {
3323 setStyles();
3324 slider_holder.style("display", "inline-block");
3325 slider.update();
3326 };
3327
3328 var hide = function() {
3329 stopSliderPlayer();
3330 slider_holder.style("display", "none");
3331 };
3332
3333 var setValue = function() {
3334 slider.label(props.value).value(props.index);
3335 };
3336
3337 var setOptions = function() {
3338 slider.domain([0, props.options.length - 1]).update();
3339 };
3340
3341
3342 var slider_obj = { handle: slider_holder };
3343 slider_obj.show = function() { show(); return slider_obj; };
3344 slider_obj.hide = function() { hide(); return slider_obj; };
3345 slider_obj.setValue = function() { setValue(); return slider_obj; };
3346 slider_obj.setOptions = function() { setOptions(); return slider_obj; };
3347
3348 return slider_obj;
3349}
3350
3351function createControlsGroup(container_selector) {
3352 injectCSS(css_string);
3353
3354 var core = createCore(container_selector);
3355 var output_obj = core.output_obj;
3356 var props = core.props;
3357 var onChangeCallbacks = core.onChangeCallbacks;
3358 var container = core.container;
3359 var container_node = container.node();
3360
3361 var dropdown_obj = createDropdown(core);
3362 var buttons_obj = createButtons(core, dropdown_obj);
3363 var slider_obj = createSlider(core);
3364
3365 var options;
3366
3367 var updateCurrentOptions = (function() {
3368 var options = [];
3369 return function() {
3370 var opts = props.options;
3371 var num_options = opts.length;
3372 if (num_options < 2) return;
3373 if (options && opts.length===options.length && opts.every(function(op, i) { return op===options[i]; })) {
3374 // If here we have multiple options that haven't changes since last call.
3375 return false;
3376 }
3377 options = Object.freeze(opts.slice());
3378 if (props.index > num_options - 1) props.index = num_options - 1;
3379 return true;
3380 };
3381 })();
3382
3383 var updateCurrentValue = (function() {
3384 var current_index, current_value;
3385 return function() {
3386 if (current_index === props.index && current_value === props.value) return false;
3387 var n_options = props.options.length;
3388 if (props.index > n_options - 1) props.index = n_options - 1;
3389 current_index = props.index;
3390 current_value = props.value;
3391 return true;
3392 }
3393 } )();
3394
3395 var setControlOptions = function() {
3396 dropdown_obj.setOptions();
3397 buttons_obj.setOptions();
3398 slider_obj.setOptions();
3399 };
3400
3401 var setControlValues = function() {
3402 dropdown_obj.setValue();
3403 buttons_obj.setValue();
3404 slider_obj.setValue();
3405 };
3406
3407 var setVisibleControl = function(control) {
3408 if (control === "dropdown") dropdown_obj.show();
3409 else dropdown_obj.hide();
3410 if (control === "slider") slider_obj.show();
3411 else slider_obj.hide();
3412 if (control === "buttons") buttons_obj.show();
3413 else buttons_obj.hide();
3414 };
3415
3416 var update = function() {
3417 var options_updated = updateCurrentOptions();
3418 if (props.options.length < 2) {
3419 props.index = 0;
3420 setVisibleControl("none");
3421 return;
3422 }
3423 var value_updated = updateCurrentValue();
3424 if (value_updated || options_updated) {
3425 if(options_updated) setControlOptions();
3426 setControlValues();
3427 }
3428 setVisibleControl(props.control);
3429 };
3430
3431 output_obj.update = function() { update(); return this; };
3432
3433 return output_obj;
3434}
3435
3436return createControlsGroup;
3437
3438})));