UNPKG

131 kBJavaScriptView Raw
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3 typeof define === 'function' && define.amd ? define(['exports'], factory) :
4 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.controls = {}));
5}(this, (function (exports) { 'use strict';
6
7 var xhtml$1 = "http://www.w3.org/1999/xhtml";
8
9 var namespaces$1 = {
10 svg: "http://www.w3.org/2000/svg",
11 xhtml: xhtml$1,
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
17 function namespace$1(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$1.hasOwnProperty(prefix) ? {space: namespaces$1[prefix], local: name} : name;
21 }
22
23 function creatorInherit$1(name) {
24 return function() {
25 var document = this.ownerDocument,
26 uri = this.namespaceURI;
27 return uri === xhtml$1 && document.documentElement.namespaceURI === xhtml$1
28 ? document.createElement(name)
29 : document.createElementNS(uri, name);
30 };
31 }
32
33 function creatorFixed$1(fullname) {
34 return function() {
35 return this.ownerDocument.createElementNS(fullname.space, fullname.local);
36 };
37 }
38
39 function creator$1(name) {
40 var fullname = namespace$1(name);
41 return (fullname.local
42 ? creatorFixed$1
43 : creatorInherit$1)(fullname);
44 }
45
46 function none$1() {}
47
48 function selector$1(selector) {
49 return selector == null ? none$1 : function() {
50 return this.querySelector(selector);
51 };
52 }
53
54 function selection_select$1(select) {
55 if (typeof select !== "function") select = selector$1(select);
56
57 for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
58 for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
59 if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
60 if ("__data__" in node) subnode.__data__ = node.__data__;
61 subgroup[i] = subnode;
62 }
63 }
64 }
65
66 return new Selection$1(subgroups, this._parents);
67 }
68
69 function empty$1() {
70 return [];
71 }
72
73 function selectorAll$1(selector) {
74 return selector == null ? empty$1 : function() {
75 return this.querySelectorAll(selector);
76 };
77 }
78
79 function selection_selectAll$1(select) {
80 if (typeof select !== "function") select = selectorAll$1(select);
81
82 for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
83 for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
84 if (node = group[i]) {
85 subgroups.push(select.call(node, node.__data__, i, group));
86 parents.push(node);
87 }
88 }
89 }
90
91 return new Selection$1(subgroups, parents);
92 }
93
94 function matcher$1(selector) {
95 return function() {
96 return this.matches(selector);
97 };
98 }
99
100 function selection_filter$1(match) {
101 if (typeof match !== "function") match = matcher$1(match);
102
103 for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
104 for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
105 if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
106 subgroup.push(node);
107 }
108 }
109 }
110
111 return new Selection$1(subgroups, this._parents);
112 }
113
114 function sparse$1(update) {
115 return new Array(update.length);
116 }
117
118 function selection_enter$1() {
119 return new Selection$1(this._enter || this._groups.map(sparse$1), this._parents);
120 }
121
122 function EnterNode$1(parent, datum) {
123 this.ownerDocument = parent.ownerDocument;
124 this.namespaceURI = parent.namespaceURI;
125 this._next = null;
126 this._parent = parent;
127 this.__data__ = datum;
128 }
129
130 EnterNode$1.prototype = {
131 constructor: EnterNode$1,
132 appendChild: function(child) { return this._parent.insertBefore(child, this._next); },
133 insertBefore: function(child, next) { return this._parent.insertBefore(child, next); },
134 querySelector: function(selector) { return this._parent.querySelector(selector); },
135 querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); }
136 };
137
138 function constant$3(x) {
139 return function() {
140 return x;
141 };
142 }
143
144 var keyPrefix$1 = "$"; // Protect against keys like “__proto__”.
145
146 function bindIndex$1(parent, group, enter, update, exit, data) {
147 var i = 0,
148 node,
149 groupLength = group.length,
150 dataLength = data.length;
151
152 // Put any non-null nodes that fit into update.
153 // Put any null nodes into enter.
154 // Put any remaining data into enter.
155 for (; i < dataLength; ++i) {
156 if (node = group[i]) {
157 node.__data__ = data[i];
158 update[i] = node;
159 } else {
160 enter[i] = new EnterNode$1(parent, data[i]);
161 }
162 }
163
164 // Put any non-null nodes that don’t fit into exit.
165 for (; i < groupLength; ++i) {
166 if (node = group[i]) {
167 exit[i] = node;
168 }
169 }
170 }
171
172 function bindKey$1(parent, group, enter, update, exit, data, key) {
173 var i,
174 node,
175 nodeByKeyValue = {},
176 groupLength = group.length,
177 dataLength = data.length,
178 keyValues = new Array(groupLength),
179 keyValue;
180
181 // Compute the key for each node.
182 // If multiple nodes have the same key, the duplicates are added to exit.
183 for (i = 0; i < groupLength; ++i) {
184 if (node = group[i]) {
185 keyValues[i] = keyValue = keyPrefix$1 + key.call(node, node.__data__, i, group);
186 if (keyValue in nodeByKeyValue) {
187 exit[i] = node;
188 } else {
189 nodeByKeyValue[keyValue] = node;
190 }
191 }
192 }
193
194 // Compute the key for each datum.
195 // If there a node associated with this key, join and add it to update.
196 // If there is not (or the key is a duplicate), add it to enter.
197 for (i = 0; i < dataLength; ++i) {
198 keyValue = keyPrefix$1 + key.call(parent, data[i], i, data);
199 if (node = nodeByKeyValue[keyValue]) {
200 update[i] = node;
201 node.__data__ = data[i];
202 nodeByKeyValue[keyValue] = null;
203 } else {
204 enter[i] = new EnterNode$1(parent, data[i]);
205 }
206 }
207
208 // Add any remaining nodes that were not bound to data to exit.
209 for (i = 0; i < groupLength; ++i) {
210 if ((node = group[i]) && (nodeByKeyValue[keyValues[i]] === node)) {
211 exit[i] = node;
212 }
213 }
214 }
215
216 function selection_data$1(value, key) {
217 if (!value) {
218 data = new Array(this.size()), j = -1;
219 this.each(function(d) { data[++j] = d; });
220 return data;
221 }
222
223 var bind = key ? bindKey$1 : bindIndex$1,
224 parents = this._parents,
225 groups = this._groups;
226
227 if (typeof value !== "function") value = constant$3(value);
228
229 for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
230 var parent = parents[j],
231 group = groups[j],
232 groupLength = group.length,
233 data = value.call(parent, parent && parent.__data__, j, parents),
234 dataLength = data.length,
235 enterGroup = enter[j] = new Array(dataLength),
236 updateGroup = update[j] = new Array(dataLength),
237 exitGroup = exit[j] = new Array(groupLength);
238
239 bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);
240
241 // Now connect the enter nodes to their following update node, such that
242 // appendChild can insert the materialized enter node before this node,
243 // rather than at the end of the parent node.
244 for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
245 if (previous = enterGroup[i0]) {
246 if (i0 >= i1) i1 = i0 + 1;
247 while (!(next = updateGroup[i1]) && ++i1 < dataLength);
248 previous._next = next || null;
249 }
250 }
251 }
252
253 update = new Selection$1(update, parents);
254 update._enter = enter;
255 update._exit = exit;
256 return update;
257 }
258
259 function selection_exit$1() {
260 return new Selection$1(this._exit || this._groups.map(sparse$1), this._parents);
261 }
262
263 function selection_join$1(onenter, onupdate, onexit) {
264 var enter = this.enter(), update = this, exit = this.exit();
265 enter = typeof onenter === "function" ? onenter(enter) : enter.append(onenter + "");
266 if (onupdate != null) update = onupdate(update);
267 if (onexit == null) exit.remove(); else onexit(exit);
268 return enter && update ? enter.merge(update).order() : update;
269 }
270
271 function selection_merge$1(selection) {
272
273 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) {
274 for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
275 if (node = group0[i] || group1[i]) {
276 merge[i] = node;
277 }
278 }
279 }
280
281 for (; j < m0; ++j) {
282 merges[j] = groups0[j];
283 }
284
285 return new Selection$1(merges, this._parents);
286 }
287
288 function selection_order$1() {
289
290 for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {
291 for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
292 if (node = group[i]) {
293 if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next);
294 next = node;
295 }
296 }
297 }
298
299 return this;
300 }
301
302 function selection_sort$1(compare) {
303 if (!compare) compare = ascending$3;
304
305 function compareNode(a, b) {
306 return a && b ? compare(a.__data__, b.__data__) : !a - !b;
307 }
308
309 for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
310 for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
311 if (node = group[i]) {
312 sortgroup[i] = node;
313 }
314 }
315 sortgroup.sort(compareNode);
316 }
317
318 return new Selection$1(sortgroups, this._parents).order();
319 }
320
321 function ascending$3(a, b) {
322 return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
323 }
324
325 function selection_call$1() {
326 var callback = arguments[0];
327 arguments[0] = this;
328 callback.apply(null, arguments);
329 return this;
330 }
331
332 function selection_nodes$1() {
333 var nodes = new Array(this.size()), i = -1;
334 this.each(function() { nodes[++i] = this; });
335 return nodes;
336 }
337
338 function selection_node$1() {
339
340 for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
341 for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
342 var node = group[i];
343 if (node) return node;
344 }
345 }
346
347 return null;
348 }
349
350 function selection_size$1() {
351 var size = 0;
352 this.each(function() { ++size; });
353 return size;
354 }
355
356 function selection_empty$1() {
357 return !this.node();
358 }
359
360 function selection_each$1(callback) {
361
362 for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
363 for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
364 if (node = group[i]) callback.call(node, node.__data__, i, group);
365 }
366 }
367
368 return this;
369 }
370
371 function attrRemove$1(name) {
372 return function() {
373 this.removeAttribute(name);
374 };
375 }
376
377 function attrRemoveNS$1(fullname) {
378 return function() {
379 this.removeAttributeNS(fullname.space, fullname.local);
380 };
381 }
382
383 function attrConstant$1(name, value) {
384 return function() {
385 this.setAttribute(name, value);
386 };
387 }
388
389 function attrConstantNS$1(fullname, value) {
390 return function() {
391 this.setAttributeNS(fullname.space, fullname.local, value);
392 };
393 }
394
395 function attrFunction$1(name, value) {
396 return function() {
397 var v = value.apply(this, arguments);
398 if (v == null) this.removeAttribute(name);
399 else this.setAttribute(name, v);
400 };
401 }
402
403 function attrFunctionNS$1(fullname, value) {
404 return function() {
405 var v = value.apply(this, arguments);
406 if (v == null) this.removeAttributeNS(fullname.space, fullname.local);
407 else this.setAttributeNS(fullname.space, fullname.local, v);
408 };
409 }
410
411 function selection_attr$1(name, value) {
412 var fullname = namespace$1(name);
413
414 if (arguments.length < 2) {
415 var node = this.node();
416 return fullname.local
417 ? node.getAttributeNS(fullname.space, fullname.local)
418 : node.getAttribute(fullname);
419 }
420
421 return this.each((value == null
422 ? (fullname.local ? attrRemoveNS$1 : attrRemove$1) : (typeof value === "function"
423 ? (fullname.local ? attrFunctionNS$1 : attrFunction$1)
424 : (fullname.local ? attrConstantNS$1 : attrConstant$1)))(fullname, value));
425 }
426
427 function defaultView$1(node) {
428 return (node.ownerDocument && node.ownerDocument.defaultView) // node is a Node
429 || (node.document && node) // node is a Window
430 || node.defaultView; // node is a Document
431 }
432
433 function styleRemove$1(name) {
434 return function() {
435 this.style.removeProperty(name);
436 };
437 }
438
439 function styleConstant$1(name, value, priority) {
440 return function() {
441 this.style.setProperty(name, value, priority);
442 };
443 }
444
445 function styleFunction$1(name, value, priority) {
446 return function() {
447 var v = value.apply(this, arguments);
448 if (v == null) this.style.removeProperty(name);
449 else this.style.setProperty(name, v, priority);
450 };
451 }
452
453 function selection_style$1(name, value, priority) {
454 return arguments.length > 1
455 ? this.each((value == null
456 ? styleRemove$1 : typeof value === "function"
457 ? styleFunction$1
458 : styleConstant$1)(name, value, priority == null ? "" : priority))
459 : styleValue$1(this.node(), name);
460 }
461
462 function styleValue$1(node, name) {
463 return node.style.getPropertyValue(name)
464 || defaultView$1(node).getComputedStyle(node, null).getPropertyValue(name);
465 }
466
467 function propertyRemove$1(name) {
468 return function() {
469 delete this[name];
470 };
471 }
472
473 function propertyConstant$1(name, value) {
474 return function() {
475 this[name] = value;
476 };
477 }
478
479 function propertyFunction$1(name, value) {
480 return function() {
481 var v = value.apply(this, arguments);
482 if (v == null) delete this[name];
483 else this[name] = v;
484 };
485 }
486
487 function selection_property$1(name, value) {
488 return arguments.length > 1
489 ? this.each((value == null
490 ? propertyRemove$1 : typeof value === "function"
491 ? propertyFunction$1
492 : propertyConstant$1)(name, value))
493 : this.node()[name];
494 }
495
496 function classArray$1(string) {
497 return string.trim().split(/^|\s+/);
498 }
499
500 function classList$1(node) {
501 return node.classList || new ClassList$1(node);
502 }
503
504 function ClassList$1(node) {
505 this._node = node;
506 this._names = classArray$1(node.getAttribute("class") || "");
507 }
508
509 ClassList$1.prototype = {
510 add: function(name) {
511 var i = this._names.indexOf(name);
512 if (i < 0) {
513 this._names.push(name);
514 this._node.setAttribute("class", this._names.join(" "));
515 }
516 },
517 remove: function(name) {
518 var i = this._names.indexOf(name);
519 if (i >= 0) {
520 this._names.splice(i, 1);
521 this._node.setAttribute("class", this._names.join(" "));
522 }
523 },
524 contains: function(name) {
525 return this._names.indexOf(name) >= 0;
526 }
527 };
528
529 function classedAdd$1(node, names) {
530 var list = classList$1(node), i = -1, n = names.length;
531 while (++i < n) list.add(names[i]);
532 }
533
534 function classedRemove$1(node, names) {
535 var list = classList$1(node), i = -1, n = names.length;
536 while (++i < n) list.remove(names[i]);
537 }
538
539 function classedTrue$1(names) {
540 return function() {
541 classedAdd$1(this, names);
542 };
543 }
544
545 function classedFalse$1(names) {
546 return function() {
547 classedRemove$1(this, names);
548 };
549 }
550
551 function classedFunction$1(names, value) {
552 return function() {
553 (value.apply(this, arguments) ? classedAdd$1 : classedRemove$1)(this, names);
554 };
555 }
556
557 function selection_classed$1(name, value) {
558 var names = classArray$1(name + "");
559
560 if (arguments.length < 2) {
561 var list = classList$1(this.node()), i = -1, n = names.length;
562 while (++i < n) if (!list.contains(names[i])) return false;
563 return true;
564 }
565
566 return this.each((typeof value === "function"
567 ? classedFunction$1 : value
568 ? classedTrue$1
569 : classedFalse$1)(names, value));
570 }
571
572 function textRemove$1() {
573 this.textContent = "";
574 }
575
576 function textConstant$1(value) {
577 return function() {
578 this.textContent = value;
579 };
580 }
581
582 function textFunction$1(value) {
583 return function() {
584 var v = value.apply(this, arguments);
585 this.textContent = v == null ? "" : v;
586 };
587 }
588
589 function selection_text$1(value) {
590 return arguments.length
591 ? this.each(value == null
592 ? textRemove$1 : (typeof value === "function"
593 ? textFunction$1
594 : textConstant$1)(value))
595 : this.node().textContent;
596 }
597
598 function htmlRemove$1() {
599 this.innerHTML = "";
600 }
601
602 function htmlConstant$1(value) {
603 return function() {
604 this.innerHTML = value;
605 };
606 }
607
608 function htmlFunction$1(value) {
609 return function() {
610 var v = value.apply(this, arguments);
611 this.innerHTML = v == null ? "" : v;
612 };
613 }
614
615 function selection_html$1(value) {
616 return arguments.length
617 ? this.each(value == null
618 ? htmlRemove$1 : (typeof value === "function"
619 ? htmlFunction$1
620 : htmlConstant$1)(value))
621 : this.node().innerHTML;
622 }
623
624 function raise$1() {
625 if (this.nextSibling) this.parentNode.appendChild(this);
626 }
627
628 function selection_raise$1() {
629 return this.each(raise$1);
630 }
631
632 function lower$1() {
633 if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
634 }
635
636 function selection_lower$1() {
637 return this.each(lower$1);
638 }
639
640 function selection_append$1(name) {
641 var create = typeof name === "function" ? name : creator$1(name);
642 return this.select(function() {
643 return this.appendChild(create.apply(this, arguments));
644 });
645 }
646
647 function constantNull$1() {
648 return null;
649 }
650
651 function selection_insert$1(name, before) {
652 var create = typeof name === "function" ? name : creator$1(name),
653 select = before == null ? constantNull$1 : typeof before === "function" ? before : selector$1(before);
654 return this.select(function() {
655 return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
656 });
657 }
658
659 function remove$1() {
660 var parent = this.parentNode;
661 if (parent) parent.removeChild(this);
662 }
663
664 function selection_remove$1() {
665 return this.each(remove$1);
666 }
667
668 function selection_cloneShallow$1() {
669 var clone = this.cloneNode(false), parent = this.parentNode;
670 return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
671 }
672
673 function selection_cloneDeep$1() {
674 var clone = this.cloneNode(true), parent = this.parentNode;
675 return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
676 }
677
678 function selection_clone$1(deep) {
679 return this.select(deep ? selection_cloneDeep$1 : selection_cloneShallow$1);
680 }
681
682 function selection_datum$1(value) {
683 return arguments.length
684 ? this.property("__data__", value)
685 : this.node().__data__;
686 }
687
688 var filterEvents$1 = {};
689
690 var event$1 = null;
691
692 if (typeof document !== "undefined") {
693 var element$1 = document.documentElement;
694 if (!("onmouseenter" in element$1)) {
695 filterEvents$1 = {mouseenter: "mouseover", mouseleave: "mouseout"};
696 }
697 }
698
699 function filterContextListener$1(listener, index, group) {
700 listener = contextListener$1(listener, index, group);
701 return function(event) {
702 var related = event.relatedTarget;
703 if (!related || (related !== this && !(related.compareDocumentPosition(this) & 8))) {
704 listener.call(this, event);
705 }
706 };
707 }
708
709 function contextListener$1(listener, index, group) {
710 return function(event1) {
711 var event0 = event$1; // Events can be reentrant (e.g., focus).
712 event$1 = event1;
713 try {
714 listener.call(this, this.__data__, index, group);
715 } finally {
716 event$1 = event0;
717 }
718 };
719 }
720
721 function parseTypenames$1(typenames) {
722 return typenames.trim().split(/^|\s+/).map(function(t) {
723 var name = "", i = t.indexOf(".");
724 if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
725 return {type: t, name: name};
726 });
727 }
728
729 function onRemove$1(typename) {
730 return function() {
731 var on = this.__on;
732 if (!on) return;
733 for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
734 if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
735 this.removeEventListener(o.type, o.listener, o.capture);
736 } else {
737 on[++i] = o;
738 }
739 }
740 if (++i) on.length = i;
741 else delete this.__on;
742 };
743 }
744
745 function onAdd$1(typename, value, capture) {
746 var wrap = filterEvents$1.hasOwnProperty(typename.type) ? filterContextListener$1 : contextListener$1;
747 return function(d, i, group) {
748 var on = this.__on, o, listener = wrap(value, i, group);
749 if (on) for (var j = 0, m = on.length; j < m; ++j) {
750 if ((o = on[j]).type === typename.type && o.name === typename.name) {
751 this.removeEventListener(o.type, o.listener, o.capture);
752 this.addEventListener(o.type, o.listener = listener, o.capture = capture);
753 o.value = value;
754 return;
755 }
756 }
757 this.addEventListener(typename.type, listener, capture);
758 o = {type: typename.type, name: typename.name, value: value, listener: listener, capture: capture};
759 if (!on) this.__on = [o];
760 else on.push(o);
761 };
762 }
763
764 function selection_on$1(typename, value, capture) {
765 var typenames = parseTypenames$1(typename + ""), i, n = typenames.length, t;
766
767 if (arguments.length < 2) {
768 var on = this.node().__on;
769 if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
770 for (i = 0, o = on[j]; i < n; ++i) {
771 if ((t = typenames[i]).type === o.type && t.name === o.name) {
772 return o.value;
773 }
774 }
775 }
776 return;
777 }
778
779 on = value ? onAdd$1 : onRemove$1;
780 if (capture == null) capture = false;
781 for (i = 0; i < n; ++i) this.each(on(typenames[i], value, capture));
782 return this;
783 }
784
785 function dispatchEvent$1(node, type, params) {
786 var window = defaultView$1(node),
787 event = window.CustomEvent;
788
789 if (typeof event === "function") {
790 event = new event(type, params);
791 } else {
792 event = window.document.createEvent("Event");
793 if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;
794 else event.initEvent(type, false, false);
795 }
796
797 node.dispatchEvent(event);
798 }
799
800 function dispatchConstant$1(type, params) {
801 return function() {
802 return dispatchEvent$1(this, type, params);
803 };
804 }
805
806 function dispatchFunction$1(type, params) {
807 return function() {
808 return dispatchEvent$1(this, type, params.apply(this, arguments));
809 };
810 }
811
812 function selection_dispatch$1(type, params) {
813 return this.each((typeof params === "function"
814 ? dispatchFunction$1
815 : dispatchConstant$1)(type, params));
816 }
817
818 var root$1 = [null];
819
820 function Selection$1(groups, parents) {
821 this._groups = groups;
822 this._parents = parents;
823 }
824
825 Selection$1.prototype = {
826 constructor: Selection$1,
827 select: selection_select$1,
828 selectAll: selection_selectAll$1,
829 filter: selection_filter$1,
830 data: selection_data$1,
831 enter: selection_enter$1,
832 exit: selection_exit$1,
833 join: selection_join$1,
834 merge: selection_merge$1,
835 order: selection_order$1,
836 sort: selection_sort$1,
837 call: selection_call$1,
838 nodes: selection_nodes$1,
839 node: selection_node$1,
840 size: selection_size$1,
841 empty: selection_empty$1,
842 each: selection_each$1,
843 attr: selection_attr$1,
844 style: selection_style$1,
845 property: selection_property$1,
846 classed: selection_classed$1,
847 text: selection_text$1,
848 html: selection_html$1,
849 raise: selection_raise$1,
850 lower: selection_lower$1,
851 append: selection_append$1,
852 insert: selection_insert$1,
853 remove: selection_remove$1,
854 clone: selection_clone$1,
855 datum: selection_datum$1,
856 on: selection_on$1,
857 dispatch: selection_dispatch$1
858 };
859
860 function select(selector) {
861 return typeof selector === "string"
862 ? new Selection$1([[document.querySelector(selector)]], [document.documentElement])
863 : new Selection$1([[selector]], root$1);
864 }
865
866 function ascending$2(a, b) {
867 return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
868 }
869
870 function sortArray(uarr, sort, parser, formatter) {
871 var sarr = uarr.map(function(d, i) {
872 var parsed_value = parser(d);
873 return {
874 value: d,
875 options_index: i,
876 parsed: parsed_value,
877 display: formatter(d)
878 };
879 });
880
881 if (!sort) return sarr;
882 return sarr.sort(function(a, b) { return ascending$2(a.parsed, b.parsed); });
883 }
884
885 function Stylesheet() {
886 this.declarations = [];
887 return this;
888 }
889
890 Stylesheet.prototype.select = function(selector) {
891 if (!selector) return this;
892 var declaration = new Declaration(selector, this);
893 declaration.parent = this;
894 this.addDeclaration(declaration);
895
896 return declaration;
897 };
898
899 Stylesheet.prototype.addDeclaration = function(declaration) {
900 this.declarations.push(declaration);
901 return this;
902 };
903
904 Stylesheet.prototype.print = function() {
905 var text = "";
906 this.declarations.forEach(function(declaration) {
907 text += declaration.selector + " {\n";
908 declaration.styles.forEach(function(style) {
909 text += "\t" + style[0] + ": " + style[1] + ";\n";
910 });
911 text += "}\n\n";
912 });
913 return text;
914 };
915
916 Stylesheet.prototype.clear = function() {
917 this.declarations = [];
918 return this;
919 };
920
921 function Declaration(selector) {
922 this.selector = selector;
923 this.styles = [];
924 return this;
925 }
926
927 Declaration.prototype.style = function(property, _value) {
928 var value = typeof value_ == "function" ? _value() : _value;
929 if (value !== "" && value !== null && value !== undefined) this.styles.push([property, value]);
930 return this;
931 };
932
933 Declaration.prototype.select = function(selector) {
934 return this.parent.select(this.selector + " " + selector);
935 };
936
937 function createCssString() {
938 var s = new Stylesheet();
939
940 s.select(".fl-controls-container")
941 .style("display", "inline-block")
942 .style("line-height", "1em");
943
944 s.select(".fl-controls-title")
945 .style("display", "inline-block")
946 .style("margin", "0px 0.5em 0px 0px");
947
948 s.select(".fl-controls-container, .fl-controls-container *")
949 .style("box-sizing", "border-box");
950
951 s.select(".slider-holder")
952 .style("margin-bottom", "20px");
953
954 s.select(".fl-controls-slider, .slider-play")
955 .style("pointer-events", "all")
956 .style("display", "inline-block")
957 .style("vertical-align", "middle");
958
959 s.select(".slider-play svg")
960 .style("height", "100%")
961 .style("width", "100%")
962 .style("display", "block")
963 .style("cursor", " pointer", "");
964
965 s.select(".fl-controls-slider svg")
966 .style("display", "block");
967
968 s.select(".slider-play:hover")
969 .style("opacity", "0.6");
970
971 s.select(".fl-control-slider")
972 .style("width", "100%")
973 .style("bottom", "0")
974 .style("align-items", "center");
975
976 s.select(".fl-control")
977 .style("position", "relative");
978
979 s.select(".fl-control.hidden")
980 .style("display", "none");
981
982 s.select(".fl-control .button")
983 .style("display", "inline-flex")
984 .style("align-items", "center")
985 .style("background", "#eee")
986 .style("padding", "0 0.5em")
987 .style("margin-right", "0.25em")
988 .style("margin-bottom", "0.25em")
989 .style("line-height", "1em")
990 .style("box-sizing", "border-box");
991
992 s.select(".fl-control.grouped:not(.hidden)")
993 .style("display", "inline-table")
994 .style("table-layout", "fixed")
995 .select(".button")
996 .style("display", "table-cell")
997 .style("vertical-align", "middle")
998 .style("margin", "0")
999 .style("text-align", "center");
1000
1001 s.select(".fl-control .button.selected")
1002 .style("background", "#ddd");
1003
1004 s.select(".fl-control-dropdown")
1005 .style("line-height", "1em")
1006 .style("position", "relative");
1007
1008 s.select(".fl-control-dropdown::after")
1009 .style("display", "block")
1010 .style("content", "''")
1011 .style("width", "10px")
1012 .style("height", "10px")
1013 .style("background", "transparent")
1014 .style("position", "absolute")
1015 .style("right", "5px")
1016 .style("top", "50%")
1017 .style("pointer-events", "none")
1018 .style("transform", "translateY(calc(-50% + 3px))")
1019 .style("border-left", "5px solid transparent")
1020 .style("border-right", "5px solid transparent")
1021 .style("border-top", "5px solid")
1022 .style("box-sizing", "border-box");
1023
1024 s.select(".fl-control-dropdown select")
1025 .style("-webkit-appearance", "none")
1026 .style("-webkit-border-radius", "0px")
1027 .style("width", "100%");
1028
1029 return s.print();
1030 }
1031
1032 var css_injected = false;
1033
1034 function injectCSS() {
1035 if (css_injected || typeof document === "undefined") return;
1036
1037 var css_string = createCssString();
1038
1039 var head = document.head || document.getElementsByTagName("head")[0];
1040 var style = document.createElement("style");
1041 style.type = "text/css";
1042 style.className = "flourish-controls";
1043 head.appendChild(style);
1044 if (style.styleSheet) {
1045 style.styleSheet.cssText = css_string;
1046 }
1047 else {
1048 style.appendChild(document.createTextNode(css_string));
1049 }
1050 css_injected = true;
1051 }
1052
1053 function define(constructor, factory, prototype) {
1054 constructor.prototype = factory.prototype = prototype;
1055 prototype.constructor = constructor;
1056 }
1057
1058 function extend(parent, definition) {
1059 var prototype = Object.create(parent.prototype);
1060 for (var key in definition) prototype[key] = definition[key];
1061 return prototype;
1062 }
1063
1064 function Color() {}
1065
1066 var darker = 0.7;
1067 var brighter = 1 / darker;
1068
1069 var reI = "\\s*([+-]?\\d+)\\s*",
1070 reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",
1071 reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",
1072 reHex = /^#([0-9a-f]{3,8})$/,
1073 reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$"),
1074 reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$"),
1075 reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$"),
1076 reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$"),
1077 reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$"),
1078 reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
1079
1080 var named = {
1081 aliceblue: 0xf0f8ff,
1082 antiquewhite: 0xfaebd7,
1083 aqua: 0x00ffff,
1084 aquamarine: 0x7fffd4,
1085 azure: 0xf0ffff,
1086 beige: 0xf5f5dc,
1087 bisque: 0xffe4c4,
1088 black: 0x000000,
1089 blanchedalmond: 0xffebcd,
1090 blue: 0x0000ff,
1091 blueviolet: 0x8a2be2,
1092 brown: 0xa52a2a,
1093 burlywood: 0xdeb887,
1094 cadetblue: 0x5f9ea0,
1095 chartreuse: 0x7fff00,
1096 chocolate: 0xd2691e,
1097 coral: 0xff7f50,
1098 cornflowerblue: 0x6495ed,
1099 cornsilk: 0xfff8dc,
1100 crimson: 0xdc143c,
1101 cyan: 0x00ffff,
1102 darkblue: 0x00008b,
1103 darkcyan: 0x008b8b,
1104 darkgoldenrod: 0xb8860b,
1105 darkgray: 0xa9a9a9,
1106 darkgreen: 0x006400,
1107 darkgrey: 0xa9a9a9,
1108 darkkhaki: 0xbdb76b,
1109 darkmagenta: 0x8b008b,
1110 darkolivegreen: 0x556b2f,
1111 darkorange: 0xff8c00,
1112 darkorchid: 0x9932cc,
1113 darkred: 0x8b0000,
1114 darksalmon: 0xe9967a,
1115 darkseagreen: 0x8fbc8f,
1116 darkslateblue: 0x483d8b,
1117 darkslategray: 0x2f4f4f,
1118 darkslategrey: 0x2f4f4f,
1119 darkturquoise: 0x00ced1,
1120 darkviolet: 0x9400d3,
1121 deeppink: 0xff1493,
1122 deepskyblue: 0x00bfff,
1123 dimgray: 0x696969,
1124 dimgrey: 0x696969,
1125 dodgerblue: 0x1e90ff,
1126 firebrick: 0xb22222,
1127 floralwhite: 0xfffaf0,
1128 forestgreen: 0x228b22,
1129 fuchsia: 0xff00ff,
1130 gainsboro: 0xdcdcdc,
1131 ghostwhite: 0xf8f8ff,
1132 gold: 0xffd700,
1133 goldenrod: 0xdaa520,
1134 gray: 0x808080,
1135 green: 0x008000,
1136 greenyellow: 0xadff2f,
1137 grey: 0x808080,
1138 honeydew: 0xf0fff0,
1139 hotpink: 0xff69b4,
1140 indianred: 0xcd5c5c,
1141 indigo: 0x4b0082,
1142 ivory: 0xfffff0,
1143 khaki: 0xf0e68c,
1144 lavender: 0xe6e6fa,
1145 lavenderblush: 0xfff0f5,
1146 lawngreen: 0x7cfc00,
1147 lemonchiffon: 0xfffacd,
1148 lightblue: 0xadd8e6,
1149 lightcoral: 0xf08080,
1150 lightcyan: 0xe0ffff,
1151 lightgoldenrodyellow: 0xfafad2,
1152 lightgray: 0xd3d3d3,
1153 lightgreen: 0x90ee90,
1154 lightgrey: 0xd3d3d3,
1155 lightpink: 0xffb6c1,
1156 lightsalmon: 0xffa07a,
1157 lightseagreen: 0x20b2aa,
1158 lightskyblue: 0x87cefa,
1159 lightslategray: 0x778899,
1160 lightslategrey: 0x778899,
1161 lightsteelblue: 0xb0c4de,
1162 lightyellow: 0xffffe0,
1163 lime: 0x00ff00,
1164 limegreen: 0x32cd32,
1165 linen: 0xfaf0e6,
1166 magenta: 0xff00ff,
1167 maroon: 0x800000,
1168 mediumaquamarine: 0x66cdaa,
1169 mediumblue: 0x0000cd,
1170 mediumorchid: 0xba55d3,
1171 mediumpurple: 0x9370db,
1172 mediumseagreen: 0x3cb371,
1173 mediumslateblue: 0x7b68ee,
1174 mediumspringgreen: 0x00fa9a,
1175 mediumturquoise: 0x48d1cc,
1176 mediumvioletred: 0xc71585,
1177 midnightblue: 0x191970,
1178 mintcream: 0xf5fffa,
1179 mistyrose: 0xffe4e1,
1180 moccasin: 0xffe4b5,
1181 navajowhite: 0xffdead,
1182 navy: 0x000080,
1183 oldlace: 0xfdf5e6,
1184 olive: 0x808000,
1185 olivedrab: 0x6b8e23,
1186 orange: 0xffa500,
1187 orangered: 0xff4500,
1188 orchid: 0xda70d6,
1189 palegoldenrod: 0xeee8aa,
1190 palegreen: 0x98fb98,
1191 paleturquoise: 0xafeeee,
1192 palevioletred: 0xdb7093,
1193 papayawhip: 0xffefd5,
1194 peachpuff: 0xffdab9,
1195 peru: 0xcd853f,
1196 pink: 0xffc0cb,
1197 plum: 0xdda0dd,
1198 powderblue: 0xb0e0e6,
1199 purple: 0x800080,
1200 rebeccapurple: 0x663399,
1201 red: 0xff0000,
1202 rosybrown: 0xbc8f8f,
1203 royalblue: 0x4169e1,
1204 saddlebrown: 0x8b4513,
1205 salmon: 0xfa8072,
1206 sandybrown: 0xf4a460,
1207 seagreen: 0x2e8b57,
1208 seashell: 0xfff5ee,
1209 sienna: 0xa0522d,
1210 silver: 0xc0c0c0,
1211 skyblue: 0x87ceeb,
1212 slateblue: 0x6a5acd,
1213 slategray: 0x708090,
1214 slategrey: 0x708090,
1215 snow: 0xfffafa,
1216 springgreen: 0x00ff7f,
1217 steelblue: 0x4682b4,
1218 tan: 0xd2b48c,
1219 teal: 0x008080,
1220 thistle: 0xd8bfd8,
1221 tomato: 0xff6347,
1222 turquoise: 0x40e0d0,
1223 violet: 0xee82ee,
1224 wheat: 0xf5deb3,
1225 white: 0xffffff,
1226 whitesmoke: 0xf5f5f5,
1227 yellow: 0xffff00,
1228 yellowgreen: 0x9acd32
1229 };
1230
1231 define(Color, color, {
1232 copy: function(channels) {
1233 return Object.assign(new this.constructor, this, channels);
1234 },
1235 displayable: function() {
1236 return this.rgb().displayable();
1237 },
1238 hex: color_formatHex, // Deprecated! Use color.formatHex.
1239 formatHex: color_formatHex,
1240 formatHsl: color_formatHsl,
1241 formatRgb: color_formatRgb,
1242 toString: color_formatRgb
1243 });
1244
1245 function color_formatHex() {
1246 return this.rgb().formatHex();
1247 }
1248
1249 function color_formatHsl() {
1250 return hslConvert(this).formatHsl();
1251 }
1252
1253 function color_formatRgb() {
1254 return this.rgb().formatRgb();
1255 }
1256
1257 function color(format) {
1258 var m, l;
1259 format = (format + "").trim().toLowerCase();
1260 return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) // #ff0000
1261 : l === 3 ? new Rgb((m >> 8 & 0xf) | (m >> 4 & 0xf0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1) // #f00
1262 : l === 8 ? rgba(m >> 24 & 0xff, m >> 16 & 0xff, m >> 8 & 0xff, (m & 0xff) / 0xff) // #ff000000
1263 : l === 4 ? rgba((m >> 12 & 0xf) | (m >> 8 & 0xf0), (m >> 8 & 0xf) | (m >> 4 & 0xf0), (m >> 4 & 0xf) | (m & 0xf0), (((m & 0xf) << 4) | (m & 0xf)) / 0xff) // #f000
1264 : null) // invalid hex
1265 : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
1266 : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
1267 : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
1268 : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
1269 : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
1270 : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
1271 : named.hasOwnProperty(format) ? rgbn(named[format]) // eslint-disable-line no-prototype-builtins
1272 : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0)
1273 : null;
1274 }
1275
1276 function rgbn(n) {
1277 return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
1278 }
1279
1280 function rgba(r, g, b, a) {
1281 if (a <= 0) r = g = b = NaN;
1282 return new Rgb(r, g, b, a);
1283 }
1284
1285 function rgbConvert(o) {
1286 if (!(o instanceof Color)) o = color(o);
1287 if (!o) return new Rgb;
1288 o = o.rgb();
1289 return new Rgb(o.r, o.g, o.b, o.opacity);
1290 }
1291
1292 function rgb$1(r, g, b, opacity) {
1293 return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
1294 }
1295
1296 function Rgb(r, g, b, opacity) {
1297 this.r = +r;
1298 this.g = +g;
1299 this.b = +b;
1300 this.opacity = +opacity;
1301 }
1302
1303 define(Rgb, rgb$1, extend(Color, {
1304 brighter: function(k) {
1305 k = k == null ? brighter : Math.pow(brighter, k);
1306 return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
1307 },
1308 darker: function(k) {
1309 k = k == null ? darker : Math.pow(darker, k);
1310 return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
1311 },
1312 rgb: function() {
1313 return this;
1314 },
1315 displayable: function() {
1316 return (-0.5 <= this.r && this.r < 255.5)
1317 && (-0.5 <= this.g && this.g < 255.5)
1318 && (-0.5 <= this.b && this.b < 255.5)
1319 && (0 <= this.opacity && this.opacity <= 1);
1320 },
1321 hex: rgb_formatHex, // Deprecated! Use color.formatHex.
1322 formatHex: rgb_formatHex,
1323 formatRgb: rgb_formatRgb,
1324 toString: rgb_formatRgb
1325 }));
1326
1327 function rgb_formatHex() {
1328 return "#" + hex(this.r) + hex(this.g) + hex(this.b);
1329 }
1330
1331 function rgb_formatRgb() {
1332 var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
1333 return (a === 1 ? "rgb(" : "rgba(")
1334 + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", "
1335 + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", "
1336 + Math.max(0, Math.min(255, Math.round(this.b) || 0))
1337 + (a === 1 ? ")" : ", " + a + ")");
1338 }
1339
1340 function hex(value) {
1341 value = Math.max(0, Math.min(255, Math.round(value) || 0));
1342 return (value < 16 ? "0" : "") + value.toString(16);
1343 }
1344
1345 function hsla(h, s, l, a) {
1346 if (a <= 0) h = s = l = NaN;
1347 else if (l <= 0 || l >= 1) h = s = NaN;
1348 else if (s <= 0) h = NaN;
1349 return new Hsl(h, s, l, a);
1350 }
1351
1352 function hslConvert(o) {
1353 if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
1354 if (!(o instanceof Color)) o = color(o);
1355 if (!o) return new Hsl;
1356 if (o instanceof Hsl) return o;
1357 o = o.rgb();
1358 var r = o.r / 255,
1359 g = o.g / 255,
1360 b = o.b / 255,
1361 min = Math.min(r, g, b),
1362 max = Math.max(r, g, b),
1363 h = NaN,
1364 s = max - min,
1365 l = (max + min) / 2;
1366 if (s) {
1367 if (r === max) h = (g - b) / s + (g < b) * 6;
1368 else if (g === max) h = (b - r) / s + 2;
1369 else h = (r - g) / s + 4;
1370 s /= l < 0.5 ? max + min : 2 - max - min;
1371 h *= 60;
1372 } else {
1373 s = l > 0 && l < 1 ? 0 : h;
1374 }
1375 return new Hsl(h, s, l, o.opacity);
1376 }
1377
1378 function hsl(h, s, l, opacity) {
1379 return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
1380 }
1381
1382 function Hsl(h, s, l, opacity) {
1383 this.h = +h;
1384 this.s = +s;
1385 this.l = +l;
1386 this.opacity = +opacity;
1387 }
1388
1389 define(Hsl, hsl, extend(Color, {
1390 brighter: function(k) {
1391 k = k == null ? brighter : Math.pow(brighter, k);
1392 return new Hsl(this.h, this.s, this.l * k, this.opacity);
1393 },
1394 darker: function(k) {
1395 k = k == null ? darker : Math.pow(darker, k);
1396 return new Hsl(this.h, this.s, this.l * k, this.opacity);
1397 },
1398 rgb: function() {
1399 var h = this.h % 360 + (this.h < 0) * 360,
1400 s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
1401 l = this.l,
1402 m2 = l + (l < 0.5 ? l : 1 - l) * s,
1403 m1 = 2 * l - m2;
1404 return new Rgb(
1405 hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2),
1406 hsl2rgb(h, m1, m2),
1407 hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2),
1408 this.opacity
1409 );
1410 },
1411 displayable: function() {
1412 return (0 <= this.s && this.s <= 1 || isNaN(this.s))
1413 && (0 <= this.l && this.l <= 1)
1414 && (0 <= this.opacity && this.opacity <= 1);
1415 },
1416 formatHsl: function() {
1417 var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
1418 return (a === 1 ? "hsl(" : "hsla(")
1419 + (this.h || 0) + ", "
1420 + (this.s || 0) * 100 + "%, "
1421 + (this.l || 0) * 100 + "%"
1422 + (a === 1 ? ")" : ", " + a + ")");
1423 }
1424 }));
1425
1426 /* From FvD 13.37, CSS Color Module Level 3 */
1427 function hsl2rgb(h, m1, m2) {
1428 return (h < 60 ? m1 + (m2 - m1) * h / 60
1429 : h < 180 ? m2
1430 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60
1431 : m1) * 255;
1432 }
1433
1434 var prefix = "$";
1435
1436 function Map() {}
1437
1438 Map.prototype = map$2.prototype = {
1439 constructor: Map,
1440 has: function(key) {
1441 return (prefix + key) in this;
1442 },
1443 get: function(key) {
1444 return this[prefix + key];
1445 },
1446 set: function(key, value) {
1447 this[prefix + key] = value;
1448 return this;
1449 },
1450 remove: function(key) {
1451 var property = prefix + key;
1452 return property in this && delete this[property];
1453 },
1454 clear: function() {
1455 for (var property in this) if (property[0] === prefix) delete this[property];
1456 },
1457 keys: function() {
1458 var keys = [];
1459 for (var property in this) if (property[0] === prefix) keys.push(property.slice(1));
1460 return keys;
1461 },
1462 values: function() {
1463 var values = [];
1464 for (var property in this) if (property[0] === prefix) values.push(this[property]);
1465 return values;
1466 },
1467 entries: function() {
1468 var entries = [];
1469 for (var property in this) if (property[0] === prefix) entries.push({key: property.slice(1), value: this[property]});
1470 return entries;
1471 },
1472 size: function() {
1473 var size = 0;
1474 for (var property in this) if (property[0] === prefix) ++size;
1475 return size;
1476 },
1477 empty: function() {
1478 for (var property in this) if (property[0] === prefix) return false;
1479 return true;
1480 },
1481 each: function(f) {
1482 for (var property in this) if (property[0] === prefix) f(this[property], property.slice(1), this);
1483 }
1484 };
1485
1486 function map$2(object, f) {
1487 var map = new Map;
1488
1489 // Copy constructor.
1490 if (object instanceof Map) object.each(function(value, key) { map.set(key, value); });
1491
1492 // Index array by numeric index or specified key function.
1493 else if (Array.isArray(object)) {
1494 var i = -1,
1495 n = object.length,
1496 o;
1497
1498 if (f == null) while (++i < n) map.set(i, object[i]);
1499 else while (++i < n) map.set(f(o = object[i], i, object), o);
1500 }
1501
1502 // Convert object to map.
1503 else if (object) for (var key in object) map.set(key, object[key]);
1504
1505 return map;
1506 }
1507
1508 function Set() {}
1509
1510 var proto = map$2.prototype;
1511
1512 Set.prototype = {
1513 constructor: Set,
1514 has: proto.has,
1515 add: function(value) {
1516 value += "";
1517 this[prefix + value] = value;
1518 return this;
1519 },
1520 remove: proto.remove,
1521 clear: proto.clear,
1522 values: proto.keys,
1523 size: proto.size,
1524 empty: proto.empty,
1525 each: proto.each
1526 };
1527
1528 var getTextWidth = (function() {
1529 var context = document.createElement("canvas").getContext("2d");
1530 return function(text, font) {
1531 context.font = font || "10px sans-serif";
1532 var metrics = context.measureText(text);
1533 return metrics.width;
1534 };
1535 })();
1536
1537 var remToPx;
1538
1539 function getRemToPx() {
1540 var font_size = parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;
1541 remToPx = function (rem) { return rem * font_size; };
1542 }
1543
1544 function createDropdown(control_obj, state, container) {
1545 var dropdown_obj = {};
1546
1547 // Add dropdown elements to container
1548 var dropdown_wrapper = select(container).append("div")
1549 .attr("class", "fl-control fl-control-dropdown");
1550
1551 const dropdown = dropdown_wrapper.append("select")
1552 .on("change", function() {
1553 const data = dropdown.select("option:checked").datum();
1554 const index = data.options_index;
1555 control_obj.index(index);
1556 control_obj.trigger("change");
1557 });
1558
1559 var showControl = function(longest_text_width) {
1560 var dropdown_width = "100%";
1561
1562 if (state.dropdown_width_mode == "auto") {
1563 dropdown_width = (Math.min(longest_text_width + 40, remToPx(20)) + remToPx(1)) + "px";
1564 }
1565 else if (state.dropdown_width_mode == "fixed") {
1566 dropdown_width = remToPx(state.dropdown_width_fixed) + "px";
1567 }
1568
1569 container.style.width = state.dropdown_width_mode == "full" ? dropdown_width : "";
1570
1571 dropdown_wrapper.style("width", dropdown_width)
1572 .style("display", state.dropdown_width_mode !== "full" ? "inline-table" : null);
1573 };
1574
1575 var hideControl = function() {
1576 dropdown_wrapper.style("display", "none");
1577 };
1578
1579 dropdown_obj.show = showControl;
1580 dropdown_obj.hide = hideControl;
1581
1582
1583 dropdown_obj.update = function(sorted_options) {
1584 var dropdown_font_size = window.getComputedStyle(dropdown.node()).fontSize;
1585 if (!control_obj.n_options || state.control_type !== "dropdown") {
1586 hideControl();
1587 return dropdown_obj;
1588 }
1589
1590 const options = dropdown.selectAll("option").data(sorted_options, d => d.value);
1591 options.exit().remove();
1592
1593 var options_enter = options.enter()
1594 .append("option")
1595 .text(d => d.display)
1596 .attr("value", d => d.value);
1597
1598 let longest_text_width = 0;
1599 const font = dropdown_font_size + " sans-serif";
1600
1601 if (state.dropdown_width_mode === "auto") {
1602 options.merge(options_enter)
1603 .each(function(d) {
1604 const text_width = getTextWidth(d.display, font);
1605 longest_text_width = Math.max(longest_text_width, text_width);
1606 });
1607 }
1608
1609 showControl(longest_text_width);
1610
1611 return dropdown_obj;
1612 };
1613
1614
1615 return dropdown_obj;
1616 }
1617
1618 function createButtons(control_obj, state, container) {
1619 var button_obj = {};
1620 var button_container = select(container).append("div").attr("class", "fl-control fl-control-buttons");
1621
1622 var showControl = function() {
1623 button_container.classed("hidden", false);
1624 };
1625
1626 var hideControl = function() {
1627 button_container.classed("hidden", true);
1628 };
1629
1630 button_obj.show = showControl;
1631 button_obj.hide = hideControl;
1632
1633 button_obj.update = function(sorted_options) {
1634 if (!control_obj.n_options || state.control_type !== "buttons") {
1635 hideControl();
1636 return button_obj;
1637 }
1638
1639 var index = control_obj.index();
1640
1641 button_container.classed("grouped", state.button_group);
1642 button_container.classed("fixed-width", state.button_group_width_mode == "fixed" || state.button_group_width_mode == "full");
1643 button_container.style("width", state.button_group && state.button_group_width_mode == "fixed" ? remToPx(state.button_group_width_fixed) + "px" : state.button_group_width_mode == "full" ? "100%" : null);
1644
1645 var clickHandler = function(d) {
1646 var i = d.options_index;
1647 if (i === control_obj.index()) return;
1648 control_obj.index(i);
1649 control_obj.trigger("change");
1650 };
1651
1652 var buttons = button_container.selectAll(".button")
1653 .data(sorted_options, function(d) { return d.display; });
1654
1655 var buttons_enter = buttons.enter()
1656 .append("div")
1657 .attr("class", "button")
1658 .style("cursor", "pointer")
1659 .attr("role", "button")
1660 .attr("tabindex", 0)
1661 .on("click", function(d) { clickHandler(d); })
1662 .on("keyup", function(d) {
1663 if (event$1.code === "Space" || event$1.code === "Enter") {
1664 event$1.preventDefault();
1665 clickHandler(d);
1666 }
1667 });
1668
1669 buttons_enter.append("span")
1670 .text(function(d) { return d.display; });
1671
1672 showControl();
1673
1674 buttons.merge(buttons_enter)
1675 .classed("selected", function(d) { return d.options_index === index; })
1676 .attr("aria-pressed", function(d) { return d.options_index === index; });
1677
1678 buttons.exit().remove();
1679
1680 showControl();
1681 };
1682
1683 return button_obj;
1684 }
1685
1686 var xhtml = "http://www.w3.org/1999/xhtml";
1687
1688 var namespaces = {
1689 svg: "http://www.w3.org/2000/svg",
1690 xhtml: xhtml,
1691 xlink: "http://www.w3.org/1999/xlink",
1692 xml: "http://www.w3.org/XML/1998/namespace",
1693 xmlns: "http://www.w3.org/2000/xmlns/"
1694 };
1695
1696 function namespace(name) {
1697 var prefix = name += "", i = prefix.indexOf(":");
1698 if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
1699 return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name;
1700 }
1701
1702 function creatorInherit(name) {
1703 return function() {
1704 var document = this.ownerDocument,
1705 uri = this.namespaceURI;
1706 return uri === xhtml && document.documentElement.namespaceURI === xhtml
1707 ? document.createElement(name)
1708 : document.createElementNS(uri, name);
1709 };
1710 }
1711
1712 function creatorFixed(fullname) {
1713 return function() {
1714 return this.ownerDocument.createElementNS(fullname.space, fullname.local);
1715 };
1716 }
1717
1718 function creator(name) {
1719 var fullname = namespace(name);
1720 return (fullname.local
1721 ? creatorFixed
1722 : creatorInherit)(fullname);
1723 }
1724
1725 function none() {}
1726
1727 function selector(selector) {
1728 return selector == null ? none : function() {
1729 return this.querySelector(selector);
1730 };
1731 }
1732
1733 function selection_select(select) {
1734 if (typeof select !== "function") select = selector(select);
1735
1736 for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
1737 for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
1738 if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
1739 if ("__data__" in node) subnode.__data__ = node.__data__;
1740 subgroup[i] = subnode;
1741 }
1742 }
1743 }
1744
1745 return new Selection(subgroups, this._parents);
1746 }
1747
1748 function empty() {
1749 return [];
1750 }
1751
1752 function selectorAll(selector) {
1753 return selector == null ? empty : function() {
1754 return this.querySelectorAll(selector);
1755 };
1756 }
1757
1758 function selection_selectAll(select) {
1759 if (typeof select !== "function") select = selectorAll(select);
1760
1761 for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
1762 for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
1763 if (node = group[i]) {
1764 subgroups.push(select.call(node, node.__data__, i, group));
1765 parents.push(node);
1766 }
1767 }
1768 }
1769
1770 return new Selection(subgroups, parents);
1771 }
1772
1773 function matcher(selector) {
1774 return function() {
1775 return this.matches(selector);
1776 };
1777 }
1778
1779 function selection_filter(match) {
1780 if (typeof match !== "function") match = matcher(match);
1781
1782 for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
1783 for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
1784 if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
1785 subgroup.push(node);
1786 }
1787 }
1788 }
1789
1790 return new Selection(subgroups, this._parents);
1791 }
1792
1793 function sparse(update) {
1794 return new Array(update.length);
1795 }
1796
1797 function selection_enter() {
1798 return new Selection(this._enter || this._groups.map(sparse), this._parents);
1799 }
1800
1801 function EnterNode(parent, datum) {
1802 this.ownerDocument = parent.ownerDocument;
1803 this.namespaceURI = parent.namespaceURI;
1804 this._next = null;
1805 this._parent = parent;
1806 this.__data__ = datum;
1807 }
1808
1809 EnterNode.prototype = {
1810 constructor: EnterNode,
1811 appendChild: function(child) { return this._parent.insertBefore(child, this._next); },
1812 insertBefore: function(child, next) { return this._parent.insertBefore(child, next); },
1813 querySelector: function(selector) { return this._parent.querySelector(selector); },
1814 querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); }
1815 };
1816
1817 function constant$2(x) {
1818 return function() {
1819 return x;
1820 };
1821 }
1822
1823 var keyPrefix = "$"; // Protect against keys like “__proto__”.
1824
1825 function bindIndex(parent, group, enter, update, exit, data) {
1826 var i = 0,
1827 node,
1828 groupLength = group.length,
1829 dataLength = data.length;
1830
1831 // Put any non-null nodes that fit into update.
1832 // Put any null nodes into enter.
1833 // Put any remaining data into enter.
1834 for (; i < dataLength; ++i) {
1835 if (node = group[i]) {
1836 node.__data__ = data[i];
1837 update[i] = node;
1838 } else {
1839 enter[i] = new EnterNode(parent, data[i]);
1840 }
1841 }
1842
1843 // Put any non-null nodes that don’t fit into exit.
1844 for (; i < groupLength; ++i) {
1845 if (node = group[i]) {
1846 exit[i] = node;
1847 }
1848 }
1849 }
1850
1851 function bindKey(parent, group, enter, update, exit, data, key) {
1852 var i,
1853 node,
1854 nodeByKeyValue = {},
1855 groupLength = group.length,
1856 dataLength = data.length,
1857 keyValues = new Array(groupLength),
1858 keyValue;
1859
1860 // Compute the key for each node.
1861 // If multiple nodes have the same key, the duplicates are added to exit.
1862 for (i = 0; i < groupLength; ++i) {
1863 if (node = group[i]) {
1864 keyValues[i] = keyValue = keyPrefix + key.call(node, node.__data__, i, group);
1865 if (keyValue in nodeByKeyValue) {
1866 exit[i] = node;
1867 } else {
1868 nodeByKeyValue[keyValue] = node;
1869 }
1870 }
1871 }
1872
1873 // Compute the key for each datum.
1874 // If there a node associated with this key, join and add it to update.
1875 // If there is not (or the key is a duplicate), add it to enter.
1876 for (i = 0; i < dataLength; ++i) {
1877 keyValue = keyPrefix + key.call(parent, data[i], i, data);
1878 if (node = nodeByKeyValue[keyValue]) {
1879 update[i] = node;
1880 node.__data__ = data[i];
1881 nodeByKeyValue[keyValue] = null;
1882 } else {
1883 enter[i] = new EnterNode(parent, data[i]);
1884 }
1885 }
1886
1887 // Add any remaining nodes that were not bound to data to exit.
1888 for (i = 0; i < groupLength; ++i) {
1889 if ((node = group[i]) && (nodeByKeyValue[keyValues[i]] === node)) {
1890 exit[i] = node;
1891 }
1892 }
1893 }
1894
1895 function selection_data(value, key) {
1896 if (!value) {
1897 data = new Array(this.size()), j = -1;
1898 this.each(function(d) { data[++j] = d; });
1899 return data;
1900 }
1901
1902 var bind = key ? bindKey : bindIndex,
1903 parents = this._parents,
1904 groups = this._groups;
1905
1906 if (typeof value !== "function") value = constant$2(value);
1907
1908 for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
1909 var parent = parents[j],
1910 group = groups[j],
1911 groupLength = group.length,
1912 data = value.call(parent, parent && parent.__data__, j, parents),
1913 dataLength = data.length,
1914 enterGroup = enter[j] = new Array(dataLength),
1915 updateGroup = update[j] = new Array(dataLength),
1916 exitGroup = exit[j] = new Array(groupLength);
1917
1918 bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);
1919
1920 // Now connect the enter nodes to their following update node, such that
1921 // appendChild can insert the materialized enter node before this node,
1922 // rather than at the end of the parent node.
1923 for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
1924 if (previous = enterGroup[i0]) {
1925 if (i0 >= i1) i1 = i0 + 1;
1926 while (!(next = updateGroup[i1]) && ++i1 < dataLength);
1927 previous._next = next || null;
1928 }
1929 }
1930 }
1931
1932 update = new Selection(update, parents);
1933 update._enter = enter;
1934 update._exit = exit;
1935 return update;
1936 }
1937
1938 function selection_exit() {
1939 return new Selection(this._exit || this._groups.map(sparse), this._parents);
1940 }
1941
1942 function selection_join(onenter, onupdate, onexit) {
1943 var enter = this.enter(), update = this, exit = this.exit();
1944 enter = typeof onenter === "function" ? onenter(enter) : enter.append(onenter + "");
1945 if (onupdate != null) update = onupdate(update);
1946 if (onexit == null) exit.remove(); else onexit(exit);
1947 return enter && update ? enter.merge(update).order() : update;
1948 }
1949
1950 function selection_merge(selection) {
1951
1952 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) {
1953 for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
1954 if (node = group0[i] || group1[i]) {
1955 merge[i] = node;
1956 }
1957 }
1958 }
1959
1960 for (; j < m0; ++j) {
1961 merges[j] = groups0[j];
1962 }
1963
1964 return new Selection(merges, this._parents);
1965 }
1966
1967 function selection_order() {
1968
1969 for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {
1970 for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
1971 if (node = group[i]) {
1972 if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next);
1973 next = node;
1974 }
1975 }
1976 }
1977
1978 return this;
1979 }
1980
1981 function selection_sort(compare) {
1982 if (!compare) compare = ascending$1;
1983
1984 function compareNode(a, b) {
1985 return a && b ? compare(a.__data__, b.__data__) : !a - !b;
1986 }
1987
1988 for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
1989 for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
1990 if (node = group[i]) {
1991 sortgroup[i] = node;
1992 }
1993 }
1994 sortgroup.sort(compareNode);
1995 }
1996
1997 return new Selection(sortgroups, this._parents).order();
1998 }
1999
2000 function ascending$1(a, b) {
2001 return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
2002 }
2003
2004 function selection_call() {
2005 var callback = arguments[0];
2006 arguments[0] = this;
2007 callback.apply(null, arguments);
2008 return this;
2009 }
2010
2011 function selection_nodes() {
2012 var nodes = new Array(this.size()), i = -1;
2013 this.each(function() { nodes[++i] = this; });
2014 return nodes;
2015 }
2016
2017 function selection_node() {
2018
2019 for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
2020 for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
2021 var node = group[i];
2022 if (node) return node;
2023 }
2024 }
2025
2026 return null;
2027 }
2028
2029 function selection_size() {
2030 var size = 0;
2031 this.each(function() { ++size; });
2032 return size;
2033 }
2034
2035 function selection_empty() {
2036 return !this.node();
2037 }
2038
2039 function selection_each(callback) {
2040
2041 for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
2042 for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
2043 if (node = group[i]) callback.call(node, node.__data__, i, group);
2044 }
2045 }
2046
2047 return this;
2048 }
2049
2050 function attrRemove(name) {
2051 return function() {
2052 this.removeAttribute(name);
2053 };
2054 }
2055
2056 function attrRemoveNS(fullname) {
2057 return function() {
2058 this.removeAttributeNS(fullname.space, fullname.local);
2059 };
2060 }
2061
2062 function attrConstant(name, value) {
2063 return function() {
2064 this.setAttribute(name, value);
2065 };
2066 }
2067
2068 function attrConstantNS(fullname, value) {
2069 return function() {
2070 this.setAttributeNS(fullname.space, fullname.local, value);
2071 };
2072 }
2073
2074 function attrFunction(name, value) {
2075 return function() {
2076 var v = value.apply(this, arguments);
2077 if (v == null) this.removeAttribute(name);
2078 else this.setAttribute(name, v);
2079 };
2080 }
2081
2082 function attrFunctionNS(fullname, value) {
2083 return function() {
2084 var v = value.apply(this, arguments);
2085 if (v == null) this.removeAttributeNS(fullname.space, fullname.local);
2086 else this.setAttributeNS(fullname.space, fullname.local, v);
2087 };
2088 }
2089
2090 function selection_attr(name, value) {
2091 var fullname = namespace(name);
2092
2093 if (arguments.length < 2) {
2094 var node = this.node();
2095 return fullname.local
2096 ? node.getAttributeNS(fullname.space, fullname.local)
2097 : node.getAttribute(fullname);
2098 }
2099
2100 return this.each((value == null
2101 ? (fullname.local ? attrRemoveNS : attrRemove) : (typeof value === "function"
2102 ? (fullname.local ? attrFunctionNS : attrFunction)
2103 : (fullname.local ? attrConstantNS : attrConstant)))(fullname, value));
2104 }
2105
2106 function defaultView(node) {
2107 return (node.ownerDocument && node.ownerDocument.defaultView) // node is a Node
2108 || (node.document && node) // node is a Window
2109 || node.defaultView; // node is a Document
2110 }
2111
2112 function styleRemove(name) {
2113 return function() {
2114 this.style.removeProperty(name);
2115 };
2116 }
2117
2118 function styleConstant(name, value, priority) {
2119 return function() {
2120 this.style.setProperty(name, value, priority);
2121 };
2122 }
2123
2124 function styleFunction(name, value, priority) {
2125 return function() {
2126 var v = value.apply(this, arguments);
2127 if (v == null) this.style.removeProperty(name);
2128 else this.style.setProperty(name, v, priority);
2129 };
2130 }
2131
2132 function selection_style(name, value, priority) {
2133 return arguments.length > 1
2134 ? this.each((value == null
2135 ? styleRemove : typeof value === "function"
2136 ? styleFunction
2137 : styleConstant)(name, value, priority == null ? "" : priority))
2138 : styleValue(this.node(), name);
2139 }
2140
2141 function styleValue(node, name) {
2142 return node.style.getPropertyValue(name)
2143 || defaultView(node).getComputedStyle(node, null).getPropertyValue(name);
2144 }
2145
2146 function propertyRemove(name) {
2147 return function() {
2148 delete this[name];
2149 };
2150 }
2151
2152 function propertyConstant(name, value) {
2153 return function() {
2154 this[name] = value;
2155 };
2156 }
2157
2158 function propertyFunction(name, value) {
2159 return function() {
2160 var v = value.apply(this, arguments);
2161 if (v == null) delete this[name];
2162 else this[name] = v;
2163 };
2164 }
2165
2166 function selection_property(name, value) {
2167 return arguments.length > 1
2168 ? this.each((value == null
2169 ? propertyRemove : typeof value === "function"
2170 ? propertyFunction
2171 : propertyConstant)(name, value))
2172 : this.node()[name];
2173 }
2174
2175 function classArray(string) {
2176 return string.trim().split(/^|\s+/);
2177 }
2178
2179 function classList(node) {
2180 return node.classList || new ClassList(node);
2181 }
2182
2183 function ClassList(node) {
2184 this._node = node;
2185 this._names = classArray(node.getAttribute("class") || "");
2186 }
2187
2188 ClassList.prototype = {
2189 add: function(name) {
2190 var i = this._names.indexOf(name);
2191 if (i < 0) {
2192 this._names.push(name);
2193 this._node.setAttribute("class", this._names.join(" "));
2194 }
2195 },
2196 remove: function(name) {
2197 var i = this._names.indexOf(name);
2198 if (i >= 0) {
2199 this._names.splice(i, 1);
2200 this._node.setAttribute("class", this._names.join(" "));
2201 }
2202 },
2203 contains: function(name) {
2204 return this._names.indexOf(name) >= 0;
2205 }
2206 };
2207
2208 function classedAdd(node, names) {
2209 var list = classList(node), i = -1, n = names.length;
2210 while (++i < n) list.add(names[i]);
2211 }
2212
2213 function classedRemove(node, names) {
2214 var list = classList(node), i = -1, n = names.length;
2215 while (++i < n) list.remove(names[i]);
2216 }
2217
2218 function classedTrue(names) {
2219 return function() {
2220 classedAdd(this, names);
2221 };
2222 }
2223
2224 function classedFalse(names) {
2225 return function() {
2226 classedRemove(this, names);
2227 };
2228 }
2229
2230 function classedFunction(names, value) {
2231 return function() {
2232 (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
2233 };
2234 }
2235
2236 function selection_classed(name, value) {
2237 var names = classArray(name + "");
2238
2239 if (arguments.length < 2) {
2240 var list = classList(this.node()), i = -1, n = names.length;
2241 while (++i < n) if (!list.contains(names[i])) return false;
2242 return true;
2243 }
2244
2245 return this.each((typeof value === "function"
2246 ? classedFunction : value
2247 ? classedTrue
2248 : classedFalse)(names, value));
2249 }
2250
2251 function textRemove() {
2252 this.textContent = "";
2253 }
2254
2255 function textConstant(value) {
2256 return function() {
2257 this.textContent = value;
2258 };
2259 }
2260
2261 function textFunction(value) {
2262 return function() {
2263 var v = value.apply(this, arguments);
2264 this.textContent = v == null ? "" : v;
2265 };
2266 }
2267
2268 function selection_text(value) {
2269 return arguments.length
2270 ? this.each(value == null
2271 ? textRemove : (typeof value === "function"
2272 ? textFunction
2273 : textConstant)(value))
2274 : this.node().textContent;
2275 }
2276
2277 function htmlRemove() {
2278 this.innerHTML = "";
2279 }
2280
2281 function htmlConstant(value) {
2282 return function() {
2283 this.innerHTML = value;
2284 };
2285 }
2286
2287 function htmlFunction(value) {
2288 return function() {
2289 var v = value.apply(this, arguments);
2290 this.innerHTML = v == null ? "" : v;
2291 };
2292 }
2293
2294 function selection_html(value) {
2295 return arguments.length
2296 ? this.each(value == null
2297 ? htmlRemove : (typeof value === "function"
2298 ? htmlFunction
2299 : htmlConstant)(value))
2300 : this.node().innerHTML;
2301 }
2302
2303 function raise() {
2304 if (this.nextSibling) this.parentNode.appendChild(this);
2305 }
2306
2307 function selection_raise() {
2308 return this.each(raise);
2309 }
2310
2311 function lower() {
2312 if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
2313 }
2314
2315 function selection_lower() {
2316 return this.each(lower);
2317 }
2318
2319 function selection_append(name) {
2320 var create = typeof name === "function" ? name : creator(name);
2321 return this.select(function() {
2322 return this.appendChild(create.apply(this, arguments));
2323 });
2324 }
2325
2326 function constantNull() {
2327 return null;
2328 }
2329
2330 function selection_insert(name, before) {
2331 var create = typeof name === "function" ? name : creator(name),
2332 select = before == null ? constantNull : typeof before === "function" ? before : selector(before);
2333 return this.select(function() {
2334 return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
2335 });
2336 }
2337
2338 function remove() {
2339 var parent = this.parentNode;
2340 if (parent) parent.removeChild(this);
2341 }
2342
2343 function selection_remove() {
2344 return this.each(remove);
2345 }
2346
2347 function selection_cloneShallow() {
2348 var clone = this.cloneNode(false), parent = this.parentNode;
2349 return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
2350 }
2351
2352 function selection_cloneDeep() {
2353 var clone = this.cloneNode(true), parent = this.parentNode;
2354 return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
2355 }
2356
2357 function selection_clone(deep) {
2358 return this.select(deep ? selection_cloneDeep : selection_cloneShallow);
2359 }
2360
2361 function selection_datum(value) {
2362 return arguments.length
2363 ? this.property("__data__", value)
2364 : this.node().__data__;
2365 }
2366
2367 var filterEvents = {};
2368
2369 var event = null;
2370
2371 if (typeof document !== "undefined") {
2372 var element = document.documentElement;
2373 if (!("onmouseenter" in element)) {
2374 filterEvents = {mouseenter: "mouseover", mouseleave: "mouseout"};
2375 }
2376 }
2377
2378 function filterContextListener(listener, index, group) {
2379 listener = contextListener(listener, index, group);
2380 return function(event) {
2381 var related = event.relatedTarget;
2382 if (!related || (related !== this && !(related.compareDocumentPosition(this) & 8))) {
2383 listener.call(this, event);
2384 }
2385 };
2386 }
2387
2388 function contextListener(listener, index, group) {
2389 return function(event1) {
2390 var event0 = event; // Events can be reentrant (e.g., focus).
2391 event = event1;
2392 try {
2393 listener.call(this, this.__data__, index, group);
2394 } finally {
2395 event = event0;
2396 }
2397 };
2398 }
2399
2400 function parseTypenames(typenames) {
2401 return typenames.trim().split(/^|\s+/).map(function(t) {
2402 var name = "", i = t.indexOf(".");
2403 if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
2404 return {type: t, name: name};
2405 });
2406 }
2407
2408 function onRemove(typename) {
2409 return function() {
2410 var on = this.__on;
2411 if (!on) return;
2412 for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
2413 if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
2414 this.removeEventListener(o.type, o.listener, o.capture);
2415 } else {
2416 on[++i] = o;
2417 }
2418 }
2419 if (++i) on.length = i;
2420 else delete this.__on;
2421 };
2422 }
2423
2424 function onAdd(typename, value, capture) {
2425 var wrap = filterEvents.hasOwnProperty(typename.type) ? filterContextListener : contextListener;
2426 return function(d, i, group) {
2427 var on = this.__on, o, listener = wrap(value, i, group);
2428 if (on) for (var j = 0, m = on.length; j < m; ++j) {
2429 if ((o = on[j]).type === typename.type && o.name === typename.name) {
2430 this.removeEventListener(o.type, o.listener, o.capture);
2431 this.addEventListener(o.type, o.listener = listener, o.capture = capture);
2432 o.value = value;
2433 return;
2434 }
2435 }
2436 this.addEventListener(typename.type, listener, capture);
2437 o = {type: typename.type, name: typename.name, value: value, listener: listener, capture: capture};
2438 if (!on) this.__on = [o];
2439 else on.push(o);
2440 };
2441 }
2442
2443 function selection_on(typename, value, capture) {
2444 var typenames = parseTypenames(typename + ""), i, n = typenames.length, t;
2445
2446 if (arguments.length < 2) {
2447 var on = this.node().__on;
2448 if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
2449 for (i = 0, o = on[j]; i < n; ++i) {
2450 if ((t = typenames[i]).type === o.type && t.name === o.name) {
2451 return o.value;
2452 }
2453 }
2454 }
2455 return;
2456 }
2457
2458 on = value ? onAdd : onRemove;
2459 if (capture == null) capture = false;
2460 for (i = 0; i < n; ++i) this.each(on(typenames[i], value, capture));
2461 return this;
2462 }
2463
2464 function dispatchEvent(node, type, params) {
2465 var window = defaultView(node),
2466 event = window.CustomEvent;
2467
2468 if (typeof event === "function") {
2469 event = new event(type, params);
2470 } else {
2471 event = window.document.createEvent("Event");
2472 if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;
2473 else event.initEvent(type, false, false);
2474 }
2475
2476 node.dispatchEvent(event);
2477 }
2478
2479 function dispatchConstant(type, params) {
2480 return function() {
2481 return dispatchEvent(this, type, params);
2482 };
2483 }
2484
2485 function dispatchFunction(type, params) {
2486 return function() {
2487 return dispatchEvent(this, type, params.apply(this, arguments));
2488 };
2489 }
2490
2491 function selection_dispatch(type, params) {
2492 return this.each((typeof params === "function"
2493 ? dispatchFunction
2494 : dispatchConstant)(type, params));
2495 }
2496
2497 var root = [null];
2498
2499 function Selection(groups, parents) {
2500 this._groups = groups;
2501 this._parents = parents;
2502 }
2503
2504 Selection.prototype = {
2505 constructor: Selection,
2506 select: selection_select,
2507 selectAll: selection_selectAll,
2508 filter: selection_filter,
2509 data: selection_data,
2510 enter: selection_enter,
2511 exit: selection_exit,
2512 join: selection_join,
2513 merge: selection_merge,
2514 order: selection_order,
2515 sort: selection_sort,
2516 call: selection_call,
2517 nodes: selection_nodes,
2518 node: selection_node,
2519 size: selection_size,
2520 empty: selection_empty,
2521 each: selection_each,
2522 attr: selection_attr,
2523 style: selection_style,
2524 property: selection_property,
2525 classed: selection_classed,
2526 text: selection_text,
2527 html: selection_html,
2528 raise: selection_raise,
2529 lower: selection_lower,
2530 append: selection_append,
2531 insert: selection_insert,
2532 remove: selection_remove,
2533 clone: selection_clone,
2534 datum: selection_datum,
2535 on: selection_on,
2536 dispatch: selection_dispatch
2537 };
2538
2539 function d3_select(selector) {
2540 return typeof selector === "string"
2541 ? new Selection([[document.querySelector(selector)]], [document.documentElement])
2542 : new Selection([[selector]], root);
2543 }
2544
2545 function sourceEvent() {
2546 var current = event, source;
2547 while (source = current.sourceEvent) current = source;
2548 return current;
2549 }
2550
2551 function point(node, event) {
2552 var svg = node.ownerSVGElement || node;
2553
2554 if (svg.createSVGPoint) {
2555 var point = svg.createSVGPoint();
2556 point.x = event.clientX, point.y = event.clientY;
2557 point = point.matrixTransform(node.getScreenCTM().inverse());
2558 return [point.x, point.y];
2559 }
2560
2561 var rect = node.getBoundingClientRect();
2562 return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
2563 }
2564
2565 function d3_mouse(node) {
2566 var event = sourceEvent();
2567 if (event.changedTouches) event = event.changedTouches[0];
2568 return point(node, event);
2569 }
2570
2571 var slice$1 = Array.prototype.slice;
2572
2573 function identity$1(x) {
2574 return x;
2575 }
2576
2577 var top = 1,
2578 right = 2,
2579 bottom = 3,
2580 left = 4,
2581 epsilon = 1e-6;
2582
2583 function translateX(x) {
2584 return "translate(" + (x + 0.5) + ",0)";
2585 }
2586
2587 function translateY(y) {
2588 return "translate(0," + (y + 0.5) + ")";
2589 }
2590
2591 function number$1(scale) {
2592 return function(d) {
2593 return +scale(d);
2594 };
2595 }
2596
2597 function center(scale) {
2598 var offset = Math.max(0, scale.bandwidth() - 1) / 2; // Adjust for 0.5px offset.
2599 if (scale.round()) offset = Math.round(offset);
2600 return function(d) {
2601 return +scale(d) + offset;
2602 };
2603 }
2604
2605 function entering() {
2606 return !this.__axis;
2607 }
2608
2609 function axis(orient, scale) {
2610 var tickArguments = [],
2611 tickValues = null,
2612 tickFormat = null,
2613 tickSizeInner = 6,
2614 tickSizeOuter = 6,
2615 tickPadding = 3,
2616 k = orient === top || orient === left ? -1 : 1,
2617 x = orient === left || orient === right ? "x" : "y",
2618 transform = orient === top || orient === bottom ? translateX : translateY;
2619
2620 function axis(context) {
2621 var values = tickValues == null ? (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain()) : tickValues,
2622 format = tickFormat == null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : identity$1) : tickFormat,
2623 spacing = Math.max(tickSizeInner, 0) + tickPadding,
2624 range = scale.range(),
2625 range0 = +range[0] + 0.5,
2626 range1 = +range[range.length - 1] + 0.5,
2627 position = (scale.bandwidth ? center : number$1)(scale.copy()),
2628 selection = context.selection ? context.selection() : context,
2629 path = selection.selectAll(".domain").data([null]),
2630 tick = selection.selectAll(".tick").data(values, scale).order(),
2631 tickExit = tick.exit(),
2632 tickEnter = tick.enter().append("g").attr("class", "tick"),
2633 line = tick.select("line"),
2634 text = tick.select("text");
2635
2636 path = path.merge(path.enter().insert("path", ".tick")
2637 .attr("class", "domain")
2638 .attr("stroke", "currentColor"));
2639
2640 tick = tick.merge(tickEnter);
2641
2642 line = line.merge(tickEnter.append("line")
2643 .attr("stroke", "currentColor")
2644 .attr(x + "2", k * tickSizeInner));
2645
2646 text = text.merge(tickEnter.append("text")
2647 .attr("fill", "currentColor")
2648 .attr(x, k * spacing)
2649 .attr("dy", orient === top ? "0em" : orient === bottom ? "0.71em" : "0.32em"));
2650
2651 if (context !== selection) {
2652 path = path.transition(context);
2653 tick = tick.transition(context);
2654 line = line.transition(context);
2655 text = text.transition(context);
2656
2657 tickExit = tickExit.transition(context)
2658 .attr("opacity", epsilon)
2659 .attr("transform", function(d) { return isFinite(d = position(d)) ? transform(d) : this.getAttribute("transform"); });
2660
2661 tickEnter
2662 .attr("opacity", epsilon)
2663 .attr("transform", function(d) { var p = this.parentNode.__axis; return transform(p && isFinite(p = p(d)) ? p : position(d)); });
2664 }
2665
2666 tickExit.remove();
2667
2668 path
2669 .attr("d", orient === left || orient == right
2670 ? (tickSizeOuter ? "M" + k * tickSizeOuter + "," + range0 + "H0.5V" + range1 + "H" + k * tickSizeOuter : "M0.5," + range0 + "V" + range1)
2671 : (tickSizeOuter ? "M" + range0 + "," + k * tickSizeOuter + "V0.5H" + range1 + "V" + k * tickSizeOuter : "M" + range0 + ",0.5H" + range1));
2672
2673 tick
2674 .attr("opacity", 1)
2675 .attr("transform", function(d) { return transform(position(d)); });
2676
2677 line
2678 .attr(x + "2", k * tickSizeInner);
2679
2680 text
2681 .attr(x, k * spacing)
2682 .text(format);
2683
2684 selection.filter(entering)
2685 .attr("fill", "none")
2686 .attr("font-size", 10)
2687 .attr("font-family", "sans-serif")
2688 .attr("text-anchor", orient === right ? "start" : orient === left ? "end" : "middle");
2689
2690 selection
2691 .each(function() { this.__axis = position; });
2692 }
2693
2694 axis.scale = function(_) {
2695 return arguments.length ? (scale = _, axis) : scale;
2696 };
2697
2698 axis.ticks = function() {
2699 return tickArguments = slice$1.call(arguments), axis;
2700 };
2701
2702 axis.tickArguments = function(_) {
2703 return arguments.length ? (tickArguments = _ == null ? [] : slice$1.call(_), axis) : tickArguments.slice();
2704 };
2705
2706 axis.tickValues = function(_) {
2707 return arguments.length ? (tickValues = _ == null ? null : slice$1.call(_), axis) : tickValues && tickValues.slice();
2708 };
2709
2710 axis.tickFormat = function(_) {
2711 return arguments.length ? (tickFormat = _, axis) : tickFormat;
2712 };
2713
2714 axis.tickSize = function(_) {
2715 return arguments.length ? (tickSizeInner = tickSizeOuter = +_, axis) : tickSizeInner;
2716 };
2717
2718 axis.tickSizeInner = function(_) {
2719 return arguments.length ? (tickSizeInner = +_, axis) : tickSizeInner;
2720 };
2721
2722 axis.tickSizeOuter = function(_) {
2723 return arguments.length ? (tickSizeOuter = +_, axis) : tickSizeOuter;
2724 };
2725
2726 axis.tickPadding = function(_) {
2727 return arguments.length ? (tickPadding = +_, axis) : tickPadding;
2728 };
2729
2730 return axis;
2731 }
2732
2733 function axisBottom(scale) {
2734 return axis(bottom, scale);
2735 }
2736
2737 function ascending(a, b) {
2738 return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
2739 }
2740
2741 function bisector(compare) {
2742 if (compare.length === 1) compare = ascendingComparator(compare);
2743 return {
2744 left: function(a, x, lo, hi) {
2745 if (lo == null) lo = 0;
2746 if (hi == null) hi = a.length;
2747 while (lo < hi) {
2748 var mid = lo + hi >>> 1;
2749 if (compare(a[mid], x) < 0) lo = mid + 1;
2750 else hi = mid;
2751 }
2752 return lo;
2753 },
2754 right: function(a, x, lo, hi) {
2755 if (lo == null) lo = 0;
2756 if (hi == null) hi = a.length;
2757 while (lo < hi) {
2758 var mid = lo + hi >>> 1;
2759 if (compare(a[mid], x) > 0) hi = mid;
2760 else lo = mid + 1;
2761 }
2762 return lo;
2763 }
2764 };
2765 }
2766
2767 function ascendingComparator(f) {
2768 return function(d, x) {
2769 return ascending(f(d), x);
2770 };
2771 }
2772
2773 var ascendingBisect = bisector(ascending);
2774 var bisectRight = ascendingBisect.right;
2775
2776 var e10 = Math.sqrt(50),
2777 e5 = Math.sqrt(10),
2778 e2 = Math.sqrt(2);
2779
2780 function ticks(start, stop, count) {
2781 var reverse,
2782 i = -1,
2783 n,
2784 ticks,
2785 step;
2786
2787 stop = +stop, start = +start, count = +count;
2788 if (start === stop && count > 0) return [start];
2789 if (reverse = stop < start) n = start, start = stop, stop = n;
2790 if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return [];
2791
2792 if (step > 0) {
2793 start = Math.ceil(start / step);
2794 stop = Math.floor(stop / step);
2795 ticks = new Array(n = Math.ceil(stop - start + 1));
2796 while (++i < n) ticks[i] = (start + i) * step;
2797 } else {
2798 start = Math.floor(start * step);
2799 stop = Math.ceil(stop * step);
2800 ticks = new Array(n = Math.ceil(start - stop + 1));
2801 while (++i < n) ticks[i] = (start - i) / step;
2802 }
2803
2804 if (reverse) ticks.reverse();
2805
2806 return ticks;
2807 }
2808
2809 function tickIncrement(start, stop, count) {
2810 var step = (stop - start) / Math.max(0, count),
2811 power = Math.floor(Math.log(step) / Math.LN10),
2812 error = step / Math.pow(10, power);
2813 return power >= 0
2814 ? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power)
2815 : -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1);
2816 }
2817
2818 function tickStep(start, stop, count) {
2819 var step0 = Math.abs(stop - start) / Math.max(0, count),
2820 step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
2821 error = step0 / step1;
2822 if (error >= e10) step1 *= 10;
2823 else if (error >= e5) step1 *= 5;
2824 else if (error >= e2) step1 *= 2;
2825 return stop < start ? -step1 : step1;
2826 }
2827
2828 function constant$1(x) {
2829 return function() {
2830 return x;
2831 };
2832 }
2833
2834 function linear$1(a, d) {
2835 return function(t) {
2836 return a + t * d;
2837 };
2838 }
2839
2840 function exponential(a, b, y) {
2841 return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {
2842 return Math.pow(a + t * b, y);
2843 };
2844 }
2845
2846 function gamma(y) {
2847 return (y = +y) === 1 ? nogamma : function(a, b) {
2848 return b - a ? exponential(a, b, y) : constant$1(isNaN(a) ? b : a);
2849 };
2850 }
2851
2852 function nogamma(a, b) {
2853 var d = b - a;
2854 return d ? linear$1(a, d) : constant$1(isNaN(a) ? b : a);
2855 }
2856
2857 var rgb = (function rgbGamma(y) {
2858 var color = gamma(y);
2859
2860 function rgb(start, end) {
2861 var r = color((start = rgb$1(start)).r, (end = rgb$1(end)).r),
2862 g = color(start.g, end.g),
2863 b = color(start.b, end.b),
2864 opacity = nogamma(start.opacity, end.opacity);
2865 return function(t) {
2866 start.r = r(t);
2867 start.g = g(t);
2868 start.b = b(t);
2869 start.opacity = opacity(t);
2870 return start + "";
2871 };
2872 }
2873
2874 rgb.gamma = rgbGamma;
2875
2876 return rgb;
2877 })(1);
2878
2879 function numberArray(a, b) {
2880 if (!b) b = [];
2881 var n = a ? Math.min(b.length, a.length) : 0,
2882 c = b.slice(),
2883 i;
2884 return function(t) {
2885 for (i = 0; i < n; ++i) c[i] = a[i] * (1 - t) + b[i] * t;
2886 return c;
2887 };
2888 }
2889
2890 function isNumberArray(x) {
2891 return ArrayBuffer.isView(x) && !(x instanceof DataView);
2892 }
2893
2894 function genericArray(a, b) {
2895 var nb = b ? b.length : 0,
2896 na = a ? Math.min(nb, a.length) : 0,
2897 x = new Array(na),
2898 c = new Array(nb),
2899 i;
2900
2901 for (i = 0; i < na; ++i) x[i] = interpolateValue(a[i], b[i]);
2902 for (; i < nb; ++i) c[i] = b[i];
2903
2904 return function(t) {
2905 for (i = 0; i < na; ++i) c[i] = x[i](t);
2906 return c;
2907 };
2908 }
2909
2910 function date(a, b) {
2911 var d = new Date;
2912 return a = +a, b = +b, function(t) {
2913 return d.setTime(a * (1 - t) + b * t), d;
2914 };
2915 }
2916
2917 function reinterpolate(a, b) {
2918 return a = +a, b = +b, function(t) {
2919 return a * (1 - t) + b * t;
2920 };
2921 }
2922
2923 function object(a, b) {
2924 var i = {},
2925 c = {},
2926 k;
2927
2928 if (a === null || typeof a !== "object") a = {};
2929 if (b === null || typeof b !== "object") b = {};
2930
2931 for (k in b) {
2932 if (k in a) {
2933 i[k] = interpolateValue(a[k], b[k]);
2934 } else {
2935 c[k] = b[k];
2936 }
2937 }
2938
2939 return function(t) {
2940 for (k in i) c[k] = i[k](t);
2941 return c;
2942 };
2943 }
2944
2945 var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,
2946 reB = new RegExp(reA.source, "g");
2947
2948 function zero(b) {
2949 return function() {
2950 return b;
2951 };
2952 }
2953
2954 function one(b) {
2955 return function(t) {
2956 return b(t) + "";
2957 };
2958 }
2959
2960 function string(a, b) {
2961 var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b
2962 am, // current match in a
2963 bm, // current match in b
2964 bs, // string preceding current number in b, if any
2965 i = -1, // index in s
2966 s = [], // string constants and placeholders
2967 q = []; // number interpolators
2968
2969 // Coerce inputs to strings.
2970 a = a + "", b = b + "";
2971
2972 // Interpolate pairs of numbers in a & b.
2973 while ((am = reA.exec(a))
2974 && (bm = reB.exec(b))) {
2975 if ((bs = bm.index) > bi) { // a string precedes the next number in b
2976 bs = b.slice(bi, bs);
2977 if (s[i]) s[i] += bs; // coalesce with previous string
2978 else s[++i] = bs;
2979 }
2980 if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match
2981 if (s[i]) s[i] += bm; // coalesce with previous string
2982 else s[++i] = bm;
2983 } else { // interpolate non-matching numbers
2984 s[++i] = null;
2985 q.push({i: i, x: reinterpolate(am, bm)});
2986 }
2987 bi = reB.lastIndex;
2988 }
2989
2990 // Add remains of b.
2991 if (bi < b.length) {
2992 bs = b.slice(bi);
2993 if (s[i]) s[i] += bs; // coalesce with previous string
2994 else s[++i] = bs;
2995 }
2996
2997 // Special optimization for only a single match.
2998 // Otherwise, interpolate each of the numbers and rejoin the string.
2999 return s.length < 2 ? (q[0]
3000 ? one(q[0].x)
3001 : zero(b))
3002 : (b = q.length, function(t) {
3003 for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
3004 return s.join("");
3005 });
3006 }
3007
3008 function interpolateValue(a, b) {
3009 var t = typeof b, c;
3010 return b == null || t === "boolean" ? constant$1(b)
3011 : (t === "number" ? reinterpolate
3012 : t === "string" ? ((c = color(b)) ? (b = c, rgb) : string)
3013 : b instanceof color ? rgb
3014 : b instanceof Date ? date
3015 : isNumberArray(b) ? numberArray
3016 : Array.isArray(b) ? genericArray
3017 : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object
3018 : reinterpolate)(a, b);
3019 }
3020
3021 function interpolateRound(a, b) {
3022 return a = +a, b = +b, function(t) {
3023 return Math.round(a * (1 - t) + b * t);
3024 };
3025 }
3026
3027 var array = Array.prototype;
3028
3029 var map$1 = array.map;
3030 var slice = array.slice;
3031
3032 function constant(x) {
3033 return function() {
3034 return x;
3035 };
3036 }
3037
3038 function number(x) {
3039 return +x;
3040 }
3041
3042 var unit = [0, 1];
3043
3044 function deinterpolateLinear(a, b) {
3045 return (b -= (a = +a))
3046 ? function(x) { return (x - a) / b; }
3047 : constant(b);
3048 }
3049
3050 function deinterpolateClamp(deinterpolate) {
3051 return function(a, b) {
3052 var d = deinterpolate(a = +a, b = +b);
3053 return function(x) { return x <= a ? 0 : x >= b ? 1 : d(x); };
3054 };
3055 }
3056
3057 function reinterpolateClamp(reinterpolate) {
3058 return function(a, b) {
3059 var r = reinterpolate(a = +a, b = +b);
3060 return function(t) { return t <= 0 ? a : t >= 1 ? b : r(t); };
3061 };
3062 }
3063
3064 function bimap(domain, range, deinterpolate, reinterpolate) {
3065 var d0 = domain[0], d1 = domain[1], r0 = range[0], r1 = range[1];
3066 if (d1 < d0) d0 = deinterpolate(d1, d0), r0 = reinterpolate(r1, r0);
3067 else d0 = deinterpolate(d0, d1), r0 = reinterpolate(r0, r1);
3068 return function(x) { return r0(d0(x)); };
3069 }
3070
3071 function polymap(domain, range, deinterpolate, reinterpolate) {
3072 var j = Math.min(domain.length, range.length) - 1,
3073 d = new Array(j),
3074 r = new Array(j),
3075 i = -1;
3076
3077 // Reverse descending domains.
3078 if (domain[j] < domain[0]) {
3079 domain = domain.slice().reverse();
3080 range = range.slice().reverse();
3081 }
3082
3083 while (++i < j) {
3084 d[i] = deinterpolate(domain[i], domain[i + 1]);
3085 r[i] = reinterpolate(range[i], range[i + 1]);
3086 }
3087
3088 return function(x) {
3089 var i = bisectRight(domain, x, 1, j) - 1;
3090 return r[i](d[i](x));
3091 };
3092 }
3093
3094 function copy(source, target) {
3095 return target
3096 .domain(source.domain())
3097 .range(source.range())
3098 .interpolate(source.interpolate())
3099 .clamp(source.clamp());
3100 }
3101
3102 // deinterpolate(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
3103 // reinterpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding domain value x in [a,b].
3104 function continuous(deinterpolate, reinterpolate) {
3105 var domain = unit,
3106 range = unit,
3107 interpolate = interpolateValue,
3108 clamp = false,
3109 piecewise,
3110 output,
3111 input;
3112
3113 function rescale() {
3114 piecewise = Math.min(domain.length, range.length) > 2 ? polymap : bimap;
3115 output = input = null;
3116 return scale;
3117 }
3118
3119 function scale(x) {
3120 return (output || (output = piecewise(domain, range, clamp ? deinterpolateClamp(deinterpolate) : deinterpolate, interpolate)))(+x);
3121 }
3122
3123 scale.invert = function(y) {
3124 return (input || (input = piecewise(range, domain, deinterpolateLinear, clamp ? reinterpolateClamp(reinterpolate) : reinterpolate)))(+y);
3125 };
3126
3127 scale.domain = function(_) {
3128 return arguments.length ? (domain = map$1.call(_, number), rescale()) : domain.slice();
3129 };
3130
3131 scale.range = function(_) {
3132 return arguments.length ? (range = slice.call(_), rescale()) : range.slice();
3133 };
3134
3135 scale.rangeRound = function(_) {
3136 return range = slice.call(_), interpolate = interpolateRound, rescale();
3137 };
3138
3139 scale.clamp = function(_) {
3140 return arguments.length ? (clamp = !!_, rescale()) : clamp;
3141 };
3142
3143 scale.interpolate = function(_) {
3144 return arguments.length ? (interpolate = _, rescale()) : interpolate;
3145 };
3146
3147 return rescale();
3148 }
3149
3150 function formatDecimal(x) {
3151 return Math.abs(x = Math.round(x)) >= 1e21
3152 ? x.toLocaleString("en").replace(/,/g, "")
3153 : x.toString(10);
3154 }
3155
3156 // Computes the decimal coefficient and exponent of the specified number x with
3157 // significant digits p, where x is positive and p is in [1, 21] or undefined.
3158 // For example, formatDecimalParts(1.23) returns ["123", 0].
3159 function formatDecimalParts(x, p) {
3160 if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
3161 var i, coefficient = x.slice(0, i);
3162
3163 // The string returned by toExponential either has the form \d\.\d+e[-+]\d+
3164 // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
3165 return [
3166 coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
3167 +x.slice(i + 1)
3168 ];
3169 }
3170
3171 function exponent(x) {
3172 return x = formatDecimalParts(Math.abs(x)), x ? x[1] : NaN;
3173 }
3174
3175 function formatGroup(grouping, thousands) {
3176 return function(value, width) {
3177 var i = value.length,
3178 t = [],
3179 j = 0,
3180 g = grouping[0],
3181 length = 0;
3182
3183 while (i > 0 && g > 0) {
3184 if (length + g + 1 > width) g = Math.max(1, width - length);
3185 t.push(value.substring(i -= g, i + g));
3186 if ((length += g + 1) > width) break;
3187 g = grouping[j = (j + 1) % grouping.length];
3188 }
3189
3190 return t.reverse().join(thousands);
3191 };
3192 }
3193
3194 function formatNumerals(numerals) {
3195 return function(value) {
3196 return value.replace(/[0-9]/g, function(i) {
3197 return numerals[+i];
3198 });
3199 };
3200 }
3201
3202 // [[fill]align][sign][symbol][0][width][,][.precision][~][type]
3203 var re = /^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;
3204
3205 function formatSpecifier(specifier) {
3206 if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
3207 var match;
3208 return new FormatSpecifier({
3209 fill: match[1],
3210 align: match[2],
3211 sign: match[3],
3212 symbol: match[4],
3213 zero: match[5],
3214 width: match[6],
3215 comma: match[7],
3216 precision: match[8] && match[8].slice(1),
3217 trim: match[9],
3218 type: match[10]
3219 });
3220 }
3221
3222 formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof
3223
3224 function FormatSpecifier(specifier) {
3225 this.fill = specifier.fill === undefined ? " " : specifier.fill + "";
3226 this.align = specifier.align === undefined ? ">" : specifier.align + "";
3227 this.sign = specifier.sign === undefined ? "-" : specifier.sign + "";
3228 this.symbol = specifier.symbol === undefined ? "" : specifier.symbol + "";
3229 this.zero = !!specifier.zero;
3230 this.width = specifier.width === undefined ? undefined : +specifier.width;
3231 this.comma = !!specifier.comma;
3232 this.precision = specifier.precision === undefined ? undefined : +specifier.precision;
3233 this.trim = !!specifier.trim;
3234 this.type = specifier.type === undefined ? "" : specifier.type + "";
3235 }
3236
3237 FormatSpecifier.prototype.toString = function() {
3238 return this.fill
3239 + this.align
3240 + this.sign
3241 + this.symbol
3242 + (this.zero ? "0" : "")
3243 + (this.width === undefined ? "" : Math.max(1, this.width | 0))
3244 + (this.comma ? "," : "")
3245 + (this.precision === undefined ? "" : "." + Math.max(0, this.precision | 0))
3246 + (this.trim ? "~" : "")
3247 + this.type;
3248 };
3249
3250 // Trims insignificant zeros, e.g., replaces 1.2000k with 1.2k.
3251 function formatTrim(s) {
3252 out: for (var n = s.length, i = 1, i0 = -1, i1; i < n; ++i) {
3253 switch (s[i]) {
3254 case ".": i0 = i1 = i; break;
3255 case "0": if (i0 === 0) i0 = i; i1 = i; break;
3256 default: if (!+s[i]) break out; if (i0 > 0) i0 = 0; break;
3257 }
3258 }
3259 return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s;
3260 }
3261
3262 var prefixExponent;
3263
3264 function formatPrefixAuto(x, p) {
3265 var d = formatDecimalParts(x, p);
3266 if (!d) return x + "";
3267 var coefficient = d[0],
3268 exponent = d[1],
3269 i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
3270 n = coefficient.length;
3271 return i === n ? coefficient
3272 : i > n ? coefficient + new Array(i - n + 1).join("0")
3273 : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i)
3274 : "0." + new Array(1 - i).join("0") + formatDecimalParts(x, Math.max(0, p + i - 1))[0]; // less than 1y!
3275 }
3276
3277 function formatRounded(x, p) {
3278 var d = formatDecimalParts(x, p);
3279 if (!d) return x + "";
3280 var coefficient = d[0],
3281 exponent = d[1];
3282 return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient
3283 : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1)
3284 : coefficient + new Array(exponent - coefficient.length + 2).join("0");
3285 }
3286
3287 var formatTypes = {
3288 "%": function(x, p) { return (x * 100).toFixed(p); },
3289 "b": function(x) { return Math.round(x).toString(2); },
3290 "c": function(x) { return x + ""; },
3291 "d": formatDecimal,
3292 "e": function(x, p) { return x.toExponential(p); },
3293 "f": function(x, p) { return x.toFixed(p); },
3294 "g": function(x, p) { return x.toPrecision(p); },
3295 "o": function(x) { return Math.round(x).toString(8); },
3296 "p": function(x, p) { return formatRounded(x * 100, p); },
3297 "r": formatRounded,
3298 "s": formatPrefixAuto,
3299 "X": function(x) { return Math.round(x).toString(16).toUpperCase(); },
3300 "x": function(x) { return Math.round(x).toString(16); }
3301 };
3302
3303 function identity(x) {
3304 return x;
3305 }
3306
3307 var map = Array.prototype.map,
3308 prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];
3309
3310 function formatLocale(locale) {
3311 var group = locale.grouping === undefined || locale.thousands === undefined ? identity : formatGroup(map.call(locale.grouping, Number), locale.thousands + ""),
3312 currencyPrefix = locale.currency === undefined ? "" : locale.currency[0] + "",
3313 currencySuffix = locale.currency === undefined ? "" : locale.currency[1] + "",
3314 decimal = locale.decimal === undefined ? "." : locale.decimal + "",
3315 numerals = locale.numerals === undefined ? identity : formatNumerals(map.call(locale.numerals, String)),
3316 percent = locale.percent === undefined ? "%" : locale.percent + "",
3317 minus = locale.minus === undefined ? "-" : locale.minus + "",
3318 nan = locale.nan === undefined ? "NaN" : locale.nan + "";
3319
3320 function newFormat(specifier) {
3321 specifier = formatSpecifier(specifier);
3322
3323 var fill = specifier.fill,
3324 align = specifier.align,
3325 sign = specifier.sign,
3326 symbol = specifier.symbol,
3327 zero = specifier.zero,
3328 width = specifier.width,
3329 comma = specifier.comma,
3330 precision = specifier.precision,
3331 trim = specifier.trim,
3332 type = specifier.type;
3333
3334 // The "n" type is an alias for ",g".
3335 if (type === "n") comma = true, type = "g";
3336
3337 // The "" type, and any invalid type, is an alias for ".12~g".
3338 else if (!formatTypes[type]) precision === undefined && (precision = 12), trim = true, type = "g";
3339
3340 // If zero fill is specified, padding goes after sign and before digits.
3341 if (zero || (fill === "0" && align === "=")) zero = true, fill = "0", align = "=";
3342
3343 // Compute the prefix and suffix.
3344 // For SI-prefix, the suffix is lazily computed.
3345 var prefix = symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
3346 suffix = symbol === "$" ? currencySuffix : /[%p]/.test(type) ? percent : "";
3347
3348 // What format function should we use?
3349 // Is this an integer type?
3350 // Can this type generate exponential notation?
3351 var formatType = formatTypes[type],
3352 maybeSuffix = /[defgprs%]/.test(type);
3353
3354 // Set the default precision if not specified,
3355 // or clamp the specified precision to the supported range.
3356 // For significant precision, it must be in [1, 21].
3357 // For fixed precision, it must be in [0, 20].
3358 precision = precision === undefined ? 6
3359 : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))
3360 : Math.max(0, Math.min(20, precision));
3361
3362 function format(value) {
3363 var valuePrefix = prefix,
3364 valueSuffix = suffix,
3365 i, n, c;
3366
3367 if (type === "c") {
3368 valueSuffix = formatType(value) + valueSuffix;
3369 value = "";
3370 } else {
3371 value = +value;
3372
3373 // Determine the sign. -0 is not less than 0, but 1 / -0 is!
3374 var valueNegative = value < 0 || 1 / value < 0;
3375
3376 // Perform the initial formatting.
3377 value = isNaN(value) ? nan : formatType(Math.abs(value), precision);
3378
3379 // Trim insignificant zeros.
3380 if (trim) value = formatTrim(value);
3381
3382 // If a negative value rounds to zero after formatting, and no explicit positive sign is requested, hide the sign.
3383 if (valueNegative && +value === 0 && sign !== "+") valueNegative = false;
3384
3385 // Compute the prefix and suffix.
3386 valuePrefix = (valueNegative ? (sign === "(" ? sign : minus) : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
3387 valueSuffix = (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign === "(" ? ")" : "");
3388
3389 // Break the formatted value into the integer “value” part that can be
3390 // grouped, and fractional or exponential “suffix” part that is not.
3391 if (maybeSuffix) {
3392 i = -1, n = value.length;
3393 while (++i < n) {
3394 if (c = value.charCodeAt(i), 48 > c || c > 57) {
3395 valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
3396 value = value.slice(0, i);
3397 break;
3398 }
3399 }
3400 }
3401 }
3402
3403 // If the fill character is not "0", grouping is applied before padding.
3404 if (comma && !zero) value = group(value, Infinity);
3405
3406 // Compute the padding.
3407 var length = valuePrefix.length + value.length + valueSuffix.length,
3408 padding = length < width ? new Array(width - length + 1).join(fill) : "";
3409
3410 // If the fill character is "0", grouping is applied after padding.
3411 if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
3412
3413 // Reconstruct the final output based on the desired alignment.
3414 switch (align) {
3415 case "<": value = valuePrefix + value + valueSuffix + padding; break;
3416 case "=": value = valuePrefix + padding + value + valueSuffix; break;
3417 case "^": value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length); break;
3418 default: value = padding + valuePrefix + value + valueSuffix; break;
3419 }
3420
3421 return numerals(value);
3422 }
3423
3424 format.toString = function() {
3425 return specifier + "";
3426 };
3427
3428 return format;
3429 }
3430
3431 function formatPrefix(specifier, value) {
3432 var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
3433 e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
3434 k = Math.pow(10, -e),
3435 prefix = prefixes[8 + e / 3];
3436 return function(value) {
3437 return f(k * value) + prefix;
3438 };
3439 }
3440
3441 return {
3442 format: newFormat,
3443 formatPrefix: formatPrefix
3444 };
3445 }
3446
3447 var locale;
3448 var format;
3449 var formatPrefix;
3450
3451 defaultLocale({
3452 decimal: ".",
3453 thousands: ",",
3454 grouping: [3],
3455 currency: ["$", ""],
3456 minus: "-"
3457 });
3458
3459 function defaultLocale(definition) {
3460 locale = formatLocale(definition);
3461 format = locale.format;
3462 formatPrefix = locale.formatPrefix;
3463 return locale;
3464 }
3465
3466 function precisionFixed(step) {
3467 return Math.max(0, -exponent(Math.abs(step)));
3468 }
3469
3470 function precisionPrefix(step, value) {
3471 return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step)));
3472 }
3473
3474 function precisionRound(step, max) {
3475 step = Math.abs(step), max = Math.abs(max) - step;
3476 return Math.max(0, exponent(max) - exponent(step)) + 1;
3477 }
3478
3479 function tickFormat(domain, count, specifier) {
3480 var start = domain[0],
3481 stop = domain[domain.length - 1],
3482 step = tickStep(start, stop, count == null ? 10 : count),
3483 precision;
3484 specifier = formatSpecifier(specifier == null ? ",f" : specifier);
3485 switch (specifier.type) {
3486 case "s": {
3487 var value = Math.max(Math.abs(start), Math.abs(stop));
3488 if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;
3489 return formatPrefix(specifier, value);
3490 }
3491 case "":
3492 case "e":
3493 case "g":
3494 case "p":
3495 case "r": {
3496 if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
3497 break;
3498 }
3499 case "f":
3500 case "%": {
3501 if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
3502 break;
3503 }
3504 }
3505 return format(specifier);
3506 }
3507
3508 function linearish(scale) {
3509 var domain = scale.domain;
3510
3511 scale.ticks = function(count) {
3512 var d = domain();
3513 return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
3514 };
3515
3516 scale.tickFormat = function(count, specifier) {
3517 return tickFormat(domain(), count, specifier);
3518 };
3519
3520 scale.nice = function(count) {
3521 if (count == null) count = 10;
3522
3523 var d = domain(),
3524 i0 = 0,
3525 i1 = d.length - 1,
3526 start = d[i0],
3527 stop = d[i1],
3528 step;
3529
3530 if (stop < start) {
3531 step = start, start = stop, stop = step;
3532 step = i0, i0 = i1, i1 = step;
3533 }
3534
3535 step = tickIncrement(start, stop, count);
3536
3537 if (step > 0) {
3538 start = Math.floor(start / step) * step;
3539 stop = Math.ceil(stop / step) * step;
3540 step = tickIncrement(start, stop, count);
3541 } else if (step < 0) {
3542 start = Math.ceil(start * step) / step;
3543 stop = Math.floor(stop * step) / step;
3544 step = tickIncrement(start, stop, count);
3545 }
3546
3547 if (step > 0) {
3548 d[i0] = Math.floor(start / step) * step;
3549 d[i1] = Math.ceil(stop / step) * step;
3550 domain(d);
3551 } else if (step < 0) {
3552 d[i0] = Math.ceil(start * step) / step;
3553 d[i1] = Math.floor(stop * step) / step;
3554 domain(d);
3555 }
3556
3557 return scale;
3558 };
3559
3560 return scale;
3561 }
3562
3563 function linear() {
3564 var scale = continuous(deinterpolateLinear, reinterpolate);
3565
3566 scale.copy = function() {
3567 return copy(scale, linear());
3568 };
3569
3570 return linearish(scale);
3571 }
3572
3573 var VERSION = "1.4.2";
3574
3575 function Slider(selector) {
3576 this.container = d3_select(selector);
3577
3578 this._width = null;
3579 this._height = null;
3580
3581 this._handleRadius = 15;
3582 this._channelHeight = 5;
3583 this._channelRadius = null;
3584
3585 this._handleFill = "black";
3586 this._channelFill = "#eee";
3587
3588 this._margin = { top: null, left: null, right: null };
3589
3590 this._domain = [0, 1];
3591 this._value = null;
3592 this._snap = false;
3593
3594 this._scale = null;
3595 this._axis = false;
3596 this._ticks = null;
3597 this._tickFormat = null;
3598 this._tickSize = null;
3599
3600 this._label = null;
3601 this._labelSize = 18;
3602
3603 this._startLabel = null;
3604 this._startLabelBelow = false;
3605
3606 this._endLabel = null;
3607 this._endLabelBelow = false;
3608
3609 this._startEndLabelSize = 16;
3610
3611 this.handlers = { "change": [] };
3612 }
3613
3614 // Create accessor methods for all the _parameters defined by the constructor
3615 function accessor(k) {
3616 if (k.length > 0 && k.charAt(0) == "_") {
3617 Slider.prototype[k.substr(1)] = function(v) {
3618 if (typeof v == "undefined") return this[k];
3619 this[k] = v;
3620 return this;
3621 };
3622 }
3623 }
3624 var s = new Slider();
3625 for (var k in s) {
3626 accessor(k);
3627 }
3628
3629 // Special accessor function for margin
3630 Slider.prototype.margin = function Slider_margin(options) {
3631 if (!options) return this._margin;
3632 for (k in options) {
3633 if (k in this._margin) this._margin[k] = options[k];
3634 else throw "Slider.margin: unrecognised option " + k;
3635 }
3636 return this;
3637 };
3638
3639 // Attach event handlers
3640 Slider.prototype.on = function Slider_on(event, handler) {
3641 if (!(event in this.handlers)) throw "Slider.on: No such event: " + event;
3642 this.handlers[event].push(handler);
3643 return this;
3644 };
3645
3646 // Fire event
3647 Slider.prototype.fire = function Slider_fire(event, d) {
3648 if (!(event in this.handlers)) throw "Slider.fire: No such event: " + event;
3649 var handlers = this.handlers[event];
3650 for (var i = 0; i < handlers.length; i++) {
3651 handlers[i].call(this, d);
3652 }
3653 return this;
3654 };
3655
3656 // Binary search
3657 function closestValue(sorted_list, value, a, b) {
3658 if (typeof a === "undefined") a = 0;
3659 if (typeof b === "undefined") b = sorted_list.length;
3660
3661 if (b-a == 0) return value;
3662 if (b-a == 1) return sorted_list[a];
3663 if (b-a == 2) {
3664 var d1 = Math.abs(sorted_list[a] - value),
3665 d2 = Math.abs(sorted_list[a+1] - value);
3666 if (d1 <= d2) return sorted_list[a];
3667 else return sorted_list[a+1];
3668 }
3669
3670 var mid = a + Math.floor((b-a) / 2),
3671 mid_v = sorted_list[mid],
3672 pre = mid - 1,
3673 pre_v = sorted_list[pre];
3674 if (pre_v <= value && value <= mid_v) {
3675 return (Math.abs(pre_v - value) <= Math.abs(mid_v - value)) ? pre_v : mid_v;
3676 }
3677 if (mid_v <= value) return closestValue(sorted_list, value, mid, b);
3678 else return closestValue(sorted_list, value, a, mid);
3679 }
3680
3681 function snapTo(specification, value) {
3682 if (typeof specification == "boolean") {
3683 return specification ? Math.round(value) : value;
3684 }
3685 // Otherwise assume “specification” is a sorted array
3686 return closestValue(specification, value);
3687 }
3688
3689 // Draw or update the slider
3690 Slider.prototype.draw = function Slider_draw() {
3691 var that = this;
3692
3693 var cw = this._width,
3694 ch = this._height;
3695
3696 var container_node = this.container.node();
3697
3698 // If the width and height have not been specified, use
3699 // the client size of the container element.
3700 if (!cw) {
3701 var r = container_node.getBoundingClientRect();
3702 // If there isn’t a bounding client rect, e.g. because
3703 // the container is display: none;, then do nothing.
3704 if (!r || r.width == 0) return this;
3705
3706 cw = r.width;
3707 ch = r.height;
3708 }
3709
3710 var channel_r = this._channelRadius == null ? this._channelHeight/2 : this._channelRadius,
3711 left_margin = (this._margin.left == null ? Math.max(this._handleRadius, channel_r) : this._margin.left),
3712 right_margin = (this._margin.right == null ? Math.max(this._handleRadius, channel_r) : this._margin.right),
3713 top_margin = this._margin.top == null ? Math.max(this._handleRadius, this._channelHeight/2) : this._margin.top,
3714 w = cw - left_margin - right_margin, // Inner width of the slider channel (excluding endcaps)
3715 channel_w = w + 2*channel_r, // Width of the slider channel (including endcaps)
3716 label_h = this._labelSize * 1.5;
3717
3718 if (this._label != null && this._margin.top == null) top_margin += label_h;
3719
3720 var slider;
3721 if (container_node.namespaceURI == "http://www.w3.org/2000/svg") {
3722 slider = this.container;
3723 }
3724 else {
3725 slider = this.container.selectAll("svg").data([{ width: cw, height: ch }]);
3726 slider.exit().remove();
3727 slider = slider.enter().append("svg").merge(slider);
3728 slider.attr("width", function(d) { return d.width; })
3729 .attr("height", function(d) { return d.height; });
3730 }
3731
3732 var g = slider.selectAll("g.slider-container").data([{left: left_margin, top: top_margin, id: this._id}]);
3733 g.exit().remove();
3734 g = g.enter().append("g").attr("class", "slider-container").merge(g);
3735 g.attr("transform", function(d) {
3736 return "translate(" + d.left + "," + d.top + ")";
3737 })
3738 .attr("id", function(d) { return d.id; });
3739
3740 this.scale = (this._scale ? this._scale() : linear()).domain(this._domain).range([0, w]);
3741
3742 if (this._value == null || this._value < this._domain[0]) this._value = this._domain[0];
3743 else if (this._value > this._domain[1]) this._value = this._domain[1];
3744
3745 if (this._snap) this._value = snapTo(this._snap, this._value);
3746
3747 var axes_data = [];
3748 if (this._axis) {
3749 var axis;
3750 if (typeof this._axis != "boolean") {
3751 axis = this._axis(this.scale);
3752 }
3753 else {
3754 axis = axisBottom().scale(this.scale).tickPadding(6);
3755 }
3756
3757 if (this._ticks) axis.ticks(this._ticks);
3758 if (this._tickFormat) axis.tickFormat(this._tickFormat);
3759 if (this._tickSize) axis.tickSize(this._tickSize);
3760 else axis.tickSize(Math.max(5, this._handleRadius - this._channelHeight - 2));
3761 axes_data.push(axis);
3762 }
3763
3764 var axes = g.selectAll(".slider-axis");
3765 var axes_enter = axes.data(axes_data).enter();
3766 axes_enter.append("g").attr("class", "slider-axis")
3767 .attr("transform", "translate(" + 0 + "," + this._channelHeight/2 + ")")
3768 .each(function(axis) { axis(d3_select(this)); });
3769 axes_enter.select(".domain").attr("fill", "none");
3770 axes_enter.selectAll(".tick line").attr("stroke", "black");
3771 axes_enter.exit().remove();
3772
3773 var channel, handle;
3774 channel = g.selectAll(".slider-channel")
3775 .data([{ width: channel_w, height: this._channelHeight, channel_r: channel_r }]);
3776 channel.exit().remove();
3777
3778 channel = channel.enter().append("rect").attr("class", "slider-channel")
3779 .attr("cursor", "pointer")
3780 .on("click", function() {
3781 var slider_x = Math.max(0, Math.min(w, d3_mouse(this)[0]));
3782 that._value = that.scale.invert(slider_x);
3783 if (that._snap) that._value = snapTo(that._snap, that._value);
3784 handle.attr("cx", that.scale(that._value));
3785 that.fire("change", that._value);
3786 })
3787 .merge(channel);
3788
3789 channel.attr("width", function(d) { return d.width; })
3790 .attr("fill", this._channelFill)
3791 .attr("height", function(d) { return d.height; })
3792 .attr("y", function(d) { return -d.height/2; })
3793 .attr("x", function(d) { return -d.channel_r; })
3794 .attr("rx", function(d) { return d.channel_r; });
3795
3796 var drag_dx_origin, drag_x_origin;
3797 function handleMousedown(event) {
3798 document.addEventListener("mouseup", handleMouseup, false);
3799 document.addEventListener("mousemove", handleMousemove, false);
3800 drag_dx_origin = event.clientX;
3801 drag_x_origin = that.scale(that._value);
3802 }
3803
3804 function handleMouseup() {
3805 document.removeEventListener("mouseup", handleMouseup, false);
3806 document.removeEventListener("mousemove", handleMousemove, false);
3807 }
3808
3809 function handleMousemove(event) {
3810 drag(event.clientX - drag_dx_origin);
3811 }
3812
3813 function handleTouchstart(event) {
3814 if (event.touches.length != 1) return;
3815 document.addEventListener("touchend", handleTouchend, false);
3816 document.addEventListener("touchmove", handleTouchmove, false);
3817 drag_dx_origin = event.touches[0].clientX;
3818 drag_x_origin = that.scale(that._value);
3819 }
3820
3821 function handleTouchend() {
3822 document.removeEventListener("touchend", handleTouchend, false);
3823 document.removeEventListener("touchmove", handleTouchmove, false);
3824 }
3825
3826 function handleTouchmove(event) {
3827 if (event.touches.length != 1) return;
3828 drag(event.touches[0].clientX - drag_dx_origin);
3829 }
3830
3831 function drag(dx) {
3832 var new_x = drag_x_origin + dx;
3833 var slider_x = Math.max(0, Math.min(w, new_x));
3834 var new_value = that.scale.invert(slider_x);
3835 if (that._snap) new_value = snapTo(that._snap, new_value);
3836 handle.attr("cx", that.scale(new_value));
3837 if (new_value != that._value) {
3838 that._value = new_value;
3839 that.fire("change", that._value);
3840 }
3841 }
3842
3843 handle = g.selectAll(".slider-handle").data([{ v: this._value, x: this.scale(this._value) }]);
3844 handle = handle.enter().append("circle").attr("class", "slider-handle")
3845 .attr("cursor", "col-resize")
3846 .merge(handle);
3847
3848 handle.attr("cx", function(d) { return d.x; })
3849 .attr("r", this._handleRadius)
3850 .attr("fill", this._handleFill)
3851 .on("mousedown", function() {
3852 event.preventDefault();
3853 handleMousedown(event);
3854 })
3855 .on("touchstart", function() {
3856 event.preventDefault();
3857 handleTouchstart(event);
3858 });
3859
3860 var label_data = [];
3861 if (this._label) {
3862 label_data.push({
3863 label: this._label, x: w/2, y: -label_h, font_size: this._labelSize
3864 });
3865 }
3866 var label = g.selectAll(".slider-label").data(label_data);
3867 label.exit().remove();
3868 label = label.enter()
3869 .append("text").attr("class", "slider-label")
3870 .attr("text-anchor", "middle")
3871 .attr("cursor", "default")
3872 .merge(label);
3873
3874 label
3875 .text(function(d) { return d.label; })
3876 .attr("x", function(d) { return d.x; })
3877 .attr("y", function(d) { return d.y; })
3878 .attr("font-size", this._labelSize);
3879
3880 var end_label_data = [];
3881 if (this._startLabel) {
3882 end_label_data.push({
3883 label: this._startLabel,
3884 x: this._startLabelBelow ? 0 : -(channel_r + 5 + Math.max(0, this._handleRadius - channel_r)),
3885 y: this._startLabelBelow ? (channel_r + 15) : this._startEndLabelSize/1.75 - channel_r/2,
3886 anchor: this._startLabelBelow ? "middle" : "end",
3887 font_size: this._startEndLabelSize
3888 });
3889 }
3890 if (this._endLabel) {
3891 end_label_data.push({
3892 label: this._endLabel,
3893 x: this._endLabelBelow ? w : w + (channel_r + Math.max(0, this._handleRadius - channel_r) + 5),
3894 y: this._startLabelBelow ? (channel_r + 15) : this._startEndLabelSize/1.75 - channel_r/2,
3895 anchor: this._endLabelBelow ? "middle" : "start",
3896 font_size: this._startEndLabelSize
3897 });
3898 }
3899
3900 var end_labels = g.selectAll(".slider-end-labels").data(end_label_data);
3901 end_labels.exit().remove();
3902 end_labels = end_labels.enter().append("text").attr("class", "slider-end-labels")
3903 .attr("pointer-events", "none")
3904 .merge(end_labels);
3905 end_labels
3906 .text(function(d) { return d.label; })
3907 .attr("font-size", function(d) { return d.font_size; })
3908 .attr("x", function(d) { return d.x; })
3909 .attr("y", function(d) { return d.y; })
3910 .attr("text-anchor", function(d) { return d.anchor; });
3911
3912 return this;
3913 };
3914
3915 Slider.prototype.update = Slider.prototype.draw;
3916
3917 function Flourish_slider(selector) {
3918 return new Slider(selector);
3919 }
3920 Flourish_slider.version = VERSION;
3921
3922 function createPlayButton(colour) {
3923 var start_string = '<svg width="25px" height="30px" viewBox="0 0 25 30"> <polygon fill="';
3924 var end_string = '" stroke="none" points="25 15 0 30 0 0"></polygon> </svg>';
3925 return start_string + colour + end_string;
3926 }
3927
3928 function createPauseButton(colour) {
3929 var start_string = '<svg width="26px" height="30px" viewBox="0 0 26 30"> <g stroke="none" stroke-width="1" fill="';
3930 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>';
3931 return start_string + colour + end_string;
3932 }
3933
3934 function createSlider(control_obj, state, container) {
3935 var slider_obj = {};
3936 var slider_holder = select(container).append("div").attr("class", "fl-control fl-control-slider animatable");
3937 var slider_play_button = slider_holder.append("div").attr("class", "slider-play");
3938 var slider_div = slider_holder.append("div").attr("class", "fl-controls-slider");
3939
3940 var play_string, pause_string, handle_color;
3941 var sorted_options, timesteps, is_playing;
3942 var timer_id = null;
3943
3944 var clearTimer = function() {
3945 clearTimeout(timer_id);
3946 timer_id = null;
3947 };
3948
3949 var sliderChangeFunction = function(i) {
3950 var d = sorted_options[i];
3951 if (d.options_index === control_obj.index()) return;
3952 control_obj.index(d.options_index);
3953 control_obj.trigger("change");
3954 };
3955
3956 var slider = Flourish_slider(slider_div.node())
3957 .snap(true)
3958 .on("change", function(d) {
3959 var is_playing = timer_id !== null;
3960 if (is_playing) clearTimer();
3961 sliderChangeFunction(d);
3962 if (is_playing) setNextTick();
3963 });
3964
3965
3966 var stopSliderPlayer = function() {
3967 clearTimer();
3968 slider_holder.classed("playing", false);
3969 slider_play_button.html(play_string);
3970 control_obj._isPlaying_(false);
3971 is_playing = false;
3972 };
3973
3974
3975 var setNextTick = function() {
3976 var current_index = control_obj.getSortedIndex();
3977 var current_delay = timesteps[current_index];
3978 var final_index = control_obj.n_options - 1;
3979 var next_index = current_index < final_index ? current_index + 1 : 0;
3980
3981 timer_id = setTimeout(function() {
3982 sliderChangeFunction(next_index);
3983 if (state.slider_loop || next_index < final_index) setNextTick();
3984 else stopSliderPlayer();
3985 }, current_delay);
3986 };
3987
3988
3989 var startSliderPlayer = function() {
3990 slider_holder.classed("playing", true);
3991 slider_play_button.html(pause_string);
3992 setNextTick();
3993 control_obj._isPlaying_(true);
3994 is_playing = true;
3995 };
3996
3997
3998 slider_play_button.on("click", function() {
3999 if (timer_id === null) startSliderPlayer();
4000 else stopSliderPlayer();
4001 });
4002
4003
4004 var setWidths = function() {
4005 var handle_radius = Math.round(remToPx(state.slider_handle_height) / 2);
4006 slider_holder.style("width", Math.round(remToPx(state.slider_width)) + "px");
4007 slider_play_button
4008 .style("height", handle_radius * 2 + "px")
4009 .style("width", handle_radius * 2 + "px")
4010 .style("display", state.slider_play_button ? null : "none");
4011 var holder_width = slider_holder.node().getBoundingClientRect().width;
4012 var button_width = slider_play_button.node().getBoundingClientRect().width;
4013 slider_div
4014 .style("width", Math.max((holder_width - button_width), 1) + "px")
4015 .style("height", handle_radius * 2 + "px");
4016
4017 slider
4018 .handleRadius(handle_radius)
4019 .margin({
4020 left: handle_radius + 5,
4021 right: handle_radius + remToPx(state.slider_margin),
4022 top: handle_radius
4023 });
4024 };
4025
4026
4027 var setHandles = function() {
4028 if (state.slider_play_button) {
4029 slider_holder.classed("animatable", true);
4030 }
4031 else {
4032 stopSliderPlayer();
4033 slider_holder.classed("animatable", false);
4034 }
4035 if (handle_color !== state.slider_handle_color) {
4036 slider.update(); // Make sure slider-handle actually exists before changing its colour
4037 handle_color = state.slider_handle_color || "currentColor";
4038 slider_holder.select(".slider-handle").style("fill", handle_color);
4039 play_string = createPlayButton(handle_color);
4040 pause_string = createPauseButton(handle_color);
4041 slider_play_button.html(timer_id ? pause_string : play_string);
4042 }
4043 };
4044
4045
4046 var showControl = function() {
4047 slider_holder.style("display", "inline-flex");
4048 setWidths();
4049 setHandles();
4050 return slider_obj;
4051 };
4052
4053 var hideControl = function() {
4054 stopSliderPlayer();
4055 slider_holder.style("display", "none");
4056 return slider_obj;
4057 };
4058
4059 slider_obj.show = showControl;
4060 slider_obj.hide = hideControl;
4061
4062
4063 slider_obj.update = function(_sorted_options) {
4064 sorted_options = _sorted_options;
4065 if (!control_obj.n_options || state.control_type !== "slider") {
4066 hideControl();
4067 return slider_obj;
4068 }
4069
4070 showControl();
4071
4072 var n_options = control_obj.n_options;
4073 var loop = state.slider_loop;
4074
4075 timesteps = sorted_options.map(function(d, i) {
4076 var dur_in_seconds = state.slider_step_time + (loop && i === (n_options -1) ? state.slider_restart_pause : 0);
4077 return dur_in_seconds * 1000;
4078 });
4079
4080 var sorted_index = control_obj.getSortedIndex();
4081 var d = sorted_options[sorted_index];
4082
4083 slider.domain([0, n_options - 1])
4084 .value(sorted_index)
4085 .endLabel(d.display)
4086 .channelHeight(Math.round(remToPx(state.slider_track_height)))
4087 .channelFill(state.slider_background_color)
4088 .update();
4089
4090 slider.container.select("svg").attr("fill", "currentColor");
4091
4092 slider_div.select("text.slider-end-labels")
4093 .style("fill", state.slider_font_color)
4094 .attr("y", "0")
4095 .attr("dy", "0.25em");
4096
4097
4098 if (control_obj._isPlaying_() && !is_playing) startSliderPlayer();
4099 else if (!control_obj._isPlaying_() && is_playing) stopSliderPlayer();
4100
4101 return slider_obj;
4102 };
4103
4104
4105 return slider_obj;
4106 }
4107
4108 var DEFAULTS$1 = Object.freeze({
4109 alignment: "start",
4110 controls_spacing: 1,
4111 });
4112
4113 function controlsContainer(state_) {
4114 this._state = state_;
4115 for (var key in DEFAULTS$1) { if (this._state[key] === undefined) this._state[key] = DEFAULTS$1[key]; }
4116 return this;
4117 }
4118
4119 controlsContainer.prototype.appendTo = function (container_) {
4120 this._container = select(container_).append("div").node();
4121 return this;
4122 };
4123
4124 controlsContainer.prototype.add = function (controls) {
4125 this._controls = Array.isArray(controls) ? controls : [controls];
4126
4127 this._controls.forEach(function(control) {
4128 if (control && typeof control.appendTo === "function") control.appendTo(this._container);
4129 else console.warn("Please pass valid controls instances to .add()");
4130 }, this);
4131
4132 return this;
4133 };
4134
4135 controlsContainer.prototype.update = function () {
4136 this._controls.forEach(function(control) {
4137 if (control && typeof control.update == "function") control.update();
4138 });
4139
4140 var alignment = this._state.alignment;
4141 var flex_alignment = alignment == "center" ? alignment : "flex-" + alignment;
4142
4143 var template = window.template || undefined;
4144 var layout = template ? template.state.layout : undefined;
4145 var read_direction = (layout && layout.read_direction) || select("body").node().dir || "ltr";
4146 // This flips the controls container margins if read direction is set to right-to-left
4147 // Flex alignment is not flipped in order to match the behaviour of the legend
4148 var alignment_for_margins = alignment;
4149 if (read_direction === "rtl" && alignment !== "center") {
4150 alignment_for_margins = alignment === "start" ? "end" : "start";
4151 }
4152
4153 select(this._container)
4154 .style("display", "flex")
4155 .style("flex-wrap", "wrap")
4156 .style("justify-content", flex_alignment);
4157
4158 var individual_controls_container = select(this._container)
4159 .selectAll(".fl-controls-container");
4160
4161 var controls_spacing = this._state.controls_spacing;
4162 var margin_left;
4163 var margin_right;
4164 switch (alignment_for_margins) {
4165 case "end":
4166 margin_left = controls_spacing + "em";
4167 margin_right = 0;
4168 break;
4169 case "center":
4170 margin_left = controls_spacing * 0.5 + "em";
4171 margin_right = controls_spacing * 0.5 + "em";
4172 break;
4173 case "start":
4174 default:
4175 margin_left = 0;
4176 margin_right = controls_spacing + "em";
4177 break;
4178 }
4179
4180 individual_controls_container
4181 .style("margin-left", margin_left)
4182 .style("margin-right", margin_right);
4183
4184 return this;
4185 };
4186
4187 var DEFAULTS = Object.freeze({
4188 control_type: "dropdown",
4189 control_title: "",
4190
4191 // Dropdown
4192 dropdown_width_mode: "auto",
4193 dropdown_width_fixed: 20,
4194
4195 // Buttons
4196 button_group: true,
4197 button_group_width_mode: "fixed",
4198 button_group_width_fixed: 20,
4199
4200 // Slider
4201 slider_width: 15,
4202 slider_handle_color: null,
4203 slider_font_color: null,
4204 slider_background_color: "#dddddd",
4205
4206 slider_handle_height: 1,
4207 slider_track_height: 0.2,
4208 slider_margin: 4.5,
4209
4210 slider_play_button: true,
4211 slider_step_time: 2,
4212 slider_loop: true,
4213 slider_restart_pause: 0,
4214
4215 // Data typing
4216 sort: false,
4217
4218 _index_: null,
4219 _is_playing_: false
4220 });
4221
4222 function defaultParser(x) {
4223 return x;
4224 }
4225
4226 function defaultFormatter(x) {
4227 return x == null ? "" : x.toString();
4228 }
4229
4230 function createControls(state) {
4231 var control_obj = {};
4232 var parser = defaultParser;
4233 var formatter = defaultFormatter;
4234 var options = [];
4235 var sorted_options = [];
4236 var changeHandlers = [];
4237 var container = document.createElement("div");
4238 container.setAttribute("class", "fl-controls-container");
4239 var container_title = select(container).append("div").attr("class", "fl-controls-title");
4240 var dropdown_obj = createDropdown(control_obj, state, container);
4241 var buttons_obj = createButtons(control_obj, state, container);
4242 var slider_obj = createSlider(control_obj, state, container);
4243
4244 for (var key in DEFAULTS) {
4245 if (state[key] === undefined) state[key] = DEFAULTS[key];
4246 }
4247
4248 var current_index = state._index_;
4249
4250 var checkValidIndex = function(i) {
4251 return options.length && i >= 0 && i < options.length;
4252 };
4253
4254 var updateControls = function(sorted_options) {
4255 container.style.display = (sorted_options.length > 1) ? null : "none";
4256 container.style.width = "";
4257 container_title.node().innerHTML = state.control_title;
4258 container_title.node().style.display = (state.control_title === "") ? "none" : "inline-block";
4259 slider_obj.update(sorted_options); // Do slider first in case we're stopping playing
4260 dropdown_obj.update(sorted_options);
4261 buttons_obj.update(sorted_options);
4262 };
4263
4264 control_obj.appendTo = function(parent_container) {
4265 injectCSS();
4266 select(parent_container).node().appendChild(container);
4267 return control_obj;
4268 };
4269
4270 var callOnChangeCallbacks = function() {
4271 var index = indexFunction();
4272 var value = options[index];
4273 changeHandlers.forEach(function(func) {
4274 func(value, index);
4275 });
4276 return control_obj;
4277 };
4278
4279 control_obj.remove = function() {
4280 if (container.parentElement) container.parentElement.removeChild(container);
4281 return control_obj;
4282 };
4283
4284 control_obj.options = function(arr) {
4285 if (arr === undefined) return options.slice();
4286 if (!Array.isArray(arr)) return control_obj;
4287 options = arr.slice();
4288 var n = options.length;
4289 var i = indexFunction();
4290 if (!n) indexFunction(null);
4291 else if (i === null || i >= n) indexFunction(0);
4292 return control_obj;
4293 };
4294
4295 Object.defineProperty(control_obj, "n_options", { get: function() { return options.length; } });
4296
4297
4298 var indexFunction = function(i) {
4299 if (i === undefined) {
4300 if (!state._is_playing_) current_index = state._index_;
4301 return current_index;
4302 }
4303 if (i === null || checkValidIndex(i)) {
4304 current_index = i;
4305 if (!state._is_playing_) state._index_ = current_index;
4306 }
4307 else console.warn("Invalid index, ignoring update call");
4308 return control_obj;
4309 };
4310 control_obj.index = indexFunction;
4311
4312 control_obj.getSortedIndex = function() {
4313 var options_index = indexFunction();
4314 if (state.sort == "unsorted") return options_index;
4315 var sorted_index;
4316 sorted_options.some(function(d, i) {
4317 if (d.options_index === options_index) {
4318 sorted_index = i;
4319 return true;
4320 }
4321 });
4322 return sorted_index;
4323 };
4324
4325 control_obj.value = function(value) {
4326 if (value === undefined) return options[indexFunction()];
4327 var index = options.indexOf(value);
4328 if (index !== -1) indexFunction(index);
4329 return control_obj;
4330 };
4331
4332 control_obj.on = function(event, callback) {
4333 if (event === "change") changeHandlers.push(callback.bind(control_obj));
4334 return control_obj;
4335 };
4336
4337 control_obj.parser = function (value) {
4338 if (value === undefined) return parser;
4339 if (value === null) parser = defaultParser;
4340 else parser = value;
4341 return control_obj;
4342 };
4343
4344 control_obj.formatter = function (value) {
4345 if (value === undefined) return formatter;
4346 if (value === null) formatter = defaultFormatter;
4347 else formatter = value;
4348 return control_obj;
4349 };
4350
4351 control_obj.update = function() {
4352 getRemToPx();
4353 sorted_options = sortArray(options, state.sort, parser, formatter);
4354 updateControls(sorted_options);
4355 return control_obj;
4356 };
4357
4358 control_obj.trigger = function(event) {
4359 if (event === "change") callOnChangeCallbacks();
4360 return control_obj;
4361 };
4362
4363 control_obj.getNode = function() {
4364 return container;
4365 };
4366
4367 var isPlaying = function(is_playing) {
4368 if (is_playing === undefined) return state._is_playing_;
4369 state._is_playing_ = !!is_playing;
4370 if (!is_playing) indexFunction(current_index); // Force _index_ to match current index
4371 };
4372
4373 control_obj._isPlaying_ = isPlaying;
4374
4375 return control_obj;
4376 }
4377
4378 function createControlsContainer(state) {
4379 return new controlsContainer(state);
4380 }
4381
4382 exports.createControls = createControls;
4383 exports.createControlsContainer = createControlsContainer;
4384
4385 Object.defineProperty(exports, '__esModule', { value: true });
4386
4387})));