UNPKG

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