diff --git a/node_modules/d3-color/src/cubehelix.js b/node_modules/d3-color/src/cubehelix.js
new file mode 100644
index 0000000000000000000000000000000000000000..b3cf696d40d70efeb070309228ed21f55f779d7e
--- /dev/null
+++ b/node_modules/d3-color/src/cubehelix.js
@@ -0,0 +1,61 @@
+import define, {extend} from "./define.js";
+import {Color, rgbConvert, Rgb, darker, brighter} from "./color.js";
+import {degrees, radians} from "./math.js";
+
+var A = -0.14861,
+ B = +1.78277,
+ C = -0.29227,
+ D = -0.90649,
+ E = +1.97294,
+ ED = E * D,
+ EB = E * B,
+ BC_DA = B * C - D * A;
+
+function cubehelixConvert(o) {
+ if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity);
+ if (!(o instanceof Rgb)) o = rgbConvert(o);
+ var r = o.r / 255,
+ g = o.g / 255,
+ b = o.b / 255,
+ l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB),
+ bl = b - l,
+ k = (E * (g - l) - C * bl) / D,
+ s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), // NaN if l=0 or l=1
+ h = s ? Math.atan2(k, bl) * degrees - 120 : NaN;
+ return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity);
+}
+
+export default function cubehelix(h, s, l, opacity) {
+ return arguments.length === 1 ? cubehelixConvert(h) : new Cubehelix(h, s, l, opacity == null ? 1 : opacity);
+}
+
+export function Cubehelix(h, s, l, opacity) {
+ this.h = +h;
+ this.s = +s;
+ this.l = +l;
+ this.opacity = +opacity;
+}
+
+define(Cubehelix, cubehelix, extend(Color, {
+ brighter(k) {
+ k = k == null ? brighter : Math.pow(brighter, k);
+ return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
+ },
+ darker(k) {
+ k = k == null ? darker : Math.pow(darker, k);
+ return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
+ },
+ rgb() {
+ var h = isNaN(this.h) ? 0 : (this.h + 120) * radians,
+ l = +this.l,
+ a = isNaN(this.s) ? 0 : this.s * l * (1 - l),
+ cosh = Math.cos(h),
+ sinh = Math.sin(h);
+ return new Rgb(
+ 255 * (l + a * (A * cosh + B * sinh)),
+ 255 * (l + a * (C * cosh + D * sinh)),
+ 255 * (l + a * (E * cosh)),
+ this.opacity
+ );
+ }
+}));
diff --git a/node_modules/d3-color/src/define.js b/node_modules/d3-color/src/define.js
new file mode 100644
index 0000000000000000000000000000000000000000..2bba2d3a4fdf3cdee152aacc711366f91c1d5747
--- /dev/null
+++ b/node_modules/d3-color/src/define.js
@@ -0,0 +1,10 @@
+export default function(constructor, factory, prototype) {
+ constructor.prototype = factory.prototype = prototype;
+ prototype.constructor = constructor;
+}
+
+export function extend(parent, definition) {
+ var prototype = Object.create(parent.prototype);
+ for (var key in definition) prototype[key] = definition[key];
+ return prototype;
+}
diff --git a/node_modules/d3-color/src/index.js b/node_modules/d3-color/src/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..831cf529518caae3bfee557707141a0d2e0c9d5f
--- /dev/null
+++ b/node_modules/d3-color/src/index.js
@@ -0,0 +1,3 @@
+export {default as color, rgb, hsl} from "./color.js";
+export {default as lab, hcl, lch, gray} from "./lab.js";
+export {default as cubehelix} from "./cubehelix.js";
diff --git a/node_modules/d3-color/src/lab.js b/node_modules/d3-color/src/lab.js
new file mode 100644
index 0000000000000000000000000000000000000000..88c46e8de4f2c6f5a27bdd782c0324c6a5aaa2b6
--- /dev/null
+++ b/node_modules/d3-color/src/lab.js
@@ -0,0 +1,123 @@
+import define, {extend} from "./define.js";
+import {Color, rgbConvert, Rgb} from "./color.js";
+import {degrees, radians} from "./math.js";
+
+// https://observablehq.com/@mbostock/lab-and-rgb
+const K = 18,
+ Xn = 0.96422,
+ Yn = 1,
+ Zn = 0.82521,
+ t0 = 4 / 29,
+ t1 = 6 / 29,
+ t2 = 3 * t1 * t1,
+ t3 = t1 * t1 * t1;
+
+function labConvert(o) {
+ if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity);
+ if (o instanceof Hcl) return hcl2lab(o);
+ if (!(o instanceof Rgb)) o = rgbConvert(o);
+ var r = rgb2lrgb(o.r),
+ g = rgb2lrgb(o.g),
+ b = rgb2lrgb(o.b),
+ y = xyz2lab((0.2225045 * r + 0.7168786 * g + 0.0606169 * b) / Yn), x, z;
+ if (r === g && g === b) x = z = y; else {
+ x = xyz2lab((0.4360747 * r + 0.3850649 * g + 0.1430804 * b) / Xn);
+ z = xyz2lab((0.0139322 * r + 0.0971045 * g + 0.7141733 * b) / Zn);
+ }
+ return new Lab(116 * y - 16, 500 * (x - y), 200 * (y - z), o.opacity);
+}
+
+export function gray(l, opacity) {
+ return new Lab(l, 0, 0, opacity == null ? 1 : opacity);
+}
+
+export default function lab(l, a, b, opacity) {
+ return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity);
+}
+
+export function Lab(l, a, b, opacity) {
+ this.l = +l;
+ this.a = +a;
+ this.b = +b;
+ this.opacity = +opacity;
+}
+
+define(Lab, lab, extend(Color, {
+ brighter(k) {
+ return new Lab(this.l + K * (k == null ? 1 : k), this.a, this.b, this.opacity);
+ },
+ darker(k) {
+ return new Lab(this.l - K * (k == null ? 1 : k), this.a, this.b, this.opacity);
+ },
+ rgb() {
+ var y = (this.l + 16) / 116,
+ x = isNaN(this.a) ? y : y + this.a / 500,
+ z = isNaN(this.b) ? y : y - this.b / 200;
+ x = Xn * lab2xyz(x);
+ y = Yn * lab2xyz(y);
+ z = Zn * lab2xyz(z);
+ return new Rgb(
+ lrgb2rgb( 3.1338561 * x - 1.6168667 * y - 0.4906146 * z),
+ lrgb2rgb(-0.9787684 * x + 1.9161415 * y + 0.0334540 * z),
+ lrgb2rgb( 0.0719453 * x - 0.2289914 * y + 1.4052427 * z),
+ this.opacity
+ );
+ }
+}));
+
+function xyz2lab(t) {
+ return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
+}
+
+function lab2xyz(t) {
+ return t > t1 ? t * t * t : t2 * (t - t0);
+}
+
+function lrgb2rgb(x) {
+ return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
+}
+
+function rgb2lrgb(x) {
+ return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
+}
+
+function hclConvert(o) {
+ if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity);
+ if (!(o instanceof Lab)) o = labConvert(o);
+ if (o.a === 0 && o.b === 0) return new Hcl(NaN, 0 < o.l && o.l < 100 ? 0 : NaN, o.l, o.opacity);
+ var h = Math.atan2(o.b, o.a) * degrees;
+ return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity);
+}
+
+export function lch(l, c, h, opacity) {
+ return arguments.length === 1 ? hclConvert(l) : new Hcl(h, c, l, opacity == null ? 1 : opacity);
+}
+
+export function hcl(h, c, l, opacity) {
+ return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity);
+}
+
+export function Hcl(h, c, l, opacity) {
+ this.h = +h;
+ this.c = +c;
+ this.l = +l;
+ this.opacity = +opacity;
+}
+
+function hcl2lab(o) {
+ if (isNaN(o.h)) return new Lab(o.l, 0, 0, o.opacity);
+ var h = o.h * radians;
+ return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity);
+}
+
+define(Hcl, hcl, extend(Color, {
+ brighter(k) {
+ return new Hcl(this.h, this.c, this.l + K * (k == null ? 1 : k), this.opacity);
+ },
+ darker(k) {
+ return new Hcl(this.h, this.c, this.l - K * (k == null ? 1 : k), this.opacity);
+ },
+ rgb() {
+ return hcl2lab(this).rgb();
+ }
+}));
diff --git a/node_modules/d3-color/src/math.js b/node_modules/d3-color/src/math.js
new file mode 100644
index 0000000000000000000000000000000000000000..66b172e7a61622565a0c594ce5fe4c3b10e93e1a
--- /dev/null
+++ b/node_modules/d3-color/src/math.js
@@ -0,0 +1,2 @@
+export const radians = Math.PI / 180;
+export const degrees = 180 / Math.PI;
diff --git a/node_modules/d3-ease/LICENSE b/node_modules/d3-ease/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..83cc9970536d2b2bd0fa53ae1b0a94f378cf8fb4
--- /dev/null
+++ b/node_modules/d3-ease/LICENSE
@@ -0,0 +1,28 @@
+Copyright 2010-2021 Mike Bostock
+Copyright 2001 Robert Penner
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the author nor the names of contributors may be used to
+ endorse or promote products derived from this software without specific prior
+ written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/node_modules/d3-ease/README.md b/node_modules/d3-ease/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..cc6ca791fd882e03fe783ac727152b6ae748e0c4
--- /dev/null
+++ b/node_modules/d3-ease/README.md
@@ -0,0 +1,253 @@
+# d3-ease
+
+*Easing* is a method of distorting time to control apparent motion in animation. It is most commonly used for [slow-in, slow-out](https://en.wikipedia.org/wiki/12_basic_principles_of_animation#Slow_In_and_Slow_Out). By easing time, [animated transitions](https://github.com/d3/d3-transition) are smoother and exhibit more plausible motion.
+
+The easing types in this module implement the [ease method](#ease_ease), which takes a normalized time *t* and returns the corresponding “eased” time *tʹ*. Both the normalized time and the eased time are typically in the range [0,1], where 0 represents the start of the animation and 1 represents the end; some easing types, such as [elastic](#easeElastic), may return eased times slightly outside this range. A good easing type should return 0 if *t* = 0 and 1 if *t* = 1. See the [easing explorer](https://observablehq.com/@d3/easing) for a visual demonstration.
+
+These easing types are largely based on work by [Robert Penner](http://robertpenner.com/easing/).
+
+## Installing
+
+If you use npm, `npm install d3-ease`. You can also download the [latest release on GitHub](https://github.com/d3/d3-ease/releases/latest). For vanilla HTML in modern browsers, import d3-ease from Skypack:
+
+```html
+
+```
+
+For legacy environments, you can load d3-ease’s UMD bundle from an npm-based CDN such as jsDelivr; a `d3` global is exported:
+
+```html
+
+
+```
+
+[Try d3-ease in your browser.](https://observablehq.com/@d3/easing-animations)
+
+## API Reference
+
+# ease(t)
+
+Given the specified normalized time *t*, typically in the range [0,1], returns the “eased” time *tʹ*, also typically in [0,1]. 0 represents the start of the animation and 1 represents the end. A good implementation returns 0 if *t* = 0 and 1 if *t* = 1. See the [easing explorer](https://observablehq.com/@d3/easing) for a visual demonstration. For example, to apply [cubic](#easeCubic) easing:
+
+```js
+const te = d3.easeCubic(t);
+```
+
+Similarly, to apply custom [elastic](#easeElastic) easing:
+
+```js
+// Before the animation starts, create your easing function.
+const customElastic = d3.easeElastic.period(0.4);
+
+// During the animation, apply the easing function.
+const te = customElastic(t);
+```
+
+# d3.easeLinear(t) [<>](https://github.com/d3/d3-ease/blob/master/src/linear.js "Source")
+
+Linear easing; the identity function; *linear*(*t*) returns *t*.
+
+[
](https://observablehq.com/@d3/easing#linear)
+
+# d3.easePolyIn(t) [<>](https://github.com/d3/d3-ease/blob/master/src/poly.js#L3 "Source")
+
+Polynomial easing; raises *t* to the specified [exponent](#poly_exponent). If the exponent is not specified, it defaults to 3, equivalent to [cubicIn](#easeCubicIn).
+
+[
](https://observablehq.com/@d3/easing#polyIn)
+
+# d3.easePolyOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/poly.js#L15 "Source")
+
+Reverse polynomial easing; equivalent to 1 - [polyIn](#easePolyIn)(1 - *t*). If the [exponent](#poly_exponent) is not specified, it defaults to 3, equivalent to [cubicOut](#easeCubicOut).
+
+[
](https://observablehq.com/@d3/easing#polyOut)
+
+# d3.easePoly(t) [<>](https://github.com/d3/d3-ease/blob/master/src/poly.js "Source")
+
# d3.easePolyInOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/poly.js#L27 "Source")
+
+Symmetric polynomial easing; scales [polyIn](#easePolyIn) for *t* in [0, 0.5] and [polyOut](#easePolyOut) for *t* in [0.5, 1]. If the [exponent](#poly_exponent) is not specified, it defaults to 3, equivalent to [cubic](#easeCubic).
+
+[
](https://observablehq.com/@d3/easing#polyInOut)
+
+# poly.exponent(e) [<>](https://github.com/d3/d3-ease/blob/master/src/poly.js#L1 "Source")
+
+Returns a new polynomial easing with the specified exponent *e*. For example, to create equivalents of [linear](#easeLinear), [quad](#easeQuad), and [cubic](#easeCubic):
+
+```js
+const linear = d3.easePoly.exponent(1);
+const quad = d3.easePoly.exponent(2);
+const cubic = d3.easePoly.exponent(3);
+```
+
+# d3.easeQuadIn(t) [<>](https://github.com/d3/d3-ease/blob/master/src/quad.js#L1 "Source")
+
+Quadratic easing; equivalent to [polyIn](#easePolyIn).[exponent](#poly_exponent)(2).
+
+[
](https://observablehq.com/@d3/easing#quadIn)
+
+# d3.easeQuadOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/quad.js#L5 "Source")
+
+Reverse quadratic easing; equivalent to 1 - [quadIn](#easeQuadIn)(1 - *t*). Also equivalent to [polyOut](#easePolyOut).[exponent](#poly_exponent)(2).
+
+[
](https://observablehq.com/@d3/easing#quadOut)
+
+# d3.easeQuad(t) [<>](https://github.com/d3/d3-ease/blob/master/src/quad.js "Source")
+
# d3.easeQuadInOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/quad.js#L9 "Source")
+
+Symmetric quadratic easing; scales [quadIn](#easeQuadIn) for *t* in [0, 0.5] and [quadOut](#easeQuadOut) for *t* in [0.5, 1]. Also equivalent to [poly](#easePoly).[exponent](#poly_exponent)(2).
+
+[
](https://observablehq.com/@d3/easing#quadInOut)
+
+# d3.easeCubicIn(t) [<>](https://github.com/d3/d3-ease/blob/master/src/cubic.js#L1 "Source")
+
+Cubic easing; equivalent to [polyIn](#easePolyIn).[exponent](#poly_exponent)(3).
+
+[
](https://observablehq.com/@d3/easing#cubicIn)
+
+# d3.easeCubicOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/cubic.js#L5 "Source")
+
+Reverse cubic easing; equivalent to 1 - [cubicIn](#easeCubicIn)(1 - *t*). Also equivalent to [polyOut](#easePolyOut).[exponent](#poly_exponent)(3).
+
+[
](https://observablehq.com/@d3/easing#cubicOut)
+
+# d3.easeCubic(t) [<>](https://github.com/d3/d3-ease/blob/master/src/cubic.js "Source")
+
# d3.easeCubicInOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/cubic.js#L9 "Source")
+
+Symmetric cubic easing; scales [cubicIn](#easeCubicIn) for *t* in [0, 0.5] and [cubicOut](#easeCubicOut) for *t* in [0.5, 1]. Also equivalent to [poly](#easePoly).[exponent](#poly_exponent)(3).
+
+[
](https://observablehq.com/@d3/easing#cubicInOut)
+
+# d3.easeSinIn(t) [<>](https://github.com/d3/d3-ease/blob/master/src/sin.js#L4 "Source")
+
+Sinusoidal easing; returns sin(*t*).
+
+[
](https://observablehq.com/@d3/easing#sinIn)
+
+# d3.easeSinOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/sin.js#L8 "Source")
+
+Reverse sinusoidal easing; equivalent to 1 - [sinIn](#easeSinIn)(1 - *t*).
+
+[
](https://observablehq.com/@d3/easing#sinOut)
+
+# d3.easeSin(t) [<>](https://github.com/d3/d3-ease/blob/master/src/sin.js "Source")
+
# d3.easeSinInOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/sin.js#L12 "Source")
+
+Symmetric sinusoidal easing; scales [sinIn](#easeSinIn) for *t* in [0, 0.5] and [sinOut](#easeSinOut) for *t* in [0.5, 1].
+
+[
](https://observablehq.com/@d3/easing#sinInOut)
+
+# d3.easeExpIn(t) [<>](https://github.com/d3/d3-ease/blob/master/src/exp.js#L1 "Source")
+
+Exponential easing; raises 2 to the exponent 10 \* (*t* - 1).
+
+[
](https://observablehq.com/@d3/easing#expIn)
+
+# d3.easeExpOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/exp.js#L5 "Source")
+
+Reverse exponential easing; equivalent to 1 - [expIn](#easeExpIn)(1 - *t*).
+
+[
](https://observablehq.com/@d3/easing#expOut)
+
+# d3.easeExp(t) [<>](https://github.com/d3/d3-ease/blob/master/src/exp.js "Source")
+
# d3.easeExpInOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/exp.js#L9 "Source")
+
+Symmetric exponential easing; scales [expIn](#easeExpIn) for *t* in [0, 0.5] and [expOut](#easeExpOut) for *t* in [0.5, 1].
+
+[
](https://observablehq.com/@d3/easing#expInOut)
+
+# d3.easeCircleIn(t) [<>](https://github.com/d3/d3-ease/blob/master/src/circle.js#L1 "Source")
+
+Circular easing.
+
+[
](https://observablehq.com/@d3/easing#circleIn)
+
+# d3.easeCircleOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/circle.js#L5 "Source")
+
+Reverse circular easing; equivalent to 1 - [circleIn](#easeCircleIn)(1 - *t*).
+
+[
](https://observablehq.com/@d3/easing#circleOut)
+
+# d3.easeCircle(t) [<>](https://github.com/d3/d3-ease/blob/master/src/circle.js "Source")
+
# d3.easeCircleInOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/circle.js#L9 "Source")
+
+Symmetric circular easing; scales [circleIn](#easeCircleIn) for *t* in [0, 0.5] and [circleOut](#easeCircleOut) for *t* in [0.5, 1].
+
+[
](https://observablehq.com/@d3/easing#circleInOut)
+
+# d3.easeElasticIn(t) [<>](https://github.com/d3/d3-ease/blob/master/src/elastic.js#L5 "Source")
+
+Elastic easing, like a rubber band. The [amplitude](#elastic_amplitude) and [period](#elastic_period) of the oscillation are configurable; if not specified, they default to 1 and 0.3, respectively.
+
+[
](https://observablehq.com/@d3/easing#elasticIn)
+
+# d3.easeElastic(t) [<>](https://github.com/d3/d3-ease/blob/master/src/elastic.js "Source")
+
# d3.easeElasticOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/elastic.js#L18 "Source")
+
+Reverse elastic easing; equivalent to 1 - [elasticIn](#easeElasticIn)(1 - *t*).
+
+[
](https://observablehq.com/@d3/easing#elasticOut)
+
+# d3.easeElasticInOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/elastic.js#L31 "Source")
+
+Symmetric elastic easing; scales [elasticIn](#easeElasticIn) for *t* in [0, 0.5] and [elasticOut](#easeElasticOut) for *t* in [0.5, 1].
+
+[
](https://observablehq.com/@d3/easing#elasticInOut)
+
+# elastic.amplitude(a) [<>](https://github.com/d3/d3-ease/blob/master/src/elastic.js#L40 "Source")
+
+Returns a new elastic easing with the specified amplitude *a*.
+
+# elastic.period(p) [<>](https://github.com/d3/d3-ease/blob/master/src/elastic.js#L41 "Source")
+
+Returns a new elastic easing with the specified period *p*.
+
+# d3.easeBackIn(t) [<>](https://github.com/d3/d3-ease/blob/master/src/back.js#L3 "Source")
+
+[Anticipatory](https://en.wikipedia.org/wiki/12_basic_principles_of_animation#Anticipation) easing, like a dancer bending his knees before jumping off the floor. The degree of [overshoot](#back_overshoot) is configurable; if not specified, it defaults to 1.70158.
+
+[
](https://observablehq.com/@d3/easing#backIn)
+
+# d3.easeBackOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/back.js#L15 "Source")
+
+Reverse anticipatory easing; equivalent to 1 - [backIn](#easeBackIn)(1 - *t*).
+
+[
](https://observablehq.com/@d3/easing#backOut)
+
+# d3.easeBack(t) [<>](https://github.com/d3/d3-ease/blob/master/src/back.js "Source")
+
# d3.easeBackInOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/back.js#L27 "Source")
+
+Symmetric anticipatory easing; scales [backIn](#easeBackIn) for *t* in [0, 0.5] and [backOut](#easeBackOut) for *t* in [0.5, 1].
+
+[
](https://observablehq.com/@d3/easing#backInOut)
+
+# back.overshoot(s) [<>](https://github.com/d3/d3-ease/blob/master/src/back.js#L1 "Source")
+
+Returns a new back easing with the specified overshoot *s*.
+
+# d3.easeBounceIn(t) [<>](https://github.com/d3/d3-ease/blob/master/src/bounce.js#L12 "Source")
+
+Bounce easing, like a rubber ball.
+
+[
](https://observablehq.com/@d3/easing#bounceIn)
+
+# d3.easeBounce(t) [<>](https://github.com/d3/d3-ease/blob/master/src/bounce.js "Source")
+
# d3.easeBounceOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/bounce.js#L16 "Source")
+
+Reverse bounce easing; equivalent to 1 - [bounceIn](#easeBounceIn)(1 - *t*).
+
+[
](https://observablehq.com/@d3/easing#bounceOut)
+
+# d3.easeBounceInOut(t) [<>](https://github.com/d3/d3-ease/blob/master/src/bounce.js#L20 "Source")
+
+Symmetric bounce easing; scales [bounceIn](#easeBounceIn) for *t* in [0, 0.5] and [bounceOut](#easeBounceOut) for *t* in [0.5, 1].
+
+[
](https://observablehq.com/@d3/easing#bounceInOut)
diff --git a/node_modules/d3-ease/dist/d3-ease.js b/node_modules/d3-ease/dist/d3-ease.js
new file mode 100644
index 0000000000000000000000000000000000000000..8e5e545cc904ade4866143bc38c1b943e74d5239
--- /dev/null
+++ b/node_modules/d3-ease/dist/d3-ease.js
@@ -0,0 +1,262 @@
+// https://d3js.org/d3-ease/ v3.0.1 Copyright 2010-2021 Mike Bostock, 2001 Robert Penner
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+typeof define === 'function' && define.amd ? define(['exports'], factory) :
+(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.d3 = global.d3 || {}));
+}(this, (function (exports) { 'use strict';
+
+const linear = t => +t;
+
+function quadIn(t) {
+ return t * t;
+}
+
+function quadOut(t) {
+ return t * (2 - t);
+}
+
+function quadInOut(t) {
+ return ((t *= 2) <= 1 ? t * t : --t * (2 - t) + 1) / 2;
+}
+
+function cubicIn(t) {
+ return t * t * t;
+}
+
+function cubicOut(t) {
+ return --t * t * t + 1;
+}
+
+function cubicInOut(t) {
+ return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
+}
+
+var exponent = 3;
+
+var polyIn = (function custom(e) {
+ e = +e;
+
+ function polyIn(t) {
+ return Math.pow(t, e);
+ }
+
+ polyIn.exponent = custom;
+
+ return polyIn;
+})(exponent);
+
+var polyOut = (function custom(e) {
+ e = +e;
+
+ function polyOut(t) {
+ return 1 - Math.pow(1 - t, e);
+ }
+
+ polyOut.exponent = custom;
+
+ return polyOut;
+})(exponent);
+
+var polyInOut = (function custom(e) {
+ e = +e;
+
+ function polyInOut(t) {
+ return ((t *= 2) <= 1 ? Math.pow(t, e) : 2 - Math.pow(2 - t, e)) / 2;
+ }
+
+ polyInOut.exponent = custom;
+
+ return polyInOut;
+})(exponent);
+
+var pi = Math.PI,
+ halfPi = pi / 2;
+
+function sinIn(t) {
+ return (+t === 1) ? 1 : 1 - Math.cos(t * halfPi);
+}
+
+function sinOut(t) {
+ return Math.sin(t * halfPi);
+}
+
+function sinInOut(t) {
+ return (1 - Math.cos(pi * t)) / 2;
+}
+
+// tpmt is two power minus ten times t scaled to [0,1]
+function tpmt(x) {
+ return (Math.pow(2, -10 * x) - 0.0009765625) * 1.0009775171065494;
+}
+
+function expIn(t) {
+ return tpmt(1 - +t);
+}
+
+function expOut(t) {
+ return 1 - tpmt(t);
+}
+
+function expInOut(t) {
+ return ((t *= 2) <= 1 ? tpmt(1 - t) : 2 - tpmt(t - 1)) / 2;
+}
+
+function circleIn(t) {
+ return 1 - Math.sqrt(1 - t * t);
+}
+
+function circleOut(t) {
+ return Math.sqrt(1 - --t * t);
+}
+
+function circleInOut(t) {
+ return ((t *= 2) <= 1 ? 1 - Math.sqrt(1 - t * t) : Math.sqrt(1 - (t -= 2) * t) + 1) / 2;
+}
+
+var b1 = 4 / 11,
+ b2 = 6 / 11,
+ b3 = 8 / 11,
+ b4 = 3 / 4,
+ b5 = 9 / 11,
+ b6 = 10 / 11,
+ b7 = 15 / 16,
+ b8 = 21 / 22,
+ b9 = 63 / 64,
+ b0 = 1 / b1 / b1;
+
+function bounceIn(t) {
+ return 1 - bounceOut(1 - t);
+}
+
+function bounceOut(t) {
+ return (t = +t) < b1 ? b0 * t * t : t < b3 ? b0 * (t -= b2) * t + b4 : t < b6 ? b0 * (t -= b5) * t + b7 : b0 * (t -= b8) * t + b9;
+}
+
+function bounceInOut(t) {
+ return ((t *= 2) <= 1 ? 1 - bounceOut(1 - t) : bounceOut(t - 1) + 1) / 2;
+}
+
+var overshoot = 1.70158;
+
+var backIn = (function custom(s) {
+ s = +s;
+
+ function backIn(t) {
+ return (t = +t) * t * (s * (t - 1) + t);
+ }
+
+ backIn.overshoot = custom;
+
+ return backIn;
+})(overshoot);
+
+var backOut = (function custom(s) {
+ s = +s;
+
+ function backOut(t) {
+ return --t * t * ((t + 1) * s + t) + 1;
+ }
+
+ backOut.overshoot = custom;
+
+ return backOut;
+})(overshoot);
+
+var backInOut = (function custom(s) {
+ s = +s;
+
+ function backInOut(t) {
+ return ((t *= 2) < 1 ? t * t * ((s + 1) * t - s) : (t -= 2) * t * ((s + 1) * t + s) + 2) / 2;
+ }
+
+ backInOut.overshoot = custom;
+
+ return backInOut;
+})(overshoot);
+
+var tau = 2 * Math.PI,
+ amplitude = 1,
+ period = 0.3;
+
+var elasticIn = (function custom(a, p) {
+ var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
+
+ function elasticIn(t) {
+ return a * tpmt(-(--t)) * Math.sin((s - t) / p);
+ }
+
+ elasticIn.amplitude = function(a) { return custom(a, p * tau); };
+ elasticIn.period = function(p) { return custom(a, p); };
+
+ return elasticIn;
+})(amplitude, period);
+
+var elasticOut = (function custom(a, p) {
+ var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
+
+ function elasticOut(t) {
+ return 1 - a * tpmt(t = +t) * Math.sin((t + s) / p);
+ }
+
+ elasticOut.amplitude = function(a) { return custom(a, p * tau); };
+ elasticOut.period = function(p) { return custom(a, p); };
+
+ return elasticOut;
+})(amplitude, period);
+
+var elasticInOut = (function custom(a, p) {
+ var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
+
+ function elasticInOut(t) {
+ return ((t = t * 2 - 1) < 0
+ ? a * tpmt(-t) * Math.sin((s - t) / p)
+ : 2 - a * tpmt(t) * Math.sin((s + t) / p)) / 2;
+ }
+
+ elasticInOut.amplitude = function(a) { return custom(a, p * tau); };
+ elasticInOut.period = function(p) { return custom(a, p); };
+
+ return elasticInOut;
+})(amplitude, period);
+
+exports.easeBack = backInOut;
+exports.easeBackIn = backIn;
+exports.easeBackInOut = backInOut;
+exports.easeBackOut = backOut;
+exports.easeBounce = bounceOut;
+exports.easeBounceIn = bounceIn;
+exports.easeBounceInOut = bounceInOut;
+exports.easeBounceOut = bounceOut;
+exports.easeCircle = circleInOut;
+exports.easeCircleIn = circleIn;
+exports.easeCircleInOut = circleInOut;
+exports.easeCircleOut = circleOut;
+exports.easeCubic = cubicInOut;
+exports.easeCubicIn = cubicIn;
+exports.easeCubicInOut = cubicInOut;
+exports.easeCubicOut = cubicOut;
+exports.easeElastic = elasticOut;
+exports.easeElasticIn = elasticIn;
+exports.easeElasticInOut = elasticInOut;
+exports.easeElasticOut = elasticOut;
+exports.easeExp = expInOut;
+exports.easeExpIn = expIn;
+exports.easeExpInOut = expInOut;
+exports.easeExpOut = expOut;
+exports.easeLinear = linear;
+exports.easePoly = polyInOut;
+exports.easePolyIn = polyIn;
+exports.easePolyInOut = polyInOut;
+exports.easePolyOut = polyOut;
+exports.easeQuad = quadInOut;
+exports.easeQuadIn = quadIn;
+exports.easeQuadInOut = quadInOut;
+exports.easeQuadOut = quadOut;
+exports.easeSin = sinInOut;
+exports.easeSinIn = sinIn;
+exports.easeSinInOut = sinInOut;
+exports.easeSinOut = sinOut;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
diff --git a/node_modules/d3-ease/dist/d3-ease.min.js b/node_modules/d3-ease/dist/d3-ease.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..f34b0dd3ccf3c2238218d1c8bd2f3c5fa697768b
--- /dev/null
+++ b/node_modules/d3-ease/dist/d3-ease.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-ease/ v3.0.1 Copyright 2010-2021 Mike Bostock, 2001 Robert Penner
+!function(n,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((n="undefined"!=typeof globalThis?globalThis:n||self).d3=n.d3||{})}(this,(function(n){"use strict";function e(n){return((n*=2)<=1?n*n:--n*(2-n)+1)/2}function t(n){return((n*=2)<=1?n*n*n:(n-=2)*n*n+2)/2}var u=function n(e){function t(n){return Math.pow(n,e)}return e=+e,t.exponent=n,t}(3),r=function n(e){function t(n){return 1-Math.pow(1-n,e)}return e=+e,t.exponent=n,t}(3),a=function n(e){function t(n){return((n*=2)<=1?Math.pow(n,e):2-Math.pow(2-n,e))/2}return e=+e,t.exponent=n,t}(3),o=Math.PI,i=o/2;function c(n){return(1-Math.cos(o*n))/2}function s(n){return 1.0009775171065494*(Math.pow(2,-10*n)-.0009765625)}function f(n){return((n*=2)<=1?s(1-n):2-s(n-1))/2}function h(n){return((n*=2)<=1?1-Math.sqrt(1-n*n):Math.sqrt(1-(n-=2)*n)+1)/2}var p=4/11,M=7.5625;function d(n){return(n=+n)
+n,n.easePoly=a,n.easePolyIn=u,n.easePolyInOut=a,n.easePolyOut=r,n.easeQuad=e,n.easeQuadIn=function(n){return n*n},n.easeQuadInOut=e,n.easeQuadOut=function(n){return n*(2-n)},n.easeSin=c,n.easeSinIn=function(n){return 1==+n?1:1-Math.cos(n*i)},n.easeSinInOut=c,n.easeSinOut=function(n){return Math.sin(n*i)},Object.defineProperty(n,"__esModule",{value:!0})}));
diff --git a/node_modules/d3-ease/package.json b/node_modules/d3-ease/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..2ff544cd3f3a6f2a4083d35ce4e8ed3dae4e26ff
--- /dev/null
+++ b/node_modules/d3-ease/package.json
@@ -0,0 +1,51 @@
+{
+ "name": "d3-ease",
+ "version": "3.0.1",
+ "description": "Easing functions for smooth animation.",
+ "homepage": "https://d3js.org/d3-ease/",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/d3/d3-ease.git"
+ },
+ "keywords": [
+ "d3",
+ "d3-module",
+ "ease",
+ "easing",
+ "animation",
+ "transition"
+ ],
+ "license": "BSD-3-Clause",
+ "author": {
+ "name": "Mike Bostock",
+ "url": "http://bost.ocks.org/mike"
+ },
+ "type": "module",
+ "files": [
+ "dist/**/*.js",
+ "src/**/*.js"
+ ],
+ "module": "src/index.js",
+ "main": "src/index.js",
+ "jsdelivr": "dist/d3-ease.min.js",
+ "unpkg": "dist/d3-ease.min.js",
+ "exports": {
+ "umd": "./dist/d3-ease.min.js",
+ "default": "./src/index.js"
+ },
+ "sideEffects": false,
+ "devDependencies": {
+ "eslint": "7",
+ "mocha": "8",
+ "rollup": "2",
+ "rollup-plugin-terser": "7"
+ },
+ "scripts": {
+ "test": "mocha 'test/**/*-test.js' && eslint src test",
+ "prepublishOnly": "rm -rf dist && yarn test && rollup -c",
+ "postpublish": "git push && git push --tags && cd ../d3.github.com && git pull && cp ../${npm_package_name}/dist/${npm_package_name}.js ${npm_package_name}.v${npm_package_version%%.*}.js && cp ../${npm_package_name}/dist/${npm_package_name}.min.js ${npm_package_name}.v${npm_package_version%%.*}.min.js && git add ${npm_package_name}.v${npm_package_version%%.*}.js ${npm_package_name}.v${npm_package_version%%.*}.min.js && git commit -m \"${npm_package_name} ${npm_package_version}\" && git push && cd -"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+}
diff --git a/node_modules/d3-ease/src/back.js b/node_modules/d3-ease/src/back.js
new file mode 100644
index 0000000000000000000000000000000000000000..b9c1bcc90eaaa8f39d9eeee2894857f60c5b3633
--- /dev/null
+++ b/node_modules/d3-ease/src/back.js
@@ -0,0 +1,37 @@
+var overshoot = 1.70158;
+
+export var backIn = (function custom(s) {
+ s = +s;
+
+ function backIn(t) {
+ return (t = +t) * t * (s * (t - 1) + t);
+ }
+
+ backIn.overshoot = custom;
+
+ return backIn;
+})(overshoot);
+
+export var backOut = (function custom(s) {
+ s = +s;
+
+ function backOut(t) {
+ return --t * t * ((t + 1) * s + t) + 1;
+ }
+
+ backOut.overshoot = custom;
+
+ return backOut;
+})(overshoot);
+
+export var backInOut = (function custom(s) {
+ s = +s;
+
+ function backInOut(t) {
+ return ((t *= 2) < 1 ? t * t * ((s + 1) * t - s) : (t -= 2) * t * ((s + 1) * t + s) + 2) / 2;
+ }
+
+ backInOut.overshoot = custom;
+
+ return backInOut;
+})(overshoot);
diff --git a/node_modules/d3-ease/src/bounce.js b/node_modules/d3-ease/src/bounce.js
new file mode 100644
index 0000000000000000000000000000000000000000..d2d81caf0193c48fa903bb02f0edef00be260a07
--- /dev/null
+++ b/node_modules/d3-ease/src/bounce.js
@@ -0,0 +1,22 @@
+var b1 = 4 / 11,
+ b2 = 6 / 11,
+ b3 = 8 / 11,
+ b4 = 3 / 4,
+ b5 = 9 / 11,
+ b6 = 10 / 11,
+ b7 = 15 / 16,
+ b8 = 21 / 22,
+ b9 = 63 / 64,
+ b0 = 1 / b1 / b1;
+
+export function bounceIn(t) {
+ return 1 - bounceOut(1 - t);
+}
+
+export function bounceOut(t) {
+ return (t = +t) < b1 ? b0 * t * t : t < b3 ? b0 * (t -= b2) * t + b4 : t < b6 ? b0 * (t -= b5) * t + b7 : b0 * (t -= b8) * t + b9;
+}
+
+export function bounceInOut(t) {
+ return ((t *= 2) <= 1 ? 1 - bounceOut(1 - t) : bounceOut(t - 1) + 1) / 2;
+}
diff --git a/node_modules/d3-ease/src/circle.js b/node_modules/d3-ease/src/circle.js
new file mode 100644
index 0000000000000000000000000000000000000000..8b9bb1de2d53dd38a7d2f4ddceb1576b1e98c295
--- /dev/null
+++ b/node_modules/d3-ease/src/circle.js
@@ -0,0 +1,11 @@
+export function circleIn(t) {
+ return 1 - Math.sqrt(1 - t * t);
+}
+
+export function circleOut(t) {
+ return Math.sqrt(1 - --t * t);
+}
+
+export function circleInOut(t) {
+ return ((t *= 2) <= 1 ? 1 - Math.sqrt(1 - t * t) : Math.sqrt(1 - (t -= 2) * t) + 1) / 2;
+}
diff --git a/node_modules/d3-ease/src/cubic.js b/node_modules/d3-ease/src/cubic.js
new file mode 100644
index 0000000000000000000000000000000000000000..bad3a7caad3720303622ffb800f303545ecf710b
--- /dev/null
+++ b/node_modules/d3-ease/src/cubic.js
@@ -0,0 +1,11 @@
+export function cubicIn(t) {
+ return t * t * t;
+}
+
+export function cubicOut(t) {
+ return --t * t * t + 1;
+}
+
+export function cubicInOut(t) {
+ return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
+}
diff --git a/node_modules/d3-ease/src/elastic.js b/node_modules/d3-ease/src/elastic.js
new file mode 100644
index 0000000000000000000000000000000000000000..48ca6733fc7bf5cc2b74cddfb50eaf2c1f2b0908
--- /dev/null
+++ b/node_modules/d3-ease/src/elastic.js
@@ -0,0 +1,46 @@
+import {tpmt} from "./math.js";
+
+var tau = 2 * Math.PI,
+ amplitude = 1,
+ period = 0.3;
+
+export var elasticIn = (function custom(a, p) {
+ var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
+
+ function elasticIn(t) {
+ return a * tpmt(-(--t)) * Math.sin((s - t) / p);
+ }
+
+ elasticIn.amplitude = function(a) { return custom(a, p * tau); };
+ elasticIn.period = function(p) { return custom(a, p); };
+
+ return elasticIn;
+})(amplitude, period);
+
+export var elasticOut = (function custom(a, p) {
+ var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
+
+ function elasticOut(t) {
+ return 1 - a * tpmt(t = +t) * Math.sin((t + s) / p);
+ }
+
+ elasticOut.amplitude = function(a) { return custom(a, p * tau); };
+ elasticOut.period = function(p) { return custom(a, p); };
+
+ return elasticOut;
+})(amplitude, period);
+
+export var elasticInOut = (function custom(a, p) {
+ var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
+
+ function elasticInOut(t) {
+ return ((t = t * 2 - 1) < 0
+ ? a * tpmt(-t) * Math.sin((s - t) / p)
+ : 2 - a * tpmt(t) * Math.sin((s + t) / p)) / 2;
+ }
+
+ elasticInOut.amplitude = function(a) { return custom(a, p * tau); };
+ elasticInOut.period = function(p) { return custom(a, p); };
+
+ return elasticInOut;
+})(amplitude, period);
diff --git a/node_modules/d3-ease/src/exp.js b/node_modules/d3-ease/src/exp.js
new file mode 100644
index 0000000000000000000000000000000000000000..f3c1cf0f6df81cf9dba1d6cf56fc2bf720013884
--- /dev/null
+++ b/node_modules/d3-ease/src/exp.js
@@ -0,0 +1,13 @@
+import {tpmt} from "./math.js";
+
+export function expIn(t) {
+ return tpmt(1 - +t);
+}
+
+export function expOut(t) {
+ return 1 - tpmt(t);
+}
+
+export function expInOut(t) {
+ return ((t *= 2) <= 1 ? tpmt(1 - t) : 2 - tpmt(t - 1)) / 2;
+}
diff --git a/node_modules/d3-ease/src/index.js b/node_modules/d3-ease/src/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..710d3df5c407b81a34605f06071c5187599d0ef2
--- /dev/null
+++ b/node_modules/d3-ease/src/index.js
@@ -0,0 +1,66 @@
+export {
+ linear as easeLinear
+} from "./linear.js";
+
+export {
+ quadInOut as easeQuad,
+ quadIn as easeQuadIn,
+ quadOut as easeQuadOut,
+ quadInOut as easeQuadInOut
+} from "./quad.js";
+
+export {
+ cubicInOut as easeCubic,
+ cubicIn as easeCubicIn,
+ cubicOut as easeCubicOut,
+ cubicInOut as easeCubicInOut
+} from "./cubic.js";
+
+export {
+ polyInOut as easePoly,
+ polyIn as easePolyIn,
+ polyOut as easePolyOut,
+ polyInOut as easePolyInOut
+} from "./poly.js";
+
+export {
+ sinInOut as easeSin,
+ sinIn as easeSinIn,
+ sinOut as easeSinOut,
+ sinInOut as easeSinInOut
+} from "./sin.js";
+
+export {
+ expInOut as easeExp,
+ expIn as easeExpIn,
+ expOut as easeExpOut,
+ expInOut as easeExpInOut
+} from "./exp.js";
+
+export {
+ circleInOut as easeCircle,
+ circleIn as easeCircleIn,
+ circleOut as easeCircleOut,
+ circleInOut as easeCircleInOut
+} from "./circle.js";
+
+export {
+ bounceOut as easeBounce,
+ bounceIn as easeBounceIn,
+ bounceOut as easeBounceOut,
+ bounceInOut as easeBounceInOut
+} from "./bounce.js";
+
+export {
+ backInOut as easeBack,
+ backIn as easeBackIn,
+ backOut as easeBackOut,
+ backInOut as easeBackInOut
+} from "./back.js";
+
+export {
+ elasticOut as easeElastic,
+ elasticIn as easeElasticIn,
+ elasticOut as easeElasticOut,
+ elasticInOut as easeElasticInOut
+} from "./elastic.js";
diff --git a/node_modules/d3-ease/src/linear.js b/node_modules/d3-ease/src/linear.js
new file mode 100644
index 0000000000000000000000000000000000000000..7b7d2c11b5f9405abebc16734e01580ca3941282
--- /dev/null
+++ b/node_modules/d3-ease/src/linear.js
@@ -0,0 +1 @@
+export const linear = t => +t;
diff --git a/node_modules/d3-ease/src/math.js b/node_modules/d3-ease/src/math.js
new file mode 100644
index 0000000000000000000000000000000000000000..d342db17777210e9c239decc454308132b0974ff
--- /dev/null
+++ b/node_modules/d3-ease/src/math.js
@@ -0,0 +1,4 @@
+// tpmt is two power minus ten times t scaled to [0,1]
+export function tpmt(x) {
+ return (Math.pow(2, -10 * x) - 0.0009765625) * 1.0009775171065494;
+}
diff --git a/node_modules/d3-ease/src/poly.js b/node_modules/d3-ease/src/poly.js
new file mode 100644
index 0000000000000000000000000000000000000000..827cf87433ac741a8ee2655aa955b548302f9e12
--- /dev/null
+++ b/node_modules/d3-ease/src/poly.js
@@ -0,0 +1,37 @@
+var exponent = 3;
+
+export var polyIn = (function custom(e) {
+ e = +e;
+
+ function polyIn(t) {
+ return Math.pow(t, e);
+ }
+
+ polyIn.exponent = custom;
+
+ return polyIn;
+})(exponent);
+
+export var polyOut = (function custom(e) {
+ e = +e;
+
+ function polyOut(t) {
+ return 1 - Math.pow(1 - t, e);
+ }
+
+ polyOut.exponent = custom;
+
+ return polyOut;
+})(exponent);
+
+export var polyInOut = (function custom(e) {
+ e = +e;
+
+ function polyInOut(t) {
+ return ((t *= 2) <= 1 ? Math.pow(t, e) : 2 - Math.pow(2 - t, e)) / 2;
+ }
+
+ polyInOut.exponent = custom;
+
+ return polyInOut;
+})(exponent);
diff --git a/node_modules/d3-ease/src/quad.js b/node_modules/d3-ease/src/quad.js
new file mode 100644
index 0000000000000000000000000000000000000000..df65bc29c203754b2a7351e380d1a8a149df58b3
--- /dev/null
+++ b/node_modules/d3-ease/src/quad.js
@@ -0,0 +1,11 @@
+export function quadIn(t) {
+ return t * t;
+}
+
+export function quadOut(t) {
+ return t * (2 - t);
+}
+
+export function quadInOut(t) {
+ return ((t *= 2) <= 1 ? t * t : --t * (2 - t) + 1) / 2;
+}
diff --git a/node_modules/d3-ease/src/sin.js b/node_modules/d3-ease/src/sin.js
new file mode 100644
index 0000000000000000000000000000000000000000..d8e09b8ea08913cb3f895af2d5a7e84b7fb81ba5
--- /dev/null
+++ b/node_modules/d3-ease/src/sin.js
@@ -0,0 +1,14 @@
+var pi = Math.PI,
+ halfPi = pi / 2;
+
+export function sinIn(t) {
+ return (+t === 1) ? 1 : 1 - Math.cos(t * halfPi);
+}
+
+export function sinOut(t) {
+ return Math.sin(t * halfPi);
+}
+
+export function sinInOut(t) {
+ return (1 - Math.cos(pi * t)) / 2;
+}
diff --git a/node_modules/d3-format/LICENSE b/node_modules/d3-format/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..a8918c41d974616d6c8d3e31d76af1923028083a
--- /dev/null
+++ b/node_modules/d3-format/LICENSE
@@ -0,0 +1,13 @@
+Copyright 2010-2026 Mike Bostock
+
+Permission to use, copy, modify, and/or distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright notice
+and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
diff --git a/node_modules/d3-format/README.md b/node_modules/d3-format/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..e9819013eaec93b112ffc17383ad8f0442cd650b
--- /dev/null
+++ b/node_modules/d3-format/README.md
@@ -0,0 +1,12 @@
+# d3-format
+
+
+
+This module formats numbers for human consumption, with a consistent output allowing comparison. Grouped digits, currencies, scientific notation…
+
+## Resources
+
+- [Documentation](https://d3js.org/d3-format)
+- [Examples](https://observablehq.com/@d3/d3-format)
+- [Releases](https://github.com/d3/d3-format/releases)
+- [Getting help](https://d3js.org/community)
diff --git a/node_modules/d3-format/dist/d3-format.js b/node_modules/d3-format/dist/d3-format.js
new file mode 100644
index 0000000000000000000000000000000000000000..6dc5b7f986dbd42c9a10892991457aa73c848acb
--- /dev/null
+++ b/node_modules/d3-format/dist/d3-format.js
@@ -0,0 +1,342 @@
+// https://d3js.org/d3-format/ v3.1.2 Copyright 2010-2026 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+typeof define === 'function' && define.amd ? define(['exports'], factory) :
+(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.d3 = global.d3 || {}));
+})(this, (function (exports) { 'use strict';
+
+function formatDecimal(x) {
+ return Math.abs(x = Math.round(x)) >= 1e21
+ ? x.toLocaleString("en").replace(/,/g, "")
+ : x.toString(10);
+}
+
+// Computes the decimal coefficient and exponent of the specified number x with
+// significant digits p, where x is positive and p is in [1, 21] or undefined.
+// For example, formatDecimalParts(1.23) returns ["123", 0].
+function formatDecimalParts(x, p) {
+ if (!isFinite(x) || x === 0) return null; // NaN, ±Infinity, ±0
+ var i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e"), coefficient = x.slice(0, i);
+
+ // The string returned by toExponential either has the form \d\.\d+e[-+]\d+
+ // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
+ return [
+ coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
+ +x.slice(i + 1)
+ ];
+}
+
+function exponent(x) {
+ return x = formatDecimalParts(Math.abs(x)), x ? x[1] : NaN;
+}
+
+function formatGroup(grouping, thousands) {
+ return function(value, width) {
+ var i = value.length,
+ t = [],
+ j = 0,
+ g = grouping[0],
+ length = 0;
+
+ while (i > 0 && g > 0) {
+ if (length + g + 1 > width) g = Math.max(1, width - length);
+ t.push(value.substring(i -= g, i + g));
+ if ((length += g + 1) > width) break;
+ g = grouping[j = (j + 1) % grouping.length];
+ }
+
+ return t.reverse().join(thousands);
+ };
+}
+
+function formatNumerals(numerals) {
+ return function(value) {
+ return value.replace(/[0-9]/g, function(i) {
+ return numerals[+i];
+ });
+ };
+}
+
+// [[fill]align][sign][symbol][0][width][,][.precision][~][type]
+var re = /^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;
+
+function formatSpecifier(specifier) {
+ if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
+ var match;
+ return new FormatSpecifier({
+ fill: match[1],
+ align: match[2],
+ sign: match[3],
+ symbol: match[4],
+ zero: match[5],
+ width: match[6],
+ comma: match[7],
+ precision: match[8] && match[8].slice(1),
+ trim: match[9],
+ type: match[10]
+ });
+}
+
+formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof
+
+function FormatSpecifier(specifier) {
+ this.fill = specifier.fill === undefined ? " " : specifier.fill + "";
+ this.align = specifier.align === undefined ? ">" : specifier.align + "";
+ this.sign = specifier.sign === undefined ? "-" : specifier.sign + "";
+ this.symbol = specifier.symbol === undefined ? "" : specifier.symbol + "";
+ this.zero = !!specifier.zero;
+ this.width = specifier.width === undefined ? undefined : +specifier.width;
+ this.comma = !!specifier.comma;
+ this.precision = specifier.precision === undefined ? undefined : +specifier.precision;
+ this.trim = !!specifier.trim;
+ this.type = specifier.type === undefined ? "" : specifier.type + "";
+}
+
+FormatSpecifier.prototype.toString = function() {
+ return this.fill
+ + this.align
+ + this.sign
+ + this.symbol
+ + (this.zero ? "0" : "")
+ + (this.width === undefined ? "" : Math.max(1, this.width | 0))
+ + (this.comma ? "," : "")
+ + (this.precision === undefined ? "" : "." + Math.max(0, this.precision | 0))
+ + (this.trim ? "~" : "")
+ + this.type;
+};
+
+// Trims insignificant zeros, e.g., replaces 1.2000k with 1.2k.
+function formatTrim(s) {
+ out: for (var n = s.length, i = 1, i0 = -1, i1; i < n; ++i) {
+ switch (s[i]) {
+ case ".": i0 = i1 = i; break;
+ case "0": if (i0 === 0) i0 = i; i1 = i; break;
+ default: if (!+s[i]) break out; if (i0 > 0) i0 = 0; break;
+ }
+ }
+ return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s;
+}
+
+var prefixExponent;
+
+function formatPrefixAuto(x, p) {
+ var d = formatDecimalParts(x, p);
+ if (!d) return prefixExponent = undefined, x.toPrecision(p);
+ var coefficient = d[0],
+ exponent = d[1],
+ i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
+ n = coefficient.length;
+ return i === n ? coefficient
+ : i > n ? coefficient + new Array(i - n + 1).join("0")
+ : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i)
+ : "0." + new Array(1 - i).join("0") + formatDecimalParts(x, Math.max(0, p + i - 1))[0]; // less than 1y!
+}
+
+function formatRounded(x, p) {
+ var d = formatDecimalParts(x, p);
+ if (!d) return x + "";
+ var coefficient = d[0],
+ exponent = d[1];
+ return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient
+ : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1)
+ : coefficient + new Array(exponent - coefficient.length + 2).join("0");
+}
+
+var formatTypes = {
+ "%": (x, p) => (x * 100).toFixed(p),
+ "b": (x) => Math.round(x).toString(2),
+ "c": (x) => x + "",
+ "d": formatDecimal,
+ "e": (x, p) => x.toExponential(p),
+ "f": (x, p) => x.toFixed(p),
+ "g": (x, p) => x.toPrecision(p),
+ "o": (x) => Math.round(x).toString(8),
+ "p": (x, p) => formatRounded(x * 100, p),
+ "r": formatRounded,
+ "s": formatPrefixAuto,
+ "X": (x) => Math.round(x).toString(16).toUpperCase(),
+ "x": (x) => Math.round(x).toString(16)
+};
+
+function identity(x) {
+ return x;
+}
+
+var map = Array.prototype.map,
+ prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];
+
+function formatLocale(locale) {
+ var group = locale.grouping === undefined || locale.thousands === undefined ? identity : formatGroup(map.call(locale.grouping, Number), locale.thousands + ""),
+ currencyPrefix = locale.currency === undefined ? "" : locale.currency[0] + "",
+ currencySuffix = locale.currency === undefined ? "" : locale.currency[1] + "",
+ decimal = locale.decimal === undefined ? "." : locale.decimal + "",
+ numerals = locale.numerals === undefined ? identity : formatNumerals(map.call(locale.numerals, String)),
+ percent = locale.percent === undefined ? "%" : locale.percent + "",
+ minus = locale.minus === undefined ? "−" : locale.minus + "",
+ nan = locale.nan === undefined ? "NaN" : locale.nan + "";
+
+ function newFormat(specifier, options) {
+ specifier = formatSpecifier(specifier);
+
+ var fill = specifier.fill,
+ align = specifier.align,
+ sign = specifier.sign,
+ symbol = specifier.symbol,
+ zero = specifier.zero,
+ width = specifier.width,
+ comma = specifier.comma,
+ precision = specifier.precision,
+ trim = specifier.trim,
+ type = specifier.type;
+
+ // The "n" type is an alias for ",g".
+ if (type === "n") comma = true, type = "g";
+
+ // The "" type, and any invalid type, is an alias for ".12~g".
+ else if (!formatTypes[type]) precision === undefined && (precision = 12), trim = true, type = "g";
+
+ // If zero fill is specified, padding goes after sign and before digits.
+ if (zero || (fill === "0" && align === "=")) zero = true, fill = "0", align = "=";
+
+ // Compute the prefix and suffix.
+ // For SI-prefix, the suffix is lazily computed.
+ var prefix = (options && options.prefix !== undefined ? options.prefix : "") + (symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : ""),
+ suffix = (symbol === "$" ? currencySuffix : /[%p]/.test(type) ? percent : "") + (options && options.suffix !== undefined ? options.suffix : "");
+
+ // What format function should we use?
+ // Is this an integer type?
+ // Can this type generate exponential notation?
+ var formatType = formatTypes[type],
+ maybeSuffix = /[defgprs%]/.test(type);
+
+ // Set the default precision if not specified,
+ // or clamp the specified precision to the supported range.
+ // For significant precision, it must be in [1, 21].
+ // For fixed precision, it must be in [0, 20].
+ precision = precision === undefined ? 6
+ : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))
+ : Math.max(0, Math.min(20, precision));
+
+ function format(value) {
+ var valuePrefix = prefix,
+ valueSuffix = suffix,
+ i, n, c;
+
+ if (type === "c") {
+ valueSuffix = formatType(value) + valueSuffix;
+ value = "";
+ } else {
+ value = +value;
+
+ // Determine the sign. -0 is not less than 0, but 1 / -0 is!
+ var valueNegative = value < 0 || 1 / value < 0;
+
+ // Perform the initial formatting.
+ value = isNaN(value) ? nan : formatType(Math.abs(value), precision);
+
+ // Trim insignificant zeros.
+ if (trim) value = formatTrim(value);
+
+ // If a negative value rounds to zero after formatting, and no explicit positive sign is requested, hide the sign.
+ if (valueNegative && +value === 0 && sign !== "+") valueNegative = false;
+
+ // Compute the prefix and suffix.
+ valuePrefix = (valueNegative ? (sign === "(" ? sign : minus) : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
+ valueSuffix = (type === "s" && !isNaN(value) && prefixExponent !== undefined ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign === "(" ? ")" : "");
+
+ // Break the formatted value into the integer “value” part that can be
+ // grouped, and fractional or exponential “suffix” part that is not.
+ if (maybeSuffix) {
+ i = -1, n = value.length;
+ while (++i < n) {
+ if (c = value.charCodeAt(i), 48 > c || c > 57) {
+ valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
+ value = value.slice(0, i);
+ break;
+ }
+ }
+ }
+ }
+
+ // If the fill character is not "0", grouping is applied before padding.
+ if (comma && !zero) value = group(value, Infinity);
+
+ // Compute the padding.
+ var length = valuePrefix.length + value.length + valueSuffix.length,
+ padding = length < width ? new Array(width - length + 1).join(fill) : "";
+
+ // If the fill character is "0", grouping is applied after padding.
+ if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
+
+ // Reconstruct the final output based on the desired alignment.
+ switch (align) {
+ case "<": value = valuePrefix + value + valueSuffix + padding; break;
+ case "=": value = valuePrefix + padding + value + valueSuffix; break;
+ case "^": value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length); break;
+ default: value = padding + valuePrefix + value + valueSuffix; break;
+ }
+
+ return numerals(value);
+ }
+
+ format.toString = function() {
+ return specifier + "";
+ };
+
+ return format;
+ }
+
+ function formatPrefix(specifier, value) {
+ var e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
+ k = Math.pow(10, -e),
+ f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier), {suffix: prefixes[8 + e / 3]});
+ return function(value) {
+ return f(k * value);
+ };
+ }
+
+ return {
+ format: newFormat,
+ formatPrefix: formatPrefix
+ };
+}
+
+var locale;
+exports.format = void 0;
+exports.formatPrefix = void 0;
+
+defaultLocale({
+ thousands: ",",
+ grouping: [3],
+ currency: ["$", ""]
+});
+
+function defaultLocale(definition) {
+ locale = formatLocale(definition);
+ exports.format = locale.format;
+ exports.formatPrefix = locale.formatPrefix;
+ return locale;
+}
+
+function precisionFixed(step) {
+ return Math.max(0, -exponent(Math.abs(step)));
+}
+
+function precisionPrefix(step, value) {
+ return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step)));
+}
+
+function precisionRound(step, max) {
+ step = Math.abs(step), max = Math.abs(max) - step;
+ return Math.max(0, exponent(max) - exponent(step)) + 1;
+}
+
+exports.FormatSpecifier = FormatSpecifier;
+exports.formatDefaultLocale = defaultLocale;
+exports.formatLocale = formatLocale;
+exports.formatSpecifier = formatSpecifier;
+exports.precisionFixed = precisionFixed;
+exports.precisionPrefix = precisionPrefix;
+exports.precisionRound = precisionRound;
+
+}));
diff --git a/node_modules/d3-format/dist/d3-format.min.js b/node_modules/d3-format/dist/d3-format.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..f684f87a3bc25c0654eb95fbbe461646f20e7e88
--- /dev/null
+++ b/node_modules/d3-format/dist/d3-format.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-format/ v3.1.2 Copyright 2010-2026 Mike Bostock
+!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i((t="undefined"!=typeof globalThis?globalThis:t||self).d3=t.d3||{})}(this,function(t){"use strict";function i(t,i){if(!isFinite(t)||0===t)return null;var r=(t=i?t.toExponential(i-1):t.toExponential()).indexOf("e"),n=t.slice(0,r);return[n.length>1?n[0]+n.slice(2):n,+t.slice(r+1)]}function r(t){return(t=i(Math.abs(t)))?t[1]:NaN}var n,e=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function o(t){if(!(i=e.exec(t)))throw new Error("invalid format: "+t);var i;return new a({fill:i[1],align:i[2],sign:i[3],symbol:i[4],zero:i[5],width:i[6],comma:i[7],precision:i[8]&&i[8].slice(1),trim:i[9],type:i[10]})}function a(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function s(t,r){var n=i(t,r);if(!n)return t+"";var e=n[0],o=n[1];return o<0?"0."+new Array(-o).join("0")+e:e.length>o+1?e.slice(0,o+1)+"."+e.slice(o+1):e+new Array(o-e.length+2).join("0")}o.prototype=a.prototype,a.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};var c={"%":(t,i)=>(100*t).toFixed(i),b:t=>Math.round(t).toString(2),c:t=>t+"",d:function(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)},e:(t,i)=>t.toExponential(i),f:(t,i)=>t.toFixed(i),g:(t,i)=>t.toPrecision(i),o:t=>Math.round(t).toString(8),p:(t,i)=>s(100*t,i),r:s,s:function(t,r){var e=i(t,r);if(!e)return n=void 0,t.toPrecision(r);var o=e[0],a=e[1],s=a-(n=3*Math.max(-8,Math.min(8,Math.floor(a/3))))+1,c=o.length;return s===c?o:s>c?o+new Array(s-c+1).join("0"):s>0?o.slice(0,s)+"."+o.slice(s):"0."+new Array(1-s).join("0")+i(t,Math.max(0,r+s-1))[0]},X:t=>Math.round(t).toString(16).toUpperCase(),x:t=>Math.round(t).toString(16)};function f(t){return t}var u,h=Array.prototype.map,l=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function d(t){var i,e,a=void 0===t.grouping||void 0===t.thousands?f:(i=h.call(t.grouping,Number),e=t.thousands+"",function(t,r){for(var n=t.length,o=[],a=0,s=i[0],c=0;n>0&&s>0&&(c+s+1>r&&(s=Math.max(1,r-c)),o.push(t.substring(n-=s,n+s)),!((c+=s+1)>r));)s=i[a=(a+1)%i.length];return o.reverse().join(e)}),s=void 0===t.currency?"":t.currency[0]+"",u=void 0===t.currency?"":t.currency[1]+"",d=void 0===t.decimal?".":t.decimal+"",m=void 0===t.numerals?f:function(t){return function(i){return i.replace(/[0-9]/g,function(i){return t[+i]})}}(h.call(t.numerals,String)),p=void 0===t.percent?"%":t.percent+"",g=void 0===t.minus?"−":t.minus+"",v=void 0===t.nan?"NaN":t.nan+"";function x(t,i){var r=(t=o(t)).fill,e=t.align,f=t.sign,h=t.symbol,x=t.zero,M=t.width,y=t.comma,b=t.precision,w=t.trim,S=t.type;"n"===S?(y=!0,S="g"):c[S]||(void 0===b&&(b=12),w=!0,S="g"),(x||"0"===r&&"="===e)&&(x=!0,r="0",e="=");var N=(i&&void 0!==i.prefix?i.prefix:"")+("$"===h?s:"#"===h&&/[boxX]/.test(S)?"0"+S.toLowerCase():""),k=("$"===h?u:/[%p]/.test(S)?p:"")+(i&&void 0!==i.suffix?i.suffix:""),P=c[S],j=/[defgprs%]/.test(S);function z(t){var i,o,s,c=N,u=k;if("c"===S)u=P(t)+u,t="";else{var h=(t=+t)<0||1/t<0;if(t=isNaN(t)?v:P(Math.abs(t),b),w&&(t=function(t){t:for(var i,r=t.length,n=1,e=-1;n
+
+Or, with a corrected [gamma](#interpolate_gamma) of 2.2:
+
+
+
+Returns an RGB color space interpolator between the two colors *a* and *b* with a configurable [gamma](#interpolate_gamma). If the gamma is not specified, it defaults to 1.0. The colors *a* and *b* need not be in RGB; they will be converted to RGB using [d3.rgb](https://github.com/d3/d3-color/blob/master/README.md#rgb). The return value of the interpolator is an RGB string.
+
+# d3.interpolateRgbBasis(colors) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/rgb.js#L54), [Examples](https://observablehq.com/@d3/working-with-color)
+
+Returns a uniform nonrational B-spline interpolator through the specified array of *colors*, which are converted to [RGB color space](https://github.com/d3/d3-color/blob/master/README.md#rgb). Implicit control points are generated such that the interpolator returns *colors*[0] at *t* = 0 and *colors*[*colors*.length - 1] at *t* = 1. Opacity interpolation is not currently supported. See also [d3.interpolateBasis](#interpolateBasis), and see [d3-scale-chromatic](https://github.com/d3/d3-scale-chromatic) for examples.
+
+# d3.interpolateRgbBasisClosed(colors) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/rgb.js#L55), [Examples](https://observablehq.com/@d3/working-with-color)
+
+Returns a uniform nonrational B-spline interpolator through the specified array of *colors*, which are converted to [RGB color space](https://github.com/d3/d3-color/blob/master/README.md#rgb). The control points are implicitly repeated such that the resulting spline has cyclical C² continuity when repeated around *t* in [0,1]; this is useful, for example, to create cyclical color scales. Opacity interpolation is not currently supported. See also [d3.interpolateBasisClosed](#interpolateBasisClosed), and see [d3-scale-chromatic](https://github.com/d3/d3-scale-chromatic) for examples.
+
+# d3.interpolateHsl(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/hsl.js), [Examples](https://observablehq.com/@d3/working-with-color)
+
+
+
+Returns an HSL color space interpolator between the two colors *a* and *b*. The colors *a* and *b* need not be in HSL; they will be converted to HSL using [d3.hsl](https://github.com/d3/d3-color/blob/master/README.md#hsl). If either color’s hue or saturation is NaN, the opposing color’s channel value is used. The shortest path between hues is used. The return value of the interpolator is an RGB string.
+
+# d3.interpolateHslLong(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/hsl.js#L21), [Examples](https://observablehq.com/@d3/working-with-color)
+
+
+
+Like [interpolateHsl](#interpolateHsl), but does not use the shortest path between hues.
+
+# d3.interpolateLab(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/lab.js), [Examples](https://observablehq.com/@d3/working-with-color)
+
+
+
+Returns a [CIELAB color space](https://en.wikipedia.org/wiki/Lab_color_space#CIELAB) interpolator between the two colors *a* and *b*. The colors *a* and *b* need not be in CIELAB; they will be converted to CIELAB using [d3.lab](https://github.com/d3/d3-color/blob/master/README.md#lab). The return value of the interpolator is an RGB string.
+
+# d3.interpolateHcl(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/hcl.js), [Examples](https://observablehq.com/@d3/working-with-color)
+
+
+
+Returns a [CIELChab color space](https://en.wikipedia.org/wiki/CIELAB_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC) interpolator between the two colors *a* and *b*. The colors *a* and *b* need not be in CIELChab; they will be converted to CIELChab using [d3.hcl](https://github.com/d3/d3-color/blob/master/README.md#hcl). If either color’s hue or chroma is NaN, the opposing color’s channel value is used. The shortest path between hues is used. The return value of the interpolator is an RGB string.
+
+# d3.interpolateHclLong(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/hcl.js#L21), [Examples](https://observablehq.com/@d3/working-with-color)
+
+
+
+Like [interpolateHcl](#interpolateHcl), but does not use the shortest path between hues.
+
+# d3.interpolateCubehelix(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/cubehelix.js), [Examples](https://observablehq.com/@d3/working-with-color)
+
+
+
+Or, with a [gamma](#interpolate_gamma) of 3.0 to emphasize high-intensity values:
+
+
+
+Returns a Cubehelix color space interpolator between the two colors *a* and *b* using a configurable [gamma](#interpolate_gamma). If the gamma is not specified, it defaults to 1.0. The colors *a* and *b* need not be in Cubehelix; they will be converted to Cubehelix using [d3.cubehelix](https://github.com/d3/d3-color/blob/master/README.md#cubehelix). If either color’s hue or saturation is NaN, the opposing color’s channel value is used. The shortest path between hues is used. The return value of the interpolator is an RGB string.
+
+# d3.interpolateCubehelixLong(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/cubehelix.js#L29), [Examples](https://observablehq.com/@d3/working-with-color)
+
+
+
+Or, with a [gamma](#interpolate_gamma) of 3.0 to emphasize high-intensity values:
+
+
+
+Like [interpolateCubehelix](#interpolateCubehelix), but does not use the shortest path between hues.
+
+# interpolate.gamma(gamma)
+
+Given that *interpolate* is one of [interpolateRgb](#interpolateRgb), [interpolateCubehelix](#interpolateCubehelix) or [interpolateCubehelixLong](#interpolateCubehelixLong), returns a new interpolator factory of the same type using the specified *gamma*. For example, to interpolate from purple to orange with a gamma of 2.2 in RGB space:
+
+```js
+const interpolator = d3.interpolateRgb.gamma(2.2)("purple", "orange");
+```
+
+See Eric Brasseur’s article, [Gamma error in picture scaling](http://www.ericbrasseur.org/gamma.html), for more on gamma correction.
+
+# d3.interpolateHue(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/hue.js), [Examples](https://observablehq.com/@d3/working-with-color)
+
+Returns an interpolator between the two hue angles *a* and *b*. If either hue is NaN, the opposing value is used. The shortest path between hues is used. The return value of the interpolator is a number in [0, 360).
+
+### Splines
+
+Whereas standard interpolators blend from a starting value *a* at *t* = 0 to an ending value *b* at *t* = 1, spline interpolators smoothly blend multiple input values for *t* in [0,1] using piecewise polynomial functions. Only cubic uniform nonrational [B-splines](https://en.wikipedia.org/wiki/B-spline) are currently supported, also known as basis splines.
+
+# d3.interpolateBasis(values) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/basis.js), [Examples](https://observablehq.com/@d3/d3-interpolatebasis)
+
+Returns a uniform nonrational B-spline interpolator through the specified array of *values*, which must be numbers. Implicit control points are generated such that the interpolator returns *values*[0] at *t* = 0 and *values*[*values*.length - 1] at *t* = 1. See also [d3.curveBasis](https://github.com/d3/d3-shape/blob/master/README.md#curveBasis).
+
+# d3.interpolateBasisClosed(values) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/basisClosed.js), [Examples](https://observablehq.com/@d3/d3-interpolatebasis)
+
+Returns a uniform nonrational B-spline interpolator through the specified array of *values*, which must be numbers. The control points are implicitly repeated such that the resulting one-dimensional spline has cyclical C² continuity when repeated around *t* in [0,1]. See also [d3.curveBasisClosed](https://github.com/d3/d3-shape/blob/master/README.md#curveBasisClosed).
+
+### Piecewise
+
+# d3.piecewise([interpolate, ]values) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/piecewise.js), [Examples](https://observablehq.com/@d3/d3-piecewise)
+
+Returns a piecewise interpolator, composing interpolators for each adjacent pair of *values*. The returned interpolator maps *t* in [0, 1 / (*n* - 1)] to *interpolate*(*values*[0], *values*[1]), *t* in [1 / (*n* - 1), 2 / (*n* - 1)] to *interpolate*(*values*[1], *values*[2]), and so on, where *n* = *values*.length. In effect, this is a lightweight [linear scale](https://github.com/d3/d3-scale/blob/master/README.md#linear-scales). For example, to blend through red, green and blue:
+
+```js
+const interpolate = d3.piecewise(d3.interpolateRgb.gamma(2.2), ["red", "green", "blue"]);
+```
+
+If *interpolate* is not specified, defaults to [d3.interpolate](#interpolate).
diff --git a/node_modules/d3-interpolate/dist/d3-interpolate.js b/node_modules/d3-interpolate/dist/d3-interpolate.js
new file mode 100644
index 0000000000000000000000000000000000000000..a374eedfbf87490ab9616f917ae430de1520d676
--- /dev/null
+++ b/node_modules/d3-interpolate/dist/d3-interpolate.js
@@ -0,0 +1,590 @@
+// https://d3js.org/d3-interpolate/ v3.0.1 Copyright 2010-2021 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-color')) :
+typeof define === 'function' && define.amd ? define(['exports', 'd3-color'], factory) :
+(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.d3 = global.d3 || {}, global.d3));
+}(this, (function (exports, d3Color) { 'use strict';
+
+function basis(t1, v0, v1, v2, v3) {
+ var t2 = t1 * t1, t3 = t2 * t1;
+ return ((1 - 3 * t1 + 3 * t2 - t3) * v0
+ + (4 - 6 * t2 + 3 * t3) * v1
+ + (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2
+ + t3 * v3) / 6;
+}
+
+function basis$1(values) {
+ var n = values.length - 1;
+ return function(t) {
+ var i = t <= 0 ? (t = 0) : t >= 1 ? (t = 1, n - 1) : Math.floor(t * n),
+ v1 = values[i],
+ v2 = values[i + 1],
+ v0 = i > 0 ? values[i - 1] : 2 * v1 - v2,
+ v3 = i < n - 1 ? values[i + 2] : 2 * v2 - v1;
+ return basis((t - i / n) * n, v0, v1, v2, v3);
+ };
+}
+
+function basisClosed(values) {
+ var n = values.length;
+ return function(t) {
+ var i = Math.floor(((t %= 1) < 0 ? ++t : t) * n),
+ v0 = values[(i + n - 1) % n],
+ v1 = values[i % n],
+ v2 = values[(i + 1) % n],
+ v3 = values[(i + 2) % n];
+ return basis((t - i / n) * n, v0, v1, v2, v3);
+ };
+}
+
+var constant = x => () => x;
+
+function linear(a, d) {
+ return function(t) {
+ return a + t * d;
+ };
+}
+
+function exponential(a, b, y) {
+ return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {
+ return Math.pow(a + t * b, y);
+ };
+}
+
+function hue$1(a, b) {
+ var d = b - a;
+ return d ? linear(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant(isNaN(a) ? b : a);
+}
+
+function gamma(y) {
+ return (y = +y) === 1 ? nogamma : function(a, b) {
+ return b - a ? exponential(a, b, y) : constant(isNaN(a) ? b : a);
+ };
+}
+
+function nogamma(a, b) {
+ var d = b - a;
+ return d ? linear(a, d) : constant(isNaN(a) ? b : a);
+}
+
+var rgb = (function rgbGamma(y) {
+ var color = gamma(y);
+
+ function rgb(start, end) {
+ var r = color((start = d3Color.rgb(start)).r, (end = d3Color.rgb(end)).r),
+ g = color(start.g, end.g),
+ b = color(start.b, end.b),
+ opacity = nogamma(start.opacity, end.opacity);
+ return function(t) {
+ start.r = r(t);
+ start.g = g(t);
+ start.b = b(t);
+ start.opacity = opacity(t);
+ return start + "";
+ };
+ }
+
+ rgb.gamma = rgbGamma;
+
+ return rgb;
+})(1);
+
+function rgbSpline(spline) {
+ return function(colors) {
+ var n = colors.length,
+ r = new Array(n),
+ g = new Array(n),
+ b = new Array(n),
+ i, color;
+ for (i = 0; i < n; ++i) {
+ color = d3Color.rgb(colors[i]);
+ r[i] = color.r || 0;
+ g[i] = color.g || 0;
+ b[i] = color.b || 0;
+ }
+ r = spline(r);
+ g = spline(g);
+ b = spline(b);
+ color.opacity = 1;
+ return function(t) {
+ color.r = r(t);
+ color.g = g(t);
+ color.b = b(t);
+ return color + "";
+ };
+ };
+}
+
+var rgbBasis = rgbSpline(basis$1);
+var rgbBasisClosed = rgbSpline(basisClosed);
+
+function numberArray(a, b) {
+ if (!b) b = [];
+ var n = a ? Math.min(b.length, a.length) : 0,
+ c = b.slice(),
+ i;
+ return function(t) {
+ for (i = 0; i < n; ++i) c[i] = a[i] * (1 - t) + b[i] * t;
+ return c;
+ };
+}
+
+function isNumberArray(x) {
+ return ArrayBuffer.isView(x) && !(x instanceof DataView);
+}
+
+function array(a, b) {
+ return (isNumberArray(b) ? numberArray : genericArray)(a, b);
+}
+
+function genericArray(a, b) {
+ var nb = b ? b.length : 0,
+ na = a ? Math.min(nb, a.length) : 0,
+ x = new Array(na),
+ c = new Array(nb),
+ i;
+
+ for (i = 0; i < na; ++i) x[i] = value(a[i], b[i]);
+ for (; i < nb; ++i) c[i] = b[i];
+
+ return function(t) {
+ for (i = 0; i < na; ++i) c[i] = x[i](t);
+ return c;
+ };
+}
+
+function date(a, b) {
+ var d = new Date;
+ return a = +a, b = +b, function(t) {
+ return d.setTime(a * (1 - t) + b * t), d;
+ };
+}
+
+function number(a, b) {
+ return a = +a, b = +b, function(t) {
+ return a * (1 - t) + b * t;
+ };
+}
+
+function object(a, b) {
+ var i = {},
+ c = {},
+ k;
+
+ if (a === null || typeof a !== "object") a = {};
+ if (b === null || typeof b !== "object") b = {};
+
+ for (k in b) {
+ if (k in a) {
+ i[k] = value(a[k], b[k]);
+ } else {
+ c[k] = b[k];
+ }
+ }
+
+ return function(t) {
+ for (k in i) c[k] = i[k](t);
+ return c;
+ };
+}
+
+var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,
+ reB = new RegExp(reA.source, "g");
+
+function zero(b) {
+ return function() {
+ return b;
+ };
+}
+
+function one(b) {
+ return function(t) {
+ return b(t) + "";
+ };
+}
+
+function string(a, b) {
+ var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b
+ am, // current match in a
+ bm, // current match in b
+ bs, // string preceding current number in b, if any
+ i = -1, // index in s
+ s = [], // string constants and placeholders
+ q = []; // number interpolators
+
+ // Coerce inputs to strings.
+ a = a + "", b = b + "";
+
+ // Interpolate pairs of numbers in a & b.
+ while ((am = reA.exec(a))
+ && (bm = reB.exec(b))) {
+ if ((bs = bm.index) > bi) { // a string precedes the next number in b
+ bs = b.slice(bi, bs);
+ if (s[i]) s[i] += bs; // coalesce with previous string
+ else s[++i] = bs;
+ }
+ if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match
+ if (s[i]) s[i] += bm; // coalesce with previous string
+ else s[++i] = bm;
+ } else { // interpolate non-matching numbers
+ s[++i] = null;
+ q.push({i: i, x: number(am, bm)});
+ }
+ bi = reB.lastIndex;
+ }
+
+ // Add remains of b.
+ if (bi < b.length) {
+ bs = b.slice(bi);
+ if (s[i]) s[i] += bs; // coalesce with previous string
+ else s[++i] = bs;
+ }
+
+ // Special optimization for only a single match.
+ // Otherwise, interpolate each of the numbers and rejoin the string.
+ return s.length < 2 ? (q[0]
+ ? one(q[0].x)
+ : zero(b))
+ : (b = q.length, function(t) {
+ for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
+ return s.join("");
+ });
+}
+
+function value(a, b) {
+ var t = typeof b, c;
+ return b == null || t === "boolean" ? constant(b)
+ : (t === "number" ? number
+ : t === "string" ? ((c = d3Color.color(b)) ? (b = c, rgb) : string)
+ : b instanceof d3Color.color ? rgb
+ : b instanceof Date ? date
+ : isNumberArray(b) ? numberArray
+ : Array.isArray(b) ? genericArray
+ : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object
+ : number)(a, b);
+}
+
+function discrete(range) {
+ var n = range.length;
+ return function(t) {
+ return range[Math.max(0, Math.min(n - 1, Math.floor(t * n)))];
+ };
+}
+
+function hue(a, b) {
+ var i = hue$1(+a, +b);
+ return function(t) {
+ var x = i(t);
+ return x - 360 * Math.floor(x / 360);
+ };
+}
+
+function round(a, b) {
+ return a = +a, b = +b, function(t) {
+ return Math.round(a * (1 - t) + b * t);
+ };
+}
+
+var degrees = 180 / Math.PI;
+
+var identity = {
+ translateX: 0,
+ translateY: 0,
+ rotate: 0,
+ skewX: 0,
+ scaleX: 1,
+ scaleY: 1
+};
+
+function decompose(a, b, c, d, e, f) {
+ var scaleX, scaleY, skewX;
+ if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
+ if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
+ if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
+ if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
+ return {
+ translateX: e,
+ translateY: f,
+ rotate: Math.atan2(b, a) * degrees,
+ skewX: Math.atan(skewX) * degrees,
+ scaleX: scaleX,
+ scaleY: scaleY
+ };
+}
+
+var svgNode;
+
+/* eslint-disable no-undef */
+function parseCss(value) {
+ const m = new (typeof DOMMatrix === "function" ? DOMMatrix : WebKitCSSMatrix)(value + "");
+ return m.isIdentity ? identity : decompose(m.a, m.b, m.c, m.d, m.e, m.f);
+}
+
+function parseSvg(value) {
+ if (value == null) return identity;
+ if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
+ svgNode.setAttribute("transform", value);
+ if (!(value = svgNode.transform.baseVal.consolidate())) return identity;
+ value = value.matrix;
+ return decompose(value.a, value.b, value.c, value.d, value.e, value.f);
+}
+
+function interpolateTransform(parse, pxComma, pxParen, degParen) {
+
+ function pop(s) {
+ return s.length ? s.pop() + " " : "";
+ }
+
+ function translate(xa, ya, xb, yb, s, q) {
+ if (xa !== xb || ya !== yb) {
+ var i = s.push("translate(", null, pxComma, null, pxParen);
+ q.push({i: i - 4, x: number(xa, xb)}, {i: i - 2, x: number(ya, yb)});
+ } else if (xb || yb) {
+ s.push("translate(" + xb + pxComma + yb + pxParen);
+ }
+ }
+
+ function rotate(a, b, s, q) {
+ if (a !== b) {
+ if (a - b > 180) b += 360; else if (b - a > 180) a += 360; // shortest path
+ q.push({i: s.push(pop(s) + "rotate(", null, degParen) - 2, x: number(a, b)});
+ } else if (b) {
+ s.push(pop(s) + "rotate(" + b + degParen);
+ }
+ }
+
+ function skewX(a, b, s, q) {
+ if (a !== b) {
+ q.push({i: s.push(pop(s) + "skewX(", null, degParen) - 2, x: number(a, b)});
+ } else if (b) {
+ s.push(pop(s) + "skewX(" + b + degParen);
+ }
+ }
+
+ function scale(xa, ya, xb, yb, s, q) {
+ if (xa !== xb || ya !== yb) {
+ var i = s.push(pop(s) + "scale(", null, ",", null, ")");
+ q.push({i: i - 4, x: number(xa, xb)}, {i: i - 2, x: number(ya, yb)});
+ } else if (xb !== 1 || yb !== 1) {
+ s.push(pop(s) + "scale(" + xb + "," + yb + ")");
+ }
+ }
+
+ return function(a, b) {
+ var s = [], // string constants and placeholders
+ q = []; // number interpolators
+ a = parse(a), b = parse(b);
+ translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
+ rotate(a.rotate, b.rotate, s, q);
+ skewX(a.skewX, b.skewX, s, q);
+ scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
+ a = b = null; // gc
+ return function(t) {
+ var i = -1, n = q.length, o;
+ while (++i < n) s[(o = q[i]).i] = o.x(t);
+ return s.join("");
+ };
+ };
+}
+
+var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)");
+var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")");
+
+var epsilon2 = 1e-12;
+
+function cosh(x) {
+ return ((x = Math.exp(x)) + 1 / x) / 2;
+}
+
+function sinh(x) {
+ return ((x = Math.exp(x)) - 1 / x) / 2;
+}
+
+function tanh(x) {
+ return ((x = Math.exp(2 * x)) - 1) / (x + 1);
+}
+
+var zoom = (function zoomRho(rho, rho2, rho4) {
+
+ // p0 = [ux0, uy0, w0]
+ // p1 = [ux1, uy1, w1]
+ function zoom(p0, p1) {
+ var ux0 = p0[0], uy0 = p0[1], w0 = p0[2],
+ ux1 = p1[0], uy1 = p1[1], w1 = p1[2],
+ dx = ux1 - ux0,
+ dy = uy1 - uy0,
+ d2 = dx * dx + dy * dy,
+ i,
+ S;
+
+ // Special case for u0 ≅ u1.
+ if (d2 < epsilon2) {
+ S = Math.log(w1 / w0) / rho;
+ i = function(t) {
+ return [
+ ux0 + t * dx,
+ uy0 + t * dy,
+ w0 * Math.exp(rho * t * S)
+ ];
+ };
+ }
+
+ // General case.
+ else {
+ var d1 = Math.sqrt(d2),
+ b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
+ b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
+ r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
+ r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
+ S = (r1 - r0) / rho;
+ i = function(t) {
+ var s = t * S,
+ coshr0 = cosh(r0),
+ u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
+ return [
+ ux0 + u * dx,
+ uy0 + u * dy,
+ w0 * coshr0 / cosh(rho * s + r0)
+ ];
+ };
+ }
+
+ i.duration = S * 1000 * rho / Math.SQRT2;
+
+ return i;
+ }
+
+ zoom.rho = function(_) {
+ var _1 = Math.max(1e-3, +_), _2 = _1 * _1, _4 = _2 * _2;
+ return zoomRho(_1, _2, _4);
+ };
+
+ return zoom;
+})(Math.SQRT2, 2, 4);
+
+function hsl(hue) {
+ return function(start, end) {
+ var h = hue((start = d3Color.hsl(start)).h, (end = d3Color.hsl(end)).h),
+ s = nogamma(start.s, end.s),
+ l = nogamma(start.l, end.l),
+ opacity = nogamma(start.opacity, end.opacity);
+ return function(t) {
+ start.h = h(t);
+ start.s = s(t);
+ start.l = l(t);
+ start.opacity = opacity(t);
+ return start + "";
+ };
+ }
+}
+
+var hsl$1 = hsl(hue$1);
+var hslLong = hsl(nogamma);
+
+function lab(start, end) {
+ var l = nogamma((start = d3Color.lab(start)).l, (end = d3Color.lab(end)).l),
+ a = nogamma(start.a, end.a),
+ b = nogamma(start.b, end.b),
+ opacity = nogamma(start.opacity, end.opacity);
+ return function(t) {
+ start.l = l(t);
+ start.a = a(t);
+ start.b = b(t);
+ start.opacity = opacity(t);
+ return start + "";
+ };
+}
+
+function hcl(hue) {
+ return function(start, end) {
+ var h = hue((start = d3Color.hcl(start)).h, (end = d3Color.hcl(end)).h),
+ c = nogamma(start.c, end.c),
+ l = nogamma(start.l, end.l),
+ opacity = nogamma(start.opacity, end.opacity);
+ return function(t) {
+ start.h = h(t);
+ start.c = c(t);
+ start.l = l(t);
+ start.opacity = opacity(t);
+ return start + "";
+ };
+ }
+}
+
+var hcl$1 = hcl(hue$1);
+var hclLong = hcl(nogamma);
+
+function cubehelix(hue) {
+ return (function cubehelixGamma(y) {
+ y = +y;
+
+ function cubehelix(start, end) {
+ var h = hue((start = d3Color.cubehelix(start)).h, (end = d3Color.cubehelix(end)).h),
+ s = nogamma(start.s, end.s),
+ l = nogamma(start.l, end.l),
+ opacity = nogamma(start.opacity, end.opacity);
+ return function(t) {
+ start.h = h(t);
+ start.s = s(t);
+ start.l = l(Math.pow(t, y));
+ start.opacity = opacity(t);
+ return start + "";
+ };
+ }
+
+ cubehelix.gamma = cubehelixGamma;
+
+ return cubehelix;
+ })(1);
+}
+
+var cubehelix$1 = cubehelix(hue$1);
+var cubehelixLong = cubehelix(nogamma);
+
+function piecewise(interpolate, values) {
+ if (values === undefined) values = interpolate, interpolate = value;
+ var i = 0, n = values.length - 1, v = values[0], I = new Array(n < 0 ? 0 : n);
+ while (i < n) I[i] = interpolate(v, v = values[++i]);
+ return function(t) {
+ var i = Math.max(0, Math.min(n - 1, Math.floor(t *= n)));
+ return I[i](t - i);
+ };
+}
+
+function quantize(interpolator, n) {
+ var samples = new Array(n);
+ for (var i = 0; i < n; ++i) samples[i] = interpolator(i / (n - 1));
+ return samples;
+}
+
+exports.interpolate = value;
+exports.interpolateArray = array;
+exports.interpolateBasis = basis$1;
+exports.interpolateBasisClosed = basisClosed;
+exports.interpolateCubehelix = cubehelix$1;
+exports.interpolateCubehelixLong = cubehelixLong;
+exports.interpolateDate = date;
+exports.interpolateDiscrete = discrete;
+exports.interpolateHcl = hcl$1;
+exports.interpolateHclLong = hclLong;
+exports.interpolateHsl = hsl$1;
+exports.interpolateHslLong = hslLong;
+exports.interpolateHue = hue;
+exports.interpolateLab = lab;
+exports.interpolateNumber = number;
+exports.interpolateNumberArray = numberArray;
+exports.interpolateObject = object;
+exports.interpolateRgb = rgb;
+exports.interpolateRgbBasis = rgbBasis;
+exports.interpolateRgbBasisClosed = rgbBasisClosed;
+exports.interpolateRound = round;
+exports.interpolateString = string;
+exports.interpolateTransformCss = interpolateTransformCss;
+exports.interpolateTransformSvg = interpolateTransformSvg;
+exports.interpolateZoom = zoom;
+exports.piecewise = piecewise;
+exports.quantize = quantize;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
diff --git a/node_modules/d3-interpolate/dist/d3-interpolate.min.js b/node_modules/d3-interpolate/dist/d3-interpolate.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..d1b626367009128c02c3918b1785110df28ec120
--- /dev/null
+++ b/node_modules/d3-interpolate/dist/d3-interpolate.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-interpolate/ v3.0.1 Copyright 2010-2021 Mike Bostock
+!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("d3-color")):"function"==typeof define&&define.amd?define(["exports","d3-color"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).d3=t.d3||{},t.d3)}(this,(function(t,n){"use strict";function r(t,n,r,e,a){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*r+(1+3*t+3*o-3*u)*e+u*a)/6}function e(t){var n=t.length-1;return function(e){var a=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),o=t[a],u=t[a+1],i=a>0?t[a-1]:2*o-u,c=a=0))throw new Error(`invalid digits: ${t}`);if(i>15)return n;const s=10**i;return function(t){this._+=t[0];for(let i=1,h=t.length;i
# time.ticks([interval])
+
+Returns representative dates from the scale’s [domain](#time_domain). The returned tick values are uniformly-spaced (mostly), have sensible values (such as every day at midnight), and are guaranteed to be within the extent of the domain. Ticks are often used to display reference lines, or tick marks, in conjunction with the visualized data.
+
+An optional *count* may be specified to affect how many ticks are generated. If *count* is not specified, it defaults to 10. The specified *count* is only a hint; the scale may return more or fewer values depending on the domain. For example, to create ten default ticks, say:
+
+```js
+var x = d3.scaleTime();
+
+x.ticks(10);
+// [Sat Jan 01 2000 00:00:00 GMT-0800 (PST),
+// Sat Jan 01 2000 03:00:00 GMT-0800 (PST),
+// Sat Jan 01 2000 06:00:00 GMT-0800 (PST),
+// Sat Jan 01 2000 09:00:00 GMT-0800 (PST),
+// Sat Jan 01 2000 12:00:00 GMT-0800 (PST),
+// Sat Jan 01 2000 15:00:00 GMT-0800 (PST),
+// Sat Jan 01 2000 18:00:00 GMT-0800 (PST),
+// Sat Jan 01 2000 21:00:00 GMT-0800 (PST),
+// Sun Jan 02 2000 00:00:00 GMT-0800 (PST)]
+```
+
+The following time intervals are considered for automatic ticks:
+
+* 1-, 5-, 15- and 30-second.
+* 1-, 5-, 15- and 30-minute.
+* 1-, 3-, 6- and 12-hour.
+* 1- and 2-day.
+* 1-week.
+* 1- and 3-month.
+* 1-year.
+
+In lieu of a *count*, a [time *interval*](https://github.com/d3/d3-time/blob/master/README.md#intervals) may be explicitly specified. To prune the generated ticks for a given time *interval*, use [*interval*.every](https://github.com/d3/d3-time/blob/master/README.md#interval_every). For example, to generate ticks at 15-[minute](https://github.com/d3/d3-time/blob/master/README.md#minute) intervals:
+
+```js
+var x = d3.scaleTime()
+ .domain([new Date(2000, 0, 1, 0), new Date(2000, 0, 1, 2)]);
+
+x.ticks(d3.timeMinute.every(15));
+// [Sat Jan 01 2000 00:00:00 GMT-0800 (PST),
+// Sat Jan 01 2000 00:15:00 GMT-0800 (PST),
+// Sat Jan 01 2000 00:30:00 GMT-0800 (PST),
+// Sat Jan 01 2000 00:45:00 GMT-0800 (PST),
+// Sat Jan 01 2000 01:00:00 GMT-0800 (PST),
+// Sat Jan 01 2000 01:15:00 GMT-0800 (PST),
+// Sat Jan 01 2000 01:30:00 GMT-0800 (PST),
+// Sat Jan 01 2000 01:45:00 GMT-0800 (PST),
+// Sat Jan 01 2000 02:00:00 GMT-0800 (PST)]
+```
+
+Alternatively, pass a test function to [*interval*.filter](https://github.com/d3/d3-time/blob/master/README.md#interval_filter):
+
+```js
+x.ticks(d3.timeMinute.filter(function(d) {
+ return d.getMinutes() % 15 === 0;
+}));
+```
+
+Note: in some cases, such as with day ticks, specifying a *step* can result in irregular spacing of ticks because time intervals have varying length.
+
+# time.tickFormat([count[, specifier]]) · [Source](https://github.com/d3/d3-scale/blob/master/src/time.js), [Examples](https://observablehq.com/@d3/scale-ticks)
+
# time.tickFormat([interval[, specifier]])
+
+Returns a time format function suitable for displaying [tick](#time_ticks) values. The specified *count* or *interval* is currently ignored, but is accepted for consistency with other scales such as [*continuous*.tickFormat](#continuous_tickFormat). If a format *specifier* is specified, this method is equivalent to [format](https://github.com/d3/d3-time-format/blob/master/README.md#format). If *specifier* is not specified, the default time format is returned. The default multi-scale time format chooses a human-readable representation based on the specified date as follows:
+
+* `%Y` - for year boundaries, such as `2011`.
+* `%B` - for month boundaries, such as `February`.
+* `%b %d` - for week boundaries, such as `Feb 06`.
+* `%a %d` - for day boundaries, such as `Mon 07`.
+* `%I %p` - for hour boundaries, such as `01 AM`.
+* `%I:%M` - for minute boundaries, such as `01:23`.
+* `:%S` - for second boundaries, such as `:45`.
+* `.%L` - milliseconds for all other times, such as `.012`.
+
+Although somewhat unusual, this default behavior has the benefit of providing both local and global context: for example, formatting a sequence of ticks as [11 PM, Mon 07, 01 AM] reveals information about hours, dates, and day simultaneously, rather than just the hours [11 PM, 12 AM, 01 AM]. See [d3-time-format](https://github.com/d3/d3-time-format) if you’d like to roll your own conditional time format.
+
+# time.nice([count]) · [Source](https://github.com/d3/d3-scale/blob/master/src/time.js), [Examples](https://observablehq.com/@d3/d3-scaletime)
+
# time.nice([interval])
+
+Extends the [domain](#time_domain) so that it starts and ends on nice round values. This method typically modifies the scale’s domain, and may only extend the bounds to the nearest round value. See [*continuous*.nice](#continuous_nice) for more.
+
+An optional tick *count* argument allows greater control over the step size used to extend the bounds, guaranteeing that the returned [ticks](#time_ticks) will exactly cover the domain. Alternatively, a [time *interval*](https://github.com/d3/d3-time/blob/master/README.md#intervals) may be specified to explicitly set the ticks. If an *interval* is specified, an optional *step* may also be specified to skip some ticks. For example, `time.nice(d3.timeSecond.every(10))` will extend the domain to an even ten seconds (0, 10, 20, etc.). See [*time*.ticks](#time_ticks) and [*interval*.every](https://github.com/d3/d3-time/blob/master/README.md#interval_every) for further detail.
+
+Nicing is useful if the domain is computed from data, say using [extent](https://github.com/d3/d3-array/blob/master/README.md#extent), and may be irregular. For example, for a domain of [2009-07-13T00:02, 2009-07-13T23:48], the nice domain is [2009-07-13, 2009-07-14]. If the domain has more than two values, nicing the domain only affects the first and last value.
+
+# time.copy() · [Source](https://github.com/d3/d3-scale/blob/master/src/time.js), [Examples](https://observablehq.com/@d3/d3-scaletime)
+
+See [*continuous*.copy](#continuous_copy).
+
+# d3.scaleUtc([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/utcTime.js), [Examples](https://observablehq.com/@d3/d3-scaletime)
+
+Equivalent to [scaleTime](#scaleTime), but the returned time scale operates in [Coordinated Universal Time](https://en.wikipedia.org/wiki/Coordinated_Universal_Time) rather than local time.
+
+### Sequential Scales
+
+Sequential scales, like [diverging scales](#diverging-scales), are similar to [continuous scales](#continuous-scales) in that they map a continuous, numeric input domain to a continuous output range. However, unlike continuous scales, the input domain and output range of a sequential scale always has exactly two elements, and the output range is typically specified as an interpolator rather than an array of values. These scales do not expose [invert](#continuous_invert) and [interpolate](#continuous_interpolate) methods.
+
+# d3.scaleSequential([[domain, ]interpolator]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+Constructs a new sequential scale with the specified [*domain*](#sequential_domain) and [*interpolator*](#sequential_interpolator) function or array. If *domain* is not specified, it defaults to [0, 1]. If *interpolator* is not specified, it defaults to the identity function. When the scale is [applied](#_sequential), the interpolator will be invoked with a value typically in the range [0, 1], where 0 represents the minimum value and 1 represents the maximum value. For example, to implement the ill-advised [HSL](https://github.com/d3/d3-color/blob/master/README.md#hsl) rainbow scale:
+
+```js
+var rainbow = d3.scaleSequential(function(t) {
+ return d3.hsl(t * 360, 1, 0.5) + "";
+});
+```
+
+A more aesthetically-pleasing and perceptually-effective cyclical hue encoding is to use [d3.interpolateRainbow](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#interpolateRainbow):
+
+```js
+var rainbow = d3.scaleSequential(d3.interpolateRainbow);
+```
+
+If *interpolator* is an array, it represents the scale’s two-element output range and is converted to an interpolator function using [d3.interpolate](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolate).
+
+# sequential(value) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+See [*continuous*](#_continuous).
+
+# sequential.domain([domain]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+See [*continuous*.domain](#continuous_domain). Note that a sequential scale’s domain must be numeric and must contain exactly two values.
+
+# sequential.clamp([clamp]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+See [*continuous*.clamp](#continuous_clamp).
+
+# sequential.interpolator([interpolator]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+If *interpolator* is specified, sets the scale’s interpolator to the specified function. If *interpolator* is not specified, returns the scale’s current interpolator.
+
+# sequential.range([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+See [*continuous*.range](#continuous_range). If *range* is specified, the given two-element array is converted to an interpolator function using [d3.interpolate](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolate).
+
+# sequential.rangeRound([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+See [*continuous*.rangeRound](#continuous_rangeRound). If *range* is specified, implicitly uses [d3.interpolateRound](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateRound) as the interpolator.
+
+# sequential.copy() · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+See [*continuous*.copy](#continuous_copy).
+
+# d3.scaleSequentialLog([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+A [sequential scale](#sequential-scales) with a logarithmic transform, analogous to a [log scale](#log-scales).
+
+# d3.scaleSequentialPow([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+A [sequential scale](#sequential-scales) with an exponential transform, analogous to a [power scale](#pow-scales).
+
+# d3.scaleSequentialSqrt([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+A [sequential scale](#sequential-scales) with a square-root transform, analogous to a [d3.scaleSqrt](#scaleSqrt).
+
+# d3.scaleSequentialSymlog([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+A [sequential scale](#sequential-scales) with a symmetric logarithmic transform, analogous to a [symlog scale](#symlog-scales).
+
+# d3.scaleSequentialQuantile([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequentialQuantile.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+A [sequential scale](#sequential-scales) using a *p*-quantile transform, analogous to a [quantile scale](#quantile-scales).
+
+# sequentialQuantile.quantiles(n) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequentialQuantile.js), [Examples](https://observablehq.com/@d3/sequential-scales)
+
+Returns an array of *n* + 1 quantiles. For example, if *n* = 4, returns an array of five numbers: the minimum value, the first quartile, the median, the third quartile, and the maximum.
+
+### Diverging Scales
+
+Diverging scales, like [sequential scales](#sequential-scales), are similar to [continuous scales](#continuous-scales) in that they map a continuous, numeric input domain to a continuous output range. However, unlike continuous scales, the input domain and output range of a diverging scale always has exactly three elements, and the output range is typically specified as an interpolator rather than an array of values. These scales do not expose [invert](#continuous_invert) and [interpolate](#continuous_interpolate) methods.
+
+# d3.scaleDiverging([[domain, ]interpolator]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+Constructs a new diverging scale with the specified [*domain*](#diverging_domain) and [*interpolator*](#diverging_interpolator) function or array. If *domain* is not specified, it defaults to [0, 0.5, 1]. If *interpolator* is not specified, it defaults to the identity function. When the scale is [applied](#_diverging), the interpolator will be invoked with a value typically in the range [0, 1], where 0 represents the extreme negative value, 0.5 represents the neutral value, and 1 represents the extreme positive value. For example, using [d3.interpolateSpectral](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#interpolateSpectral):
+
+```js
+var spectral = d3.scaleDiverging(d3.interpolateSpectral);
+```
+
+If *interpolator* is an array, it represents the scale’s three-element output range and is converted to an interpolator function using [d3.interpolate](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolate) and [d3.piecewise](https://github.com/d3/d3-interpolate/blob/master/README.md#piecewise).
+
+# diverging(value) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+See [*continuous*](#_continuous).
+
+# diverging.domain([domain]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+See [*continuous*.domain](#continuous_domain). Note that a diverging scale’s domain must be numeric and must contain exactly three values. The default domain is [0, 0.5, 1].
+
+# diverging.clamp([clamp]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+See [*continuous*.clamp](#continuous_clamp).
+
+# diverging.interpolator([interpolator]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+If *interpolator* is specified, sets the scale’s interpolator to the specified function. If *interpolator* is not specified, returns the scale’s current interpolator.
+
+# diverging.range([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+See [*continuous*.range](#continuous_range). If *range* is specified, the given three-element array is converted to an interpolator function using [d3.interpolate](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolate) and [d3.piecewise](https://github.com/d3/d3-interpolate/blob/master/README.md#piecewise).
+
+# diverging.rangeRound([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+See [*continuous*.range](#continuous_rangeRound). If *range* is specified, implicitly uses [d3.interpolateRound](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateRound) as the interpolator.
+
+# diverging.copy() · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+See [*continuous*.copy](#continuous_copy).
+
+# diverging.unknown() · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+See [*continuous*.unknown](#continuous_unknown).
+
+# d3.scaleDivergingLog([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+A [diverging scale](#diverging-scales) with a logarithmic transform, analogous to a [log scale](#log-scales).
+
+# d3.scaleDivergingPow([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+A [diverging scale](#diverging-scales) with an exponential transform, analogous to a [power scale](#pow-scales).
+
+# d3.scaleDivergingSqrt([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+A [diverging scale](#diverging-scales) with a square-root transform, analogous to a [d3.scaleSqrt](#scaleSqrt).
+
+# d3.scaleDivergingSymlog([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
+
+A [diverging scale](#diverging-scales) with a symmetric logarithmic transform, analogous to a [symlog scale](#symlog-scales).
+
+### Quantize Scales
+
+Quantize scales are similar to [linear scales](#linear-scales), except they use a discrete rather than continuous range. The continuous input domain is divided into uniform segments based on the number of values in (*i.e.*, the cardinality of) the output range. Each range value *y* can be expressed as a quantized linear function of the domain value *x*: *y* = *m round(x)* + *b*. See [this choropleth](https://observablehq.com/@d3/choropleth) for an example.
+
+# d3.scaleQuantize([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Constructs a new quantize scale with the specified [*domain*](#quantize_domain) and [*range*](#quantize_range). If either *domain* or *range* is not specified, each defaults to [0, 1]. Thus, the default quantize scale is equivalent to the [Math.round](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Math/round) function.
+
+# quantize(value) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Given a *value* in the input [domain](#quantize_domain), returns the corresponding value in the output [range](#quantize_range). For example, to apply a color encoding:
+
+```js
+var color = d3.scaleQuantize()
+ .domain([0, 1])
+ .range(["brown", "steelblue"]);
+
+color(0.49); // "brown"
+color(0.51); // "steelblue"
+```
+
+Or dividing the domain into three equally-sized parts with different range values to compute an appropriate stroke width:
+
+```js
+var width = d3.scaleQuantize()
+ .domain([10, 100])
+ .range([1, 2, 4]);
+
+width(20); // 1
+width(50); // 2
+width(80); // 4
+```
+
+# quantize.invertExtent(value) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Returns the extent of values in the [domain](#quantize_domain) [x0, x1] for the corresponding *value* in the [range](#quantize_range): the inverse of [*quantize*](#_quantize). This method is useful for interaction, say to determine the value in the domain that corresponds to the pixel location under the mouse.
+
+```js
+var width = d3.scaleQuantize()
+ .domain([10, 100])
+ .range([1, 2, 4]);
+
+width.invertExtent(2); // [40, 70]
+```
+
+# quantize.domain([domain]) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+If *domain* is specified, sets the scale’s domain to the specified two-element array of numbers. If the elements in the given array are not numbers, they will be coerced to numbers. The numbers must be in ascending order or the behavior of the scale is undefined. If *domain* is not specified, returns the scale’s current domain.
+
+# quantize.range([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+If *range* is specified, sets the scale’s range to the specified array of values. The array may contain any number of discrete values. The elements in the given array need not be numbers; any value or type will work. If *range* is not specified, returns the scale’s current range.
+
+# quantize.ticks([count]) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/scale-ticks)
+
+Equivalent to [*continuous*.ticks](#continuous_ticks).
+
+# quantize.tickFormat([count[, specifier]]) · [Source](https://github.com/d3/d3-scale/blob/master/src/linear.js), [Examples](https://observablehq.com/@d3/scale-ticks)
+
+Equivalent to [*continuous*.tickFormat](#continuous_tickFormat).
+
+# quantize.nice() · [Source](https://github.com/d3/d3-scale/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Equivalent to [*continuous*.nice](#continuous_nice).
+
+# quantize.thresholds() · [Source](https://github.com/d3/d3-scale/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Returns the array of computed thresholds within the [domain](#quantize_domain).
+
+# quantize.copy() · [Source](https://github.com/d3/d3-scale/blob/master/src/quantize.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Returns an exact copy of this scale. Changes to this scale will not affect the returned scale, and vice versa.
+
+### Quantile Scales
+
+Quantile scales map a sampled input domain to a discrete range. The domain is considered continuous and thus the scale will accept any reasonable input value; however, the domain is specified as a discrete set of sample values. The number of values in (the cardinality of) the output range determines the number of quantiles that will be computed from the domain. To compute the quantiles, the domain is sorted, and treated as a [population of discrete values](https://en.wikipedia.org/wiki/Quantile#Quantiles_of_a_population); see d3-array’s [quantile](https://github.com/d3/d3-array/blob/master/README.md#quantile). See [this quantile choropleth](https://observablehq.com/@d3/quantile-choropleth) for an example.
+
+# d3.scaleQuantile([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantile.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Constructs a new quantile scale with the specified [*domain*](#quantile_domain) and [*range*](#quantile_range). If either *domain* or *range* is not specified, each defaults to the empty array. The quantile scale is invalid until both a domain and range are specified.
+
+# quantile(value) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantile.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Given a *value* in the input [domain](#quantile_domain), returns the corresponding value in the output [range](#quantile_range).
+
+# quantile.invertExtent(value) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantile.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Returns the extent of values in the [domain](#quantile_domain) [x0, x1] for the corresponding *value* in the [range](#quantile_range): the inverse of [*quantile*](#_quantile). This method is useful for interaction, say to determine the value in the domain that corresponds to the pixel location under the mouse.
+
+# quantile.domain([domain]) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantile.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+If *domain* is specified, sets the domain of the quantile scale to the specified set of discrete numeric values. The array must not be empty, and must contain at least one numeric value; NaN, null and undefined values are ignored and not considered part of the sample population. If the elements in the given array are not numbers, they will be coerced to numbers. A copy of the input array is sorted and stored internally. If *domain* is not specified, returns the scale’s current domain.
+
+# quantile.range([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/quantile.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+If *range* is specified, sets the discrete values in the range. The array must not be empty, and may contain any type of value. The number of values in (the cardinality, or length, of) the *range* array determines the number of quantiles that are computed. For example, to compute quartiles, *range* must be an array of four elements such as [0, 1, 2, 3]. If *range* is not specified, returns the current range.
+
+# quantile.quantiles() · [Source](https://github.com/d3/d3-scale/blob/master/src/quantile.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Returns the quantile thresholds. If the [range](#quantile_range) contains *n* discrete values, the returned array will contain *n* - 1 thresholds. Values less than the first threshold are considered in the first quantile; values greater than or equal to the first threshold but less than the second threshold are in the second quantile, and so on. Internally, the thresholds array is used with [bisect](https://github.com/d3/d3-array/blob/master/README.md#bisect) to find the output quantile associated with the given input value.
+
+# quantile.copy() · [Source](https://github.com/d3/d3-scale/blob/master/src/quantile.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Returns an exact copy of this scale. Changes to this scale will not affect the returned scale, and vice versa.
+
+### Threshold Scales
+
+Threshold scales are similar to [quantize scales](#quantize-scales), except they allow you to map arbitrary subsets of the domain to discrete values in the range. The input domain is still continuous, and divided into slices based on a set of threshold values. See [this choropleth](https://observablehq.com/@d3/threshold-choropleth) for an example.
+
+# d3.scaleThreshold([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/threshold.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Constructs a new threshold scale with the specified [*domain*](#threshold_domain) and [*range*](#threshold_range). If *domain* is not specified, it defaults to [0.5]. If *range* is not specified, it defaults to [0, 1]. Thus, the default threshold scale is equivalent to the [Math.round](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Math/round) function for numbers; for example threshold(0.49) returns 0, and threshold(0.51) returns 1.
+
+# threshold(value) · [Source](https://github.com/d3/d3-scale/blob/master/src/threshold.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Given a *value* in the input [domain](#threshold_domain), returns the corresponding value in the output [range](#threshold_range). For example:
+
+```js
+var color = d3.scaleThreshold()
+ .domain([0, 1])
+ .range(["red", "white", "green"]);
+
+color(-1); // "red"
+color(0); // "white"
+color(0.5); // "white"
+color(1); // "green"
+color(1000); // "green"
+```
+
+# threshold.invertExtent(value) · [Source](https://github.com/d3/d3-scale/blob/master/src/threshold.js), [Examples](https://observablehq.com/@d3/choropleth)
+
+Returns the extent of values in the [domain](#threshold_domain) [x0, x1] for the corresponding *value* in the [range](#threshold_range), representing the inverse mapping from range to domain. This method is useful for interaction, say to determine the value in the domain that corresponds to the pixel location under the mouse. For example:
+
+```js
+var color = d3.scaleThreshold()
+ .domain([0, 1])
+ .range(["red", "white", "green"]);
+
+color.invertExtent("red"); // [undefined, 0]
+color.invertExtent("white"); // [0, 1]
+color.invertExtent("green"); // [1, undefined]
+```
+
+# threshold.domain([domain]) · [Source](https://github.com/d3/d3-scale/blob/master/src/threshold.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+If *domain* is specified, sets the scale’s domain to the specified array of values. The values must be in ascending order or the behavior of the scale is undefined. The values are typically numbers, but any naturally ordered values (such as strings) will work; a threshold scale can be used to encode any type that is ordered. If the number of values in the scale’s range is N+1, the number of values in the scale’s domain must be N. If there are fewer than N elements in the domain, the additional values in the range are ignored. If there are more than N elements in the domain, the scale may return undefined for some inputs. If *domain* is not specified, returns the scale’s current domain.
+
+# threshold.range([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/threshold.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+If *range* is specified, sets the scale’s range to the specified array of values. If the number of values in the scale’s domain is N, the number of values in the scale’s range must be N+1. If there are fewer than N+1 elements in the range, the scale may return undefined for some inputs. If there are more than N+1 elements in the range, the additional values are ignored. The elements in the given array need not be numbers; any value or type will work. If *range* is not specified, returns the scale’s current range.
+
+# threshold.copy() · [Source](https://github.com/d3/d3-scale/blob/master/src/threshold.js), [Examples](https://observablehq.com/@d3/quantile-quantize-and-threshold-scales)
+
+Returns an exact copy of this scale. Changes to this scale will not affect the returned scale, and vice versa.
+
+### Ordinal Scales
+
+Unlike [continuous scales](#continuous-scales), ordinal scales have a discrete domain and range. For example, an ordinal scale might map a set of named categories to a set of colors, or determine the horizontal positions of columns in a column chart.
+
+# d3.scaleOrdinal([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/ordinal.js), [Examples](https://observablehq.com/@d3/d3-scaleordinal)
+
+Constructs a new ordinal scale with the specified [*domain*](#ordinal_domain) and [*range*](#ordinal_range). If *domain* is not specified, it defaults to the empty array. If *range* is not specified, it defaults to the empty array; an ordinal scale always returns undefined until a non-empty range is defined.
+
+# ordinal(value) · [Source](https://github.com/d3/d3-scale/blob/master/src/ordinal.js), [Examples](https://observablehq.com/@d3/d3-scaleordinal)
+
+Given a *value* in the input [domain](#ordinal_domain), returns the corresponding value in the output [range](#ordinal_range). If the given *value* is not in the scale’s [domain](#ordinal_domain), returns the [unknown](#ordinal_unknown); or, if the unknown value is [implicit](#scaleImplicit) (the default), then the *value* is implicitly added to the domain and the next-available value in the range is assigned to *value*, such that this and subsequent invocations of the scale given the same input *value* return the same output value.
+
+# ordinal.domain([domain]) · [Source](https://github.com/d3/d3-scale/blob/master/src/ordinal.js), [Examples](https://observablehq.com/@d3/d3-scaleordinal)
+
+If *domain* is specified, sets the domain to the specified array of values. The first element in *domain* will be mapped to the first element in the range, the second domain value to the second range value, and so on. Domain values are stored internally in an [InternMap](https://github.com/mbostock/internmap) from primitive value to index; the resulting index is then used to retrieve a value from the range. Thus, an ordinal scale’s values must be coercible to a primitive value, and the primitive domain value uniquely identifies the corresponding range value. If *domain* is not specified, this method returns the current domain.
+
+Setting the domain on an ordinal scale is optional if the [unknown value](#ordinal_unknown) is [implicit](#scaleImplicit) (the default). In this case, the domain will be inferred implicitly from usage by assigning each unique value passed to the scale a new value from the range. Note that an explicit domain is recommended to ensure deterministic behavior, as inferring the domain from usage will be dependent on ordering.
+
+# ordinal.range([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/ordinal.js), [Examples](https://observablehq.com/@d3/d3-scaleordinal)
+
+If *range* is specified, sets the range of the ordinal scale to the specified array of values. The first element in the domain will be mapped to the first element in *range*, the second domain value to the second range value, and so on. If there are fewer elements in the range than in the domain, the scale will reuse values from the start of the range. If *range* is not specified, this method returns the current range.
+
+# ordinal.unknown([value]) · [Source](https://github.com/d3/d3-scale/blob/master/src/ordinal.js), [Examples](https://observablehq.com/@d3/d3-scaleordinal)
+
+If *value* is specified, sets the output value of the scale for unknown input values and returns this scale. If *value* is not specified, returns the current unknown value, which defaults to [implicit](#scaleImplicit). The implicit value enables implicit domain construction; see [*ordinal*.domain](#ordinal_domain).
+
+# ordinal.copy() · [Source](https://github.com/d3/d3-scale/blob/master/src/ordinal.js), [Examples](https://observablehq.com/@d3/d3-scaleordinal)
+
+Returns an exact copy of this ordinal scale. Changes to this scale will not affect the returned scale, and vice versa.
+
+# d3.scaleImplicit · [Source](https://github.com/d3/d3-scale/blob/master/src/ordinal.js), [Examples](https://observablehq.com/@d3/d3-scaleordinal)
+
+A special value for [*ordinal*.unknown](#ordinal_unknown) that enables implicit domain construction: unknown values are implicitly added to the domain.
+
+#### Band Scales
+
+Band scales are like [ordinal scales](#ordinal-scales) except the output range is continuous and numeric. Discrete output values are automatically computed by the scale by dividing the continuous range into uniform bands. Band scales are typically used for bar charts with an ordinal or categorical dimension. The [unknown value](#ordinal_unknown) of a band scale is effectively undefined: they do not allow implicit domain construction.
+
+
+
+# d3.scaleBand([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+Constructs a new band scale with the specified [*domain*](#band_domain) and [*range*](#band_range), no [padding](#band_padding), no [rounding](#band_round) and center [alignment](#band_align). If *domain* is not specified, it defaults to the empty domain. If *range* is not specified, it defaults to the unit range [0, 1].
+
+# band(*value*) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+Given a *value* in the input [domain](#band_domain), returns the start of the corresponding band derived from the output [range](#band_range). If the given *value* is not in the scale’s domain, returns undefined.
+
+# band.domain([domain]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+If *domain* is specified, sets the domain to the specified array of values. The first element in *domain* will be mapped to the first band, the second domain value to the second band, and so on. Domain values are stored internally in an [InternMap](https://github.com/mbostock/internmap) from primitive value to index; the resulting index is then used to determine the band. Thus, a band scale’s values must be coercible to a primitive value, and the primitive domain value uniquely identifies the corresponding band. If *domain* is not specified, this method returns the current domain.
+
+# band.range([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+If *range* is specified, sets the scale’s range to the specified two-element array of numbers. If the elements in the given array are not numbers, they will be coerced to numbers. If *range* is not specified, returns the scale’s current range, which defaults to [0, 1].
+
+# band.rangeRound([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+Sets the scale’s [*range*](#band_range) to the specified two-element array of numbers while also enabling [rounding](#band_round). This is a convenience method equivalent to:
+
+```js
+band
+ .range(range)
+ .round(true);
+```
+
+Rounding is sometimes useful for avoiding antialiasing artifacts, though also consider the [shape-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering) “crispEdges” styles.
+
+# band.round([round]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+If *round* is specified, enables or disables rounding accordingly. If rounding is enabled, the start and stop of each band will be integers. Rounding is sometimes useful for avoiding antialiasing artifacts, though also consider the [shape-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering) “crispEdges” styles. Note that if the width of the domain is not a multiple of the cardinality of the range, there may be leftover unused space, even without padding! Use [*band*.align](#band_align) to specify how the leftover space is distributed.
+
+# band.paddingInner([padding]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+If *padding* is specified, sets the inner padding to the specified number which must be less than or equal to 1. If *padding* is not specified, returns the current inner padding which defaults to 0. The inner padding specifies the proportion of the range that is reserved for blank space between bands; a value of 0 means no blank space between bands, and a value of 1 means a [bandwidth](#band_bandwidth) of zero.
+
+# band.paddingOuter([padding]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+If *padding* is specified, sets the outer padding to the specified number which is typically in the range [0, 1]. If *padding* is not specified, returns the current outer padding which defaults to 0. The outer padding specifies the amount of blank space, in terms of multiples of the [step](#band_step), to reserve before the first band and after the last band.
+
+# band.padding([padding]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+A convenience method for setting the [inner](#band_paddingInner) and [outer](#band_paddingOuter) padding to the same *padding* value. If *padding* is not specified, returns the inner padding.
+
+# band.align([align]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+If *align* is specified, sets the alignment to the specified value which must be in the range [0, 1]. If *align* is not specified, returns the current alignment which defaults to 0.5. The alignment specifies how outer padding is distributed in the range. A value of 0.5 indicates that the outer padding should be equally distributed before the first band and after the last band; *i.e.*, the bands should be centered within the range. A value of 0 or 1 may be used to shift the bands to one side, say to position them adjacent to an axis. For more, [see this explainer](https://observablehq.com/@d3/band-align).
+
+# band.bandwidth() · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+Returns the width of each band.
+
+# band.step() · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+Returns the distance between the starts of adjacent bands.
+
+# band.copy() · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scaleband)
+
+Returns an exact copy of this scale. Changes to this scale will not affect the returned scale, and vice versa.
+
+#### Point Scales
+
+Point scales are a variant of [band scales](#band-scales) with the bandwidth fixed to zero. Point scales are typically used for scatterplots with an ordinal or categorical dimension. The [unknown value](#ordinal_unknown) of a point scale is always undefined: they do not allow implicit domain construction.
+
+
+
+# d3.scalePoint([[domain, ]range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+Constructs a new point scale with the specified [*domain*](#point_domain) and [*range*](#point_range), no [padding](#point_padding), no [rounding](#point_round) and center [alignment](#point_align). If *domain* is not specified, it defaults to the empty domain. If *range* is not specified, it defaults to the unit range [0, 1].
+
+# point(*value*) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+Given a *value* in the input [domain](#point_domain), returns the corresponding point derived from the output [range](#point_range). If the given *value* is not in the scale’s domain, returns undefined.
+
+# point.domain([domain]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+If *domain* is specified, sets the domain to the specified array of values. The first element in *domain* will be mapped to the first point, the second domain value to the second point, and so on. Domain values are stored internally in an [InternMap](https://github.com/mbostock/internmap) from primitive value to index; the resulting index is then used to determine the point. Thus, a point scale’s values must be coercible to a primitive value, and the primitive domain value uniquely identifies the corresponding point. If *domain* is not specified, this method returns the current domain.
+
+# point.range([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+If *range* is specified, sets the scale’s range to the specified two-element array of numbers. If the elements in the given array are not numbers, they will be coerced to numbers. If *range* is not specified, returns the scale’s current range, which defaults to [0, 1].
+
+# point.rangeRound([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+Sets the scale’s [*range*](#point_range) to the specified two-element array of numbers while also enabling [rounding](#point_round). This is a convenience method equivalent to:
+
+```js
+point
+ .range(range)
+ .round(true);
+```
+
+Rounding is sometimes useful for avoiding antialiasing artifacts, though also consider the [shape-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering) “crispEdges” styles.
+
+# point.round([round]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+If *round* is specified, enables or disables rounding accordingly. If rounding is enabled, the position of each point will be integers. Rounding is sometimes useful for avoiding antialiasing artifacts, though also consider the [shape-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering) “crispEdges” styles. Note that if the width of the domain is not a multiple of the cardinality of the range, there may be leftover unused space, even without padding! Use [*point*.align](#point_align) to specify how the leftover space is distributed.
+
+# point.padding([padding]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+If *padding* is specified, sets the outer padding to the specified number which is typically in the range [0, 1]. If *padding* is not specified, returns the current outer padding which defaults to 0. The outer padding specifies the amount of blank space, in terms of multiples of the [step](#band_step), to reserve before the first point and after the last point. Equivalent to [*band*.paddingOuter](#band_paddingOuter).
+
+# point.align([align]) · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+If *align* is specified, sets the alignment to the specified value which must be in the range [0, 1]. If *align* is not specified, returns the current alignment which defaults to 0.5. The alignment specifies how any leftover unused space in the range is distributed. A value of 0.5 indicates that the leftover space should be equally distributed before the first point and after the last point; *i.e.*, the points should be centered within the range. A value of 0 or 1 may be used to shift the points to one side, say to position them adjacent to an axis.
+
+# point.bandwidth() · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+Returns zero.
+
+# point.step() · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+Returns the distance between the starts of adjacent points.
+
+# point.copy() · [Source](https://github.com/d3/d3-scale/blob/master/src/band.js), [Examples](https://observablehq.com/@d3/d3-scalepoint)
+
+Returns an exact copy of this scale. Changes to this scale will not affect the returned scale, and vice versa.
diff --git a/node_modules/d3-scale/dist/d3-scale.js b/node_modules/d3-scale/dist/d3-scale.js
new file mode 100644
index 0000000000000000000000000000000000000000..408d9271cd0b4f197b6e17fc5decb9ccb0f658bb
--- /dev/null
+++ b/node_modules/d3-scale/dist/d3-scale.js
@@ -0,0 +1,1196 @@
+// https://d3js.org/d3-scale/ v4.0.2 Copyright 2010-2021 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-array'), require('d3-interpolate'), require('d3-format'), require('d3-time'), require('d3-time-format')) :
+typeof define === 'function' && define.amd ? define(['exports', 'd3-array', 'd3-interpolate', 'd3-format', 'd3-time', 'd3-time-format'], factory) :
+(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.d3 = global.d3 || {}, global.d3, global.d3, global.d3, global.d3, global.d3));
+})(this, (function (exports, d3Array, d3Interpolate, d3Format, d3Time, d3TimeFormat) { 'use strict';
+
+function initRange(domain, range) {
+ switch (arguments.length) {
+ case 0: break;
+ case 1: this.range(domain); break;
+ default: this.range(range).domain(domain); break;
+ }
+ return this;
+}
+
+function initInterpolator(domain, interpolator) {
+ switch (arguments.length) {
+ case 0: break;
+ case 1: {
+ if (typeof domain === "function") this.interpolator(domain);
+ else this.range(domain);
+ break;
+ }
+ default: {
+ this.domain(domain);
+ if (typeof interpolator === "function") this.interpolator(interpolator);
+ else this.range(interpolator);
+ break;
+ }
+ }
+ return this;
+}
+
+const implicit = Symbol("implicit");
+
+function ordinal() {
+ var index = new d3Array.InternMap(),
+ domain = [],
+ range = [],
+ unknown = implicit;
+
+ function scale(d) {
+ let i = index.get(d);
+ if (i === undefined) {
+ if (unknown !== implicit) return unknown;
+ index.set(d, i = domain.push(d) - 1);
+ }
+ return range[i % range.length];
+ }
+
+ scale.domain = function(_) {
+ if (!arguments.length) return domain.slice();
+ domain = [], index = new d3Array.InternMap();
+ for (const value of _) {
+ if (index.has(value)) continue;
+ index.set(value, domain.push(value) - 1);
+ }
+ return scale;
+ };
+
+ scale.range = function(_) {
+ return arguments.length ? (range = Array.from(_), scale) : range.slice();
+ };
+
+ scale.unknown = function(_) {
+ return arguments.length ? (unknown = _, scale) : unknown;
+ };
+
+ scale.copy = function() {
+ return ordinal(domain, range).unknown(unknown);
+ };
+
+ initRange.apply(scale, arguments);
+
+ return scale;
+}
+
+function band() {
+ var scale = ordinal().unknown(undefined),
+ domain = scale.domain,
+ ordinalRange = scale.range,
+ r0 = 0,
+ r1 = 1,
+ step,
+ bandwidth,
+ round = false,
+ paddingInner = 0,
+ paddingOuter = 0,
+ align = 0.5;
+
+ delete scale.unknown;
+
+ function rescale() {
+ var n = domain().length,
+ reverse = r1 < r0,
+ start = reverse ? r1 : r0,
+ stop = reverse ? r0 : r1;
+ step = (stop - start) / Math.max(1, n - paddingInner + paddingOuter * 2);
+ if (round) step = Math.floor(step);
+ start += (stop - start - step * (n - paddingInner)) * align;
+ bandwidth = step * (1 - paddingInner);
+ if (round) start = Math.round(start), bandwidth = Math.round(bandwidth);
+ var values = d3Array.range(n).map(function(i) { return start + step * i; });
+ return ordinalRange(reverse ? values.reverse() : values);
+ }
+
+ scale.domain = function(_) {
+ return arguments.length ? (domain(_), rescale()) : domain();
+ };
+
+ scale.range = function(_) {
+ return arguments.length ? ([r0, r1] = _, r0 = +r0, r1 = +r1, rescale()) : [r0, r1];
+ };
+
+ scale.rangeRound = function(_) {
+ return [r0, r1] = _, r0 = +r0, r1 = +r1, round = true, rescale();
+ };
+
+ scale.bandwidth = function() {
+ return bandwidth;
+ };
+
+ scale.step = function() {
+ return step;
+ };
+
+ scale.round = function(_) {
+ return arguments.length ? (round = !!_, rescale()) : round;
+ };
+
+ scale.padding = function(_) {
+ return arguments.length ? (paddingInner = Math.min(1, paddingOuter = +_), rescale()) : paddingInner;
+ };
+
+ scale.paddingInner = function(_) {
+ return arguments.length ? (paddingInner = Math.min(1, _), rescale()) : paddingInner;
+ };
+
+ scale.paddingOuter = function(_) {
+ return arguments.length ? (paddingOuter = +_, rescale()) : paddingOuter;
+ };
+
+ scale.align = function(_) {
+ return arguments.length ? (align = Math.max(0, Math.min(1, _)), rescale()) : align;
+ };
+
+ scale.copy = function() {
+ return band(domain(), [r0, r1])
+ .round(round)
+ .paddingInner(paddingInner)
+ .paddingOuter(paddingOuter)
+ .align(align);
+ };
+
+ return initRange.apply(rescale(), arguments);
+}
+
+function pointish(scale) {
+ var copy = scale.copy;
+
+ scale.padding = scale.paddingOuter;
+ delete scale.paddingInner;
+ delete scale.paddingOuter;
+
+ scale.copy = function() {
+ return pointish(copy());
+ };
+
+ return scale;
+}
+
+function point() {
+ return pointish(band.apply(null, arguments).paddingInner(1));
+}
+
+function constants(x) {
+ return function() {
+ return x;
+ };
+}
+
+function number$1(x) {
+ return +x;
+}
+
+var unit = [0, 1];
+
+function identity$1(x) {
+ return x;
+}
+
+function normalize(a, b) {
+ return (b -= (a = +a))
+ ? function(x) { return (x - a) / b; }
+ : constants(isNaN(b) ? NaN : 0.5);
+}
+
+function clamper(a, b) {
+ var t;
+ if (a > b) t = a, a = b, b = t;
+ return function(x) { return Math.max(a, Math.min(b, x)); };
+}
+
+// normalize(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
+// interpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding range value x in [a,b].
+function bimap(domain, range, interpolate) {
+ var d0 = domain[0], d1 = domain[1], r0 = range[0], r1 = range[1];
+ if (d1 < d0) d0 = normalize(d1, d0), r0 = interpolate(r1, r0);
+ else d0 = normalize(d0, d1), r0 = interpolate(r0, r1);
+ return function(x) { return r0(d0(x)); };
+}
+
+function polymap(domain, range, interpolate) {
+ var j = Math.min(domain.length, range.length) - 1,
+ d = new Array(j),
+ r = new Array(j),
+ i = -1;
+
+ // Reverse descending domains.
+ if (domain[j] < domain[0]) {
+ domain = domain.slice().reverse();
+ range = range.slice().reverse();
+ }
+
+ while (++i < j) {
+ d[i] = normalize(domain[i], domain[i + 1]);
+ r[i] = interpolate(range[i], range[i + 1]);
+ }
+
+ return function(x) {
+ var i = d3Array.bisect(domain, x, 1, j) - 1;
+ return r[i](d[i](x));
+ };
+}
+
+function copy$1(source, target) {
+ return target
+ .domain(source.domain())
+ .range(source.range())
+ .interpolate(source.interpolate())
+ .clamp(source.clamp())
+ .unknown(source.unknown());
+}
+
+function transformer$2() {
+ var domain = unit,
+ range = unit,
+ interpolate = d3Interpolate.interpolate,
+ transform,
+ untransform,
+ unknown,
+ clamp = identity$1,
+ piecewise,
+ output,
+ input;
+
+ function rescale() {
+ var n = Math.min(domain.length, range.length);
+ if (clamp !== identity$1) clamp = clamper(domain[0], domain[n - 1]);
+ piecewise = n > 2 ? polymap : bimap;
+ output = input = null;
+ return scale;
+ }
+
+ function scale(x) {
+ return x == null || isNaN(x = +x) ? unknown : (output || (output = piecewise(domain.map(transform), range, interpolate)))(transform(clamp(x)));
+ }
+
+ scale.invert = function(y) {
+ return clamp(untransform((input || (input = piecewise(range, domain.map(transform), d3Interpolate.interpolateNumber)))(y)));
+ };
+
+ scale.domain = function(_) {
+ return arguments.length ? (domain = Array.from(_, number$1), rescale()) : domain.slice();
+ };
+
+ scale.range = function(_) {
+ return arguments.length ? (range = Array.from(_), rescale()) : range.slice();
+ };
+
+ scale.rangeRound = function(_) {
+ return range = Array.from(_), interpolate = d3Interpolate.interpolateRound, rescale();
+ };
+
+ scale.clamp = function(_) {
+ return arguments.length ? (clamp = _ ? true : identity$1, rescale()) : clamp !== identity$1;
+ };
+
+ scale.interpolate = function(_) {
+ return arguments.length ? (interpolate = _, rescale()) : interpolate;
+ };
+
+ scale.unknown = function(_) {
+ return arguments.length ? (unknown = _, scale) : unknown;
+ };
+
+ return function(t, u) {
+ transform = t, untransform = u;
+ return rescale();
+ };
+}
+
+function continuous() {
+ return transformer$2()(identity$1, identity$1);
+}
+
+function tickFormat(start, stop, count, specifier) {
+ var step = d3Array.tickStep(start, stop, count),
+ precision;
+ specifier = d3Format.formatSpecifier(specifier == null ? ",f" : specifier);
+ switch (specifier.type) {
+ case "s": {
+ var value = Math.max(Math.abs(start), Math.abs(stop));
+ if (specifier.precision == null && !isNaN(precision = d3Format.precisionPrefix(step, value))) specifier.precision = precision;
+ return d3Format.formatPrefix(specifier, value);
+ }
+ case "":
+ case "e":
+ case "g":
+ case "p":
+ case "r": {
+ if (specifier.precision == null && !isNaN(precision = d3Format.precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
+ break;
+ }
+ case "f":
+ case "%": {
+ if (specifier.precision == null && !isNaN(precision = d3Format.precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
+ break;
+ }
+ }
+ return d3Format.format(specifier);
+}
+
+function linearish(scale) {
+ var domain = scale.domain;
+
+ scale.ticks = function(count) {
+ var d = domain();
+ return d3Array.ticks(d[0], d[d.length - 1], count == null ? 10 : count);
+ };
+
+ scale.tickFormat = function(count, specifier) {
+ var d = domain();
+ return tickFormat(d[0], d[d.length - 1], count == null ? 10 : count, specifier);
+ };
+
+ scale.nice = function(count) {
+ if (count == null) count = 10;
+
+ var d = domain();
+ var i0 = 0;
+ var i1 = d.length - 1;
+ var start = d[i0];
+ var stop = d[i1];
+ var prestep;
+ var step;
+ var maxIter = 10;
+
+ if (stop < start) {
+ step = start, start = stop, stop = step;
+ step = i0, i0 = i1, i1 = step;
+ }
+
+ while (maxIter-- > 0) {
+ step = d3Array.tickIncrement(start, stop, count);
+ if (step === prestep) {
+ d[i0] = start;
+ d[i1] = stop;
+ return domain(d);
+ } else if (step > 0) {
+ start = Math.floor(start / step) * step;
+ stop = Math.ceil(stop / step) * step;
+ } else if (step < 0) {
+ start = Math.ceil(start * step) / step;
+ stop = Math.floor(stop * step) / step;
+ } else {
+ break;
+ }
+ prestep = step;
+ }
+
+ return scale;
+ };
+
+ return scale;
+}
+
+function linear() {
+ var scale = continuous();
+
+ scale.copy = function() {
+ return copy$1(scale, linear());
+ };
+
+ initRange.apply(scale, arguments);
+
+ return linearish(scale);
+}
+
+function identity(domain) {
+ var unknown;
+
+ function scale(x) {
+ return x == null || isNaN(x = +x) ? unknown : x;
+ }
+
+ scale.invert = scale;
+
+ scale.domain = scale.range = function(_) {
+ return arguments.length ? (domain = Array.from(_, number$1), scale) : domain.slice();
+ };
+
+ scale.unknown = function(_) {
+ return arguments.length ? (unknown = _, scale) : unknown;
+ };
+
+ scale.copy = function() {
+ return identity(domain).unknown(unknown);
+ };
+
+ domain = arguments.length ? Array.from(domain, number$1) : [0, 1];
+
+ return linearish(scale);
+}
+
+function nice(domain, interval) {
+ domain = domain.slice();
+
+ var i0 = 0,
+ i1 = domain.length - 1,
+ x0 = domain[i0],
+ x1 = domain[i1],
+ t;
+
+ if (x1 < x0) {
+ t = i0, i0 = i1, i1 = t;
+ t = x0, x0 = x1, x1 = t;
+ }
+
+ domain[i0] = interval.floor(x0);
+ domain[i1] = interval.ceil(x1);
+ return domain;
+}
+
+function transformLog(x) {
+ return Math.log(x);
+}
+
+function transformExp(x) {
+ return Math.exp(x);
+}
+
+function transformLogn(x) {
+ return -Math.log(-x);
+}
+
+function transformExpn(x) {
+ return -Math.exp(-x);
+}
+
+function pow10(x) {
+ return isFinite(x) ? +("1e" + x) : x < 0 ? 0 : x;
+}
+
+function powp(base) {
+ return base === 10 ? pow10
+ : base === Math.E ? Math.exp
+ : x => Math.pow(base, x);
+}
+
+function logp(base) {
+ return base === Math.E ? Math.log
+ : base === 10 && Math.log10
+ || base === 2 && Math.log2
+ || (base = Math.log(base), x => Math.log(x) / base);
+}
+
+function reflect(f) {
+ return (x, k) => -f(-x, k);
+}
+
+function loggish(transform) {
+ const scale = transform(transformLog, transformExp);
+ const domain = scale.domain;
+ let base = 10;
+ let logs;
+ let pows;
+
+ function rescale() {
+ logs = logp(base), pows = powp(base);
+ if (domain()[0] < 0) {
+ logs = reflect(logs), pows = reflect(pows);
+ transform(transformLogn, transformExpn);
+ } else {
+ transform(transformLog, transformExp);
+ }
+ return scale;
+ }
+
+ scale.base = function(_) {
+ return arguments.length ? (base = +_, rescale()) : base;
+ };
+
+ scale.domain = function(_) {
+ return arguments.length ? (domain(_), rescale()) : domain();
+ };
+
+ scale.ticks = count => {
+ const d = domain();
+ let u = d[0];
+ let v = d[d.length - 1];
+ const r = v < u;
+
+ if (r) ([u, v] = [v, u]);
+
+ let i = logs(u);
+ let j = logs(v);
+ let k;
+ let t;
+ const n = count == null ? 10 : +count;
+ let z = [];
+
+ if (!(base % 1) && j - i < n) {
+ i = Math.floor(i), j = Math.ceil(j);
+ if (u > 0) for (; i <= j; ++i) {
+ for (k = 1; k < base; ++k) {
+ t = i < 0 ? k / pows(-i) : k * pows(i);
+ if (t < u) continue;
+ if (t > v) break;
+ z.push(t);
+ }
+ } else for (; i <= j; ++i) {
+ for (k = base - 1; k >= 1; --k) {
+ t = i > 0 ? k / pows(-i) : k * pows(i);
+ if (t < u) continue;
+ if (t > v) break;
+ z.push(t);
+ }
+ }
+ if (z.length * 2 < n) z = d3Array.ticks(u, v, n);
+ } else {
+ z = d3Array.ticks(i, j, Math.min(j - i, n)).map(pows);
+ }
+ return r ? z.reverse() : z;
+ };
+
+ scale.tickFormat = (count, specifier) => {
+ if (count == null) count = 10;
+ if (specifier == null) specifier = base === 10 ? "s" : ",";
+ if (typeof specifier !== "function") {
+ if (!(base % 1) && (specifier = d3Format.formatSpecifier(specifier)).precision == null) specifier.trim = true;
+ specifier = d3Format.format(specifier);
+ }
+ if (count === Infinity) return specifier;
+ const k = Math.max(1, base * count / scale.ticks().length); // TODO fast estimate?
+ return d => {
+ let i = d / pows(Math.round(logs(d)));
+ if (i * base < base - 0.5) i *= base;
+ return i <= k ? specifier(d) : "";
+ };
+ };
+
+ scale.nice = () => {
+ return domain(nice(domain(), {
+ floor: x => pows(Math.floor(logs(x))),
+ ceil: x => pows(Math.ceil(logs(x)))
+ }));
+ };
+
+ return scale;
+}
+
+function log() {
+ const scale = loggish(transformer$2()).domain([1, 10]);
+ scale.copy = () => copy$1(scale, log()).base(scale.base());
+ initRange.apply(scale, arguments);
+ return scale;
+}
+
+function transformSymlog(c) {
+ return function(x) {
+ return Math.sign(x) * Math.log1p(Math.abs(x / c));
+ };
+}
+
+function transformSymexp(c) {
+ return function(x) {
+ return Math.sign(x) * Math.expm1(Math.abs(x)) * c;
+ };
+}
+
+function symlogish(transform) {
+ var c = 1, scale = transform(transformSymlog(c), transformSymexp(c));
+
+ scale.constant = function(_) {
+ return arguments.length ? transform(transformSymlog(c = +_), transformSymexp(c)) : c;
+ };
+
+ return linearish(scale);
+}
+
+function symlog() {
+ var scale = symlogish(transformer$2());
+
+ scale.copy = function() {
+ return copy$1(scale, symlog()).constant(scale.constant());
+ };
+
+ return initRange.apply(scale, arguments);
+}
+
+function transformPow(exponent) {
+ return function(x) {
+ return x < 0 ? -Math.pow(-x, exponent) : Math.pow(x, exponent);
+ };
+}
+
+function transformSqrt(x) {
+ return x < 0 ? -Math.sqrt(-x) : Math.sqrt(x);
+}
+
+function transformSquare(x) {
+ return x < 0 ? -x * x : x * x;
+}
+
+function powish(transform) {
+ var scale = transform(identity$1, identity$1),
+ exponent = 1;
+
+ function rescale() {
+ return exponent === 1 ? transform(identity$1, identity$1)
+ : exponent === 0.5 ? transform(transformSqrt, transformSquare)
+ : transform(transformPow(exponent), transformPow(1 / exponent));
+ }
+
+ scale.exponent = function(_) {
+ return arguments.length ? (exponent = +_, rescale()) : exponent;
+ };
+
+ return linearish(scale);
+}
+
+function pow() {
+ var scale = powish(transformer$2());
+
+ scale.copy = function() {
+ return copy$1(scale, pow()).exponent(scale.exponent());
+ };
+
+ initRange.apply(scale, arguments);
+
+ return scale;
+}
+
+function sqrt() {
+ return pow.apply(null, arguments).exponent(0.5);
+}
+
+function square(x) {
+ return Math.sign(x) * x * x;
+}
+
+function unsquare(x) {
+ return Math.sign(x) * Math.sqrt(Math.abs(x));
+}
+
+function radial() {
+ var squared = continuous(),
+ range = [0, 1],
+ round = false,
+ unknown;
+
+ function scale(x) {
+ var y = unsquare(squared(x));
+ return isNaN(y) ? unknown : round ? Math.round(y) : y;
+ }
+
+ scale.invert = function(y) {
+ return squared.invert(square(y));
+ };
+
+ scale.domain = function(_) {
+ return arguments.length ? (squared.domain(_), scale) : squared.domain();
+ };
+
+ scale.range = function(_) {
+ return arguments.length ? (squared.range((range = Array.from(_, number$1)).map(square)), scale) : range.slice();
+ };
+
+ scale.rangeRound = function(_) {
+ return scale.range(_).round(true);
+ };
+
+ scale.round = function(_) {
+ return arguments.length ? (round = !!_, scale) : round;
+ };
+
+ scale.clamp = function(_) {
+ return arguments.length ? (squared.clamp(_), scale) : squared.clamp();
+ };
+
+ scale.unknown = function(_) {
+ return arguments.length ? (unknown = _, scale) : unknown;
+ };
+
+ scale.copy = function() {
+ return radial(squared.domain(), range)
+ .round(round)
+ .clamp(squared.clamp())
+ .unknown(unknown);
+ };
+
+ initRange.apply(scale, arguments);
+
+ return linearish(scale);
+}
+
+function quantile() {
+ var domain = [],
+ range = [],
+ thresholds = [],
+ unknown;
+
+ function rescale() {
+ var i = 0, n = Math.max(1, range.length);
+ thresholds = new Array(n - 1);
+ while (++i < n) thresholds[i - 1] = d3Array.quantileSorted(domain, i / n);
+ return scale;
+ }
+
+ function scale(x) {
+ return x == null || isNaN(x = +x) ? unknown : range[d3Array.bisect(thresholds, x)];
+ }
+
+ scale.invertExtent = function(y) {
+ var i = range.indexOf(y);
+ return i < 0 ? [NaN, NaN] : [
+ i > 0 ? thresholds[i - 1] : domain[0],
+ i < thresholds.length ? thresholds[i] : domain[domain.length - 1]
+ ];
+ };
+
+ scale.domain = function(_) {
+ if (!arguments.length) return domain.slice();
+ domain = [];
+ for (let d of _) if (d != null && !isNaN(d = +d)) domain.push(d);
+ domain.sort(d3Array.ascending);
+ return rescale();
+ };
+
+ scale.range = function(_) {
+ return arguments.length ? (range = Array.from(_), rescale()) : range.slice();
+ };
+
+ scale.unknown = function(_) {
+ return arguments.length ? (unknown = _, scale) : unknown;
+ };
+
+ scale.quantiles = function() {
+ return thresholds.slice();
+ };
+
+ scale.copy = function() {
+ return quantile()
+ .domain(domain)
+ .range(range)
+ .unknown(unknown);
+ };
+
+ return initRange.apply(scale, arguments);
+}
+
+function quantize() {
+ var x0 = 0,
+ x1 = 1,
+ n = 1,
+ domain = [0.5],
+ range = [0, 1],
+ unknown;
+
+ function scale(x) {
+ return x != null && x <= x ? range[d3Array.bisect(domain, x, 0, n)] : unknown;
+ }
+
+ function rescale() {
+ var i = -1;
+ domain = new Array(n);
+ while (++i < n) domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);
+ return scale;
+ }
+
+ scale.domain = function(_) {
+ return arguments.length ? ([x0, x1] = _, x0 = +x0, x1 = +x1, rescale()) : [x0, x1];
+ };
+
+ scale.range = function(_) {
+ return arguments.length ? (n = (range = Array.from(_)).length - 1, rescale()) : range.slice();
+ };
+
+ scale.invertExtent = function(y) {
+ var i = range.indexOf(y);
+ return i < 0 ? [NaN, NaN]
+ : i < 1 ? [x0, domain[0]]
+ : i >= n ? [domain[n - 1], x1]
+ : [domain[i - 1], domain[i]];
+ };
+
+ scale.unknown = function(_) {
+ return arguments.length ? (unknown = _, scale) : scale;
+ };
+
+ scale.thresholds = function() {
+ return domain.slice();
+ };
+
+ scale.copy = function() {
+ return quantize()
+ .domain([x0, x1])
+ .range(range)
+ .unknown(unknown);
+ };
+
+ return initRange.apply(linearish(scale), arguments);
+}
+
+function threshold() {
+ var domain = [0.5],
+ range = [0, 1],
+ unknown,
+ n = 1;
+
+ function scale(x) {
+ return x != null && x <= x ? range[d3Array.bisect(domain, x, 0, n)] : unknown;
+ }
+
+ scale.domain = function(_) {
+ return arguments.length ? (domain = Array.from(_), n = Math.min(domain.length, range.length - 1), scale) : domain.slice();
+ };
+
+ scale.range = function(_) {
+ return arguments.length ? (range = Array.from(_), n = Math.min(domain.length, range.length - 1), scale) : range.slice();
+ };
+
+ scale.invertExtent = function(y) {
+ var i = range.indexOf(y);
+ return [domain[i - 1], domain[i]];
+ };
+
+ scale.unknown = function(_) {
+ return arguments.length ? (unknown = _, scale) : unknown;
+ };
+
+ scale.copy = function() {
+ return threshold()
+ .domain(domain)
+ .range(range)
+ .unknown(unknown);
+ };
+
+ return initRange.apply(scale, arguments);
+}
+
+function date(t) {
+ return new Date(t);
+}
+
+function number(t) {
+ return t instanceof Date ? +t : +new Date(+t);
+}
+
+function calendar(ticks, tickInterval, year, month, week, day, hour, minute, second, format) {
+ var scale = continuous(),
+ invert = scale.invert,
+ domain = scale.domain;
+
+ var formatMillisecond = format(".%L"),
+ formatSecond = format(":%S"),
+ formatMinute = format("%I:%M"),
+ formatHour = format("%I %p"),
+ formatDay = format("%a %d"),
+ formatWeek = format("%b %d"),
+ formatMonth = format("%B"),
+ formatYear = format("%Y");
+
+ function tickFormat(date) {
+ return (second(date) < date ? formatMillisecond
+ : minute(date) < date ? formatSecond
+ : hour(date) < date ? formatMinute
+ : day(date) < date ? formatHour
+ : month(date) < date ? (week(date) < date ? formatDay : formatWeek)
+ : year(date) < date ? formatMonth
+ : formatYear)(date);
+ }
+
+ scale.invert = function(y) {
+ return new Date(invert(y));
+ };
+
+ scale.domain = function(_) {
+ return arguments.length ? domain(Array.from(_, number)) : domain().map(date);
+ };
+
+ scale.ticks = function(interval) {
+ var d = domain();
+ return ticks(d[0], d[d.length - 1], interval == null ? 10 : interval);
+ };
+
+ scale.tickFormat = function(count, specifier) {
+ return specifier == null ? tickFormat : format(specifier);
+ };
+
+ scale.nice = function(interval) {
+ var d = domain();
+ if (!interval || typeof interval.range !== "function") interval = tickInterval(d[0], d[d.length - 1], interval == null ? 10 : interval);
+ return interval ? domain(nice(d, interval)) : scale;
+ };
+
+ scale.copy = function() {
+ return copy$1(scale, calendar(ticks, tickInterval, year, month, week, day, hour, minute, second, format));
+ };
+
+ return scale;
+}
+
+function time() {
+ return initRange.apply(calendar(d3Time.timeTicks, d3Time.timeTickInterval, d3Time.timeYear, d3Time.timeMonth, d3Time.timeWeek, d3Time.timeDay, d3Time.timeHour, d3Time.timeMinute, d3Time.timeSecond, d3TimeFormat.timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]), arguments);
+}
+
+function utcTime() {
+ return initRange.apply(calendar(d3Time.utcTicks, d3Time.utcTickInterval, d3Time.utcYear, d3Time.utcMonth, d3Time.utcWeek, d3Time.utcDay, d3Time.utcHour, d3Time.utcMinute, d3Time.utcSecond, d3TimeFormat.utcFormat).domain([Date.UTC(2000, 0, 1), Date.UTC(2000, 0, 2)]), arguments);
+}
+
+function transformer$1() {
+ var x0 = 0,
+ x1 = 1,
+ t0,
+ t1,
+ k10,
+ transform,
+ interpolator = identity$1,
+ clamp = false,
+ unknown;
+
+ function scale(x) {
+ return x == null || isNaN(x = +x) ? unknown : interpolator(k10 === 0 ? 0.5 : (x = (transform(x) - t0) * k10, clamp ? Math.max(0, Math.min(1, x)) : x));
+ }
+
+ scale.domain = function(_) {
+ return arguments.length ? ([x0, x1] = _, t0 = transform(x0 = +x0), t1 = transform(x1 = +x1), k10 = t0 === t1 ? 0 : 1 / (t1 - t0), scale) : [x0, x1];
+ };
+
+ scale.clamp = function(_) {
+ return arguments.length ? (clamp = !!_, scale) : clamp;
+ };
+
+ scale.interpolator = function(_) {
+ return arguments.length ? (interpolator = _, scale) : interpolator;
+ };
+
+ function range(interpolate) {
+ return function(_) {
+ var r0, r1;
+ return arguments.length ? ([r0, r1] = _, interpolator = interpolate(r0, r1), scale) : [interpolator(0), interpolator(1)];
+ };
+ }
+
+ scale.range = range(d3Interpolate.interpolate);
+
+ scale.rangeRound = range(d3Interpolate.interpolateRound);
+
+ scale.unknown = function(_) {
+ return arguments.length ? (unknown = _, scale) : unknown;
+ };
+
+ return function(t) {
+ transform = t, t0 = t(x0), t1 = t(x1), k10 = t0 === t1 ? 0 : 1 / (t1 - t0);
+ return scale;
+ };
+}
+
+function copy(source, target) {
+ return target
+ .domain(source.domain())
+ .interpolator(source.interpolator())
+ .clamp(source.clamp())
+ .unknown(source.unknown());
+}
+
+function sequential() {
+ var scale = linearish(transformer$1()(identity$1));
+
+ scale.copy = function() {
+ return copy(scale, sequential());
+ };
+
+ return initInterpolator.apply(scale, arguments);
+}
+
+function sequentialLog() {
+ var scale = loggish(transformer$1()).domain([1, 10]);
+
+ scale.copy = function() {
+ return copy(scale, sequentialLog()).base(scale.base());
+ };
+
+ return initInterpolator.apply(scale, arguments);
+}
+
+function sequentialSymlog() {
+ var scale = symlogish(transformer$1());
+
+ scale.copy = function() {
+ return copy(scale, sequentialSymlog()).constant(scale.constant());
+ };
+
+ return initInterpolator.apply(scale, arguments);
+}
+
+function sequentialPow() {
+ var scale = powish(transformer$1());
+
+ scale.copy = function() {
+ return copy(scale, sequentialPow()).exponent(scale.exponent());
+ };
+
+ return initInterpolator.apply(scale, arguments);
+}
+
+function sequentialSqrt() {
+ return sequentialPow.apply(null, arguments).exponent(0.5);
+}
+
+function sequentialQuantile() {
+ var domain = [],
+ interpolator = identity$1;
+
+ function scale(x) {
+ if (x != null && !isNaN(x = +x)) return interpolator((d3Array.bisect(domain, x, 1) - 1) / (domain.length - 1));
+ }
+
+ scale.domain = function(_) {
+ if (!arguments.length) return domain.slice();
+ domain = [];
+ for (let d of _) if (d != null && !isNaN(d = +d)) domain.push(d);
+ domain.sort(d3Array.ascending);
+ return scale;
+ };
+
+ scale.interpolator = function(_) {
+ return arguments.length ? (interpolator = _, scale) : interpolator;
+ };
+
+ scale.range = function() {
+ return domain.map((d, i) => interpolator(i / (domain.length - 1)));
+ };
+
+ scale.quantiles = function(n) {
+ return Array.from({length: n + 1}, (_, i) => d3Array.quantile(domain, i / n));
+ };
+
+ scale.copy = function() {
+ return sequentialQuantile(interpolator).domain(domain);
+ };
+
+ return initInterpolator.apply(scale, arguments);
+}
+
+function transformer() {
+ var x0 = 0,
+ x1 = 0.5,
+ x2 = 1,
+ s = 1,
+ t0,
+ t1,
+ t2,
+ k10,
+ k21,
+ interpolator = identity$1,
+ transform,
+ clamp = false,
+ unknown;
+
+ function scale(x) {
+ return isNaN(x = +x) ? unknown : (x = 0.5 + ((x = +transform(x)) - t1) * (s * x < s * t1 ? k10 : k21), interpolator(clamp ? Math.max(0, Math.min(1, x)) : x));
+ }
+
+ scale.domain = function(_) {
+ return arguments.length ? ([x0, x1, x2] = _, t0 = transform(x0 = +x0), t1 = transform(x1 = +x1), t2 = transform(x2 = +x2), k10 = t0 === t1 ? 0 : 0.5 / (t1 - t0), k21 = t1 === t2 ? 0 : 0.5 / (t2 - t1), s = t1 < t0 ? -1 : 1, scale) : [x0, x1, x2];
+ };
+
+ scale.clamp = function(_) {
+ return arguments.length ? (clamp = !!_, scale) : clamp;
+ };
+
+ scale.interpolator = function(_) {
+ return arguments.length ? (interpolator = _, scale) : interpolator;
+ };
+
+ function range(interpolate) {
+ return function(_) {
+ var r0, r1, r2;
+ return arguments.length ? ([r0, r1, r2] = _, interpolator = d3Interpolate.piecewise(interpolate, [r0, r1, r2]), scale) : [interpolator(0), interpolator(0.5), interpolator(1)];
+ };
+ }
+
+ scale.range = range(d3Interpolate.interpolate);
+
+ scale.rangeRound = range(d3Interpolate.interpolateRound);
+
+ scale.unknown = function(_) {
+ return arguments.length ? (unknown = _, scale) : unknown;
+ };
+
+ return function(t) {
+ transform = t, t0 = t(x0), t1 = t(x1), t2 = t(x2), k10 = t0 === t1 ? 0 : 0.5 / (t1 - t0), k21 = t1 === t2 ? 0 : 0.5 / (t2 - t1), s = t1 < t0 ? -1 : 1;
+ return scale;
+ };
+}
+
+function diverging() {
+ var scale = linearish(transformer()(identity$1));
+
+ scale.copy = function() {
+ return copy(scale, diverging());
+ };
+
+ return initInterpolator.apply(scale, arguments);
+}
+
+function divergingLog() {
+ var scale = loggish(transformer()).domain([0.1, 1, 10]);
+
+ scale.copy = function() {
+ return copy(scale, divergingLog()).base(scale.base());
+ };
+
+ return initInterpolator.apply(scale, arguments);
+}
+
+function divergingSymlog() {
+ var scale = symlogish(transformer());
+
+ scale.copy = function() {
+ return copy(scale, divergingSymlog()).constant(scale.constant());
+ };
+
+ return initInterpolator.apply(scale, arguments);
+}
+
+function divergingPow() {
+ var scale = powish(transformer());
+
+ scale.copy = function() {
+ return copy(scale, divergingPow()).exponent(scale.exponent());
+ };
+
+ return initInterpolator.apply(scale, arguments);
+}
+
+function divergingSqrt() {
+ return divergingPow.apply(null, arguments).exponent(0.5);
+}
+
+exports.scaleBand = band;
+exports.scaleDiverging = diverging;
+exports.scaleDivergingLog = divergingLog;
+exports.scaleDivergingPow = divergingPow;
+exports.scaleDivergingSqrt = divergingSqrt;
+exports.scaleDivergingSymlog = divergingSymlog;
+exports.scaleIdentity = identity;
+exports.scaleImplicit = implicit;
+exports.scaleLinear = linear;
+exports.scaleLog = log;
+exports.scaleOrdinal = ordinal;
+exports.scalePoint = point;
+exports.scalePow = pow;
+exports.scaleQuantile = quantile;
+exports.scaleQuantize = quantize;
+exports.scaleRadial = radial;
+exports.scaleSequential = sequential;
+exports.scaleSequentialLog = sequentialLog;
+exports.scaleSequentialPow = sequentialPow;
+exports.scaleSequentialQuantile = sequentialQuantile;
+exports.scaleSequentialSqrt = sequentialSqrt;
+exports.scaleSequentialSymlog = sequentialSymlog;
+exports.scaleSqrt = sqrt;
+exports.scaleSymlog = symlog;
+exports.scaleThreshold = threshold;
+exports.scaleTime = time;
+exports.scaleUtc = utcTime;
+exports.tickFormat = tickFormat;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git a/node_modules/d3-scale/dist/d3-scale.min.js b/node_modules/d3-scale/dist/d3-scale.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..1612ea9f7e4e5b96b134093520cb7903073c71f1
--- /dev/null
+++ b/node_modules/d3-scale/dist/d3-scale.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-scale/ v4.0.2 Copyright 2010-2021 Mike Bostock
+!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("d3-array"),require("d3-interpolate"),require("d3-format"),require("d3-time"),require("d3-time-format")):"function"==typeof define&&define.amd?define(["exports","d3-array","d3-interpolate","d3-format","d3-time","d3-time-format"],t):t((n="undefined"!=typeof globalThis?globalThis:n||self).d3=n.d3||{},n.d3,n.d3,n.d3,n.d3,n.d3)}(this,(function(n,t,r,e,u,i){"use strict";function o(n,t){switch(arguments.length){case 0:break;case 1:this.range(n);break;default:this.range(t).domain(n)}return this}function a(n,t){switch(arguments.length){case 0:break;case 1:"function"==typeof n?this.interpolator(n):this.range(n);break;default:this.domain(n),"function"==typeof t?this.interpolator(t):this.range(t)}return this}const c=Symbol("implicit");function l(){var n=new t.InternMap,r=[],e=[],u=c;function i(t){let i=n.get(t);if(void 0===i){if(u!==c)return u;n.set(t,i=r.push(t)-1)}return e[i%e.length]}return i.domain=function(e){if(!arguments.length)return r.slice();r=[],n=new t.InternMap;for(const t of e)n.has(t)||n.set(t,r.push(t)-1);return i},i.range=function(n){return arguments.length?(e=Array.from(n),i):e.slice()},i.unknown=function(n){return arguments.length?(u=n,i):u},i.copy=function(){return l(r,e).unknown(u)},o.apply(i,arguments),i}function f(){var n,r,e=l().unknown(void 0),u=e.domain,i=e.range,a=0,c=1,s=!1,p=0,h=0,g=.5;function m(){var e=u().length,o=ct&&(r=n,n=t,t=r),f=function(r){return Math.max(n,Math.min(t,r))}),u=e>2?y:d,i=o=null,m}function m(t){return null==t||isNaN(t=+t)?e:(i||(i=u(a.map(n),c,l)))(n(f(t)))}return m.invert=function(e){return f(t((o||(o=u(c,a.map(n),r.interpolateNumber)))(e)))},m.domain=function(n){return arguments.length?(a=Array.from(n,p),s()):a.slice()},m.range=function(n){return arguments.length?(c=Array.from(n),s()):c.slice()},m.rangeRound=function(n){return c=Array.from(n),l=r.interpolateRound,s()},m.clamp=function(n){return arguments.length?(f=!!n||g,s()):f!==g},m.interpolate=function(n){return arguments.length?(l=n,s()):l},m.unknown=function(n){return arguments.length?(e=n,m):e},function(r,e){return n=r,t=e,s()}}function k(){return M()(g,g)}function w(n,r,u,i){var o,a=t.tickStep(n,r,u);switch((i=e.formatSpecifier(null==i?",f":i)).type){case"s":var c=Math.max(Math.abs(n),Math.abs(r));return null!=i.precision||isNaN(o=e.precisionPrefix(a,c))||(i.precision=o),e.formatPrefix(i,c);case"":case"e":case"g":case"p":case"r":null!=i.precision||isNaN(o=e.precisionRound(a,Math.max(Math.abs(n),Math.abs(r))))||(i.precision=o-("e"===i.type));break;case"f":case"%":null!=i.precision||isNaN(o=e.precisionFixed(a))||(i.precision=o-2*("%"===i.type))}return e.format(i)}function N(n){var r=n.domain;return n.ticks=function(n){var e=r();return t.ticks(e[0],e[e.length-1],null==n?10:n)},n.tickFormat=function(n,t){var e=r();return w(e[0],e[e.length-1],null==n?10:n,t)},n.nice=function(e){null==e&&(e=10);var u,i,o=r(),a=0,c=o.length-1,l=o[a],f=o[c],s=10;for(f
](https://observablehq.com/@d3/pie-chart)[
](https://observablehq.com/@d3/donut-chart)
+
+The arc generator produces a [circular](https://en.wikipedia.org/wiki/Circular_sector) or [annular](https://en.wikipedia.org/wiki/Annulus_\(mathematics\)) sector, as in a pie or donut chart. If the absolute difference between the [start](#arc_startAngle) and [end](#arc_endAngle) angles (the *angular span*) is greater than [τ](https://en.wikipedia.org/wiki/Turn_\(geometry\)#Tau_proposal), the arc generator will produce a complete circle or annulus. If it is less than τ, the arc’s angular length will be equal to the absolute difference between the two angles (going clockwise if the signed difference is positive and anticlockwise if it is negative). If the absolute difference is less than τ, the arc may have [rounded corners](#arc_cornerRadius) and [angular padding](#arc_padAngle). Arcs are always centered at ⟨0,0⟩; use a transform (see: [SVG](http://www.w3.org/TR/SVG/coords.html#TransformAttribute), [Canvas](http://www.w3.org/TR/2dcontext/#transformations)) to move the arc to a different position.
+
+See also the [pie generator](#pies), which computes the necessary angles to represent an array of data as a pie or donut chart; these angles can then be passed to an arc generator.
+
+# d3.arc() · [Source](https://github.com/d3/d3-shape/blob/main/src/arc.js)
+
+Constructs a new arc generator with the default settings.
+
+# arc(arguments…) · [Source](https://github.com/d3/d3-shape/blob/main/src/arc.js)
+
+Generates an arc for the given *arguments*. The *arguments* are arbitrary; they are simply propagated to the arc generator’s accessor functions along with the `this` object. For example, with the default settings, an object with radii and angles is expected:
+
+```js
+const arc = d3.arc();
+
+arc({
+ innerRadius: 0,
+ outerRadius: 100,
+ startAngle: 0,
+ endAngle: Math.PI / 2
+}); // "M0,-100A100,100,0,0,1,100,0L0,0Z"
+```
+
+If the radii and angles are instead defined as constants, you can generate an arc without any arguments:
+
+```js
+const arc = d3.arc()
+ .innerRadius(0)
+ .outerRadius(100)
+ .startAngle(0)
+ .endAngle(Math.PI / 2);
+
+arc(); // "M0,-100A100,100,0,0,1,100,0L0,0Z"
+```
+
+If the arc generator has a [context](#arc_context), then the arc is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls and this function returns void. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string is returned.
+
+# arc.centroid(arguments…) · [Source](https://github.com/d3/d3-shape/blob/main/src/arc.js)
+
+Computes the midpoint [*x*, *y*] of the center line of the arc that would be [generated](#_arc) by the given *arguments*. The *arguments* are arbitrary; they are simply propagated to the arc generator’s accessor functions along with the `this` object. To be consistent with the generated arc, the accessors must be deterministic, *i.e.*, return the same value given the same arguments. The midpoint is defined as ([startAngle](#arc_startAngle) + [endAngle](#arc_endAngle)) / 2 and ([innerRadius](#arc_innerRadius) + [outerRadius](#arc_outerRadius)) / 2. For example:
+
+[
](https://observablehq.com/@d3/pie-settings)[
](https://observablehq.com/@d3/pie-settings)
+
+Note that this is **not the geometric center** of the arc, which may be outside the arc; this method is merely a convenience for positioning labels.
+
+# arc.innerRadius([radius]) · [Source](https://github.com/d3/d3-shape/blob/main/src/arc.js)
+
+If *radius* is specified, sets the inner radius to the specified function or number and returns this arc generator. If *radius* is not specified, returns the current inner radius accessor, which defaults to:
+
+```js
+function innerRadius(d) {
+ return d.innerRadius;
+}
+```
+
+Specifying the inner radius as a function is useful for constructing a stacked polar bar chart, often in conjunction with a [sqrt scale](https://github.com/d3/d3-scale#sqrt). More commonly, a constant inner radius is used for a donut or pie chart. If the outer radius is smaller than the inner radius, the inner and outer radii are swapped. A negative value is treated as zero.
+
+# arc.outerRadius([radius]) · [Source](https://github.com/d3/d3-shape/blob/main/src/arc.js)
+
+If *radius* is specified, sets the outer radius to the specified function or number and returns this arc generator. If *radius* is not specified, returns the current outer radius accessor, which defaults to:
+
+```js
+function outerRadius(d) {
+ return d.outerRadius;
+}
+```
+
+Specifying the outer radius as a function is useful for constructing a coxcomb or polar bar chart, often in conjunction with a [sqrt scale](https://github.com/d3/d3-scale#sqrt). More commonly, a constant outer radius is used for a pie or donut chart. If the outer radius is smaller than the inner radius, the inner and outer radii are swapped. A negative value is treated as zero.
+
+# arc.cornerRadius([radius]) · [Source](https://github.com/d3/d3-shape/blob/main/src/arc.js)
+
+If *radius* is specified, sets the corner radius to the specified function or number and returns this arc generator. If *radius* is not specified, returns the current corner radius accessor, which defaults to:
+
+```js
+function cornerRadius() {
+ return 0;
+}
+```
+
+If the corner radius is greater than zero, the corners of the arc are rounded using circles of the given radius. For a circular sector, the two outer corners are rounded; for an annular sector, all four corners are rounded. The corner circles are shown in this diagram:
+
+[
](https://observablehq.com/@d3/pie-settings)[
](https://observablehq.com/@d3/pie-settings)
+
+The corner radius may not be larger than ([outerRadius](#arc_outerRadius) - [innerRadius](#arc_innerRadius)) / 2. In addition, for arcs whose angular span is less than π, the corner radius may be reduced as two adjacent rounded corners intersect. This is occurs more often with the inner corners. See the [arc corners animation](https://observablehq.com/@d3/arc-corners) for illustration.
+
+# arc.startAngle([angle]) · [Source](https://github.com/d3/d3-shape/blob/main/src/arc.js)
+
+If *angle* is specified, sets the start angle to the specified function or number and returns this arc generator. If *angle* is not specified, returns the current start angle accessor, which defaults to:
+
+```js
+function startAngle(d) {
+ return d.startAngle;
+}
+```
+
+The *angle* is specified in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise. If |endAngle - startAngle| ≥ τ, a complete circle or annulus is generated rather than a sector.
+
+# arc.endAngle([angle]) · [Source](https://github.com/d3/d3-shape/blob/main/src/arc.js)
+
+If *angle* is specified, sets the end angle to the specified function or number and returns this arc generator. If *angle* is not specified, returns the current end angle accessor, which defaults to:
+
+```js
+function endAngle(d) {
+ return d.endAngle;
+}
+```
+
+The *angle* is specified in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise. If |endAngle - startAngle| ≥ τ, a complete circle or annulus is generated rather than a sector.
+
+# arc.padAngle([angle]) · [Source](https://github.com/d3/d3-shape/blob/main/src/arc.js)
+
+If *angle* is specified, sets the pad angle to the specified function or number and returns this arc generator. If *angle* is not specified, returns the current pad angle accessor, which defaults to:
+
+```js
+function padAngle() {
+ return d && d.padAngle;
+}
+```
+
+The pad angle is converted to a fixed linear distance separating adjacent arcs, defined as [padRadius](#arc_padRadius) * padAngle. This distance is subtracted equally from the [start](#arc_startAngle) and [end](#arc_endAngle) of the arc. If the arc forms a complete circle or annulus, as when |endAngle - startAngle| ≥ τ, the pad angle is ignored.
+
+If the [inner radius](#arc_innerRadius) or angular span is small relative to the pad angle, it may not be possible to maintain parallel edges between adjacent arcs. In this case, the inner edge of the arc may collapse to a point, similar to a circular sector. For this reason, padding is typically only applied to annular sectors (*i.e.*, when innerRadius is positive), as shown in this diagram:
+
+[
](https://observablehq.com/@d3/pie-settings)[
](https://observablehq.com/@d3/pie-settings)
+
+The recommended minimum inner radius when using padding is outerRadius \* padAngle / sin(θ), where θ is the angular span of the smallest arc before padding. For example, if the outer radius is 200 pixels and the pad angle is 0.02 radians, a reasonable θ is 0.04 radians, and a reasonable inner radius is 100 pixels. See the [arc padding animation](https://observablehq.com/@d3/arc-pad-angle) for illustration.
+
+Often, the pad angle is not set directly on the arc generator, but is instead computed by the [pie generator](#pies) so as to ensure that the area of padded arcs is proportional to their value; see [*pie*.padAngle](#pie_padAngle). See the [pie padding animation](https://observablehq.com/@d3/arc-pad-angle) for illustration. If you apply a constant pad angle to the arc generator directly, it tends to subtract disproportionately from smaller arcs, introducing distortion.
+
+# arc.padRadius([radius]) · [Source](https://github.com/d3/d3-shape/blob/main/src/arc.js)
+
+If *radius* is specified, sets the pad radius to the specified function or number and returns this arc generator. If *radius* is not specified, returns the current pad radius accessor, which defaults to null, indicating that the pad radius should be automatically computed as sqrt([innerRadius](#arc_innerRadius) * innerRadius + [outerRadius](#arc_outerRadius) * outerRadius). The pad radius determines the fixed linear distance separating adjacent arcs, defined as padRadius * [padAngle](#arc_padAngle).
+
+# arc.context([context]) · [Source](https://github.com/d3/d3-shape/blob/main/src/arc.js)
+
+If *context* is specified, sets the context and returns this arc generator. If *context* is not specified, returns the current context, which defaults to null. If the context is not null, then the [generated arc](#_arc) is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string representing the generated arc is returned.
+
+# arc.digits([digits]) · [Source](https://github.com/d3/d3-shape/blob/main/src/arc.js)
+
+If *digits* is specified, sets the maximum number of digits after the decimal separator and returns this arc generator. If *digits* is not specified, returns the current maximum fraction digits, which defaults to 3. This option only applies when the associated [*context*](#arc_context) is null, as when this arc generator is used to produce [path data](http://www.w3.org/TR/SVG/paths.html#PathData).
+
+### Pies
+
+The pie generator does not produce a shape directly, but instead computes the necessary angles to represent a tabular dataset as a pie or donut chart; these angles can then be passed to an [arc generator](#arcs).
+
+# d3.pie() · [Source](https://github.com/d3/d3-shape/blob/main/src/pie.js)
+
+Constructs a new pie generator with the default settings.
+
+# pie(data[, arguments…]) · [Source](https://github.com/d3/d3-shape/blob/main/src/pie.js)
+
+Generates a pie for the given array of *data*, returning an array of objects representing each datum’s arc angles. Any additional *arguments* are arbitrary; they are simply propagated to the pie generator’s accessor functions along with the `this` object. The length of the returned array is the same as *data*, and each element *i* in the returned array corresponds to the element *i* in the input data. Each object in the returned array has the following properties:
+
+* `data` - the input datum; the corresponding element in the input data array.
+* `value` - the numeric [value](#pie_value) of the arc.
+* `index` - the zero-based [sorted index](#pie_sort) of the arc.
+* `startAngle` - the [start angle](#pie_startAngle) of the arc.
+* `endAngle` - the [end angle](#pie_endAngle) of the arc.
+* `padAngle` - the [pad angle](#pie_padAngle) of the arc.
+
+This representation is designed to work with the arc generator’s default [startAngle](#arc_startAngle), [endAngle](#arc_endAngle) and [padAngle](#arc_padAngle) accessors. The angular units are arbitrary, but if you plan to use the pie generator in conjunction with an [arc generator](#arcs), you should specify angles in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise.
+
+Given a small dataset of numbers, here is how to compute the arc angles to render this data as a pie chart:
+
+```js
+const data = [1, 1, 2, 3, 5, 8, 13, 21];
+const arcs = d3.pie()(data);
+```
+
+The first pair of parens, `pie()`, [constructs](#pie) a default pie generator. The second, `pie()(data)`, [invokes](#_pie) this generator on the dataset, returning an array of objects:
+
+```json
+[
+ {"data": 1, "value": 1, "index": 6, "startAngle": 6.050474740247008, "endAngle": 6.166830023713296, "padAngle": 0},
+ {"data": 1, "value": 1, "index": 7, "startAngle": 6.166830023713296, "endAngle": 6.283185307179584, "padAngle": 0},
+ {"data": 2, "value": 2, "index": 5, "startAngle": 5.817764173314431, "endAngle": 6.050474740247008, "padAngle": 0},
+ {"data": 3, "value": 3, "index": 4, "startAngle": 5.468698322915565, "endAngle": 5.817764173314431, "padAngle": 0},
+ {"data": 5, "value": 5, "index": 3, "startAngle": 4.886921905584122, "endAngle": 5.468698322915565, "padAngle": 0},
+ {"data": 8, "value": 8, "index": 2, "startAngle": 3.956079637853813, "endAngle": 4.886921905584122, "padAngle": 0},
+ {"data": 13, "value": 13, "index": 1, "startAngle": 2.443460952792061, "endAngle": 3.956079637853813, "padAngle": 0},
+ {"data": 21, "value": 21, "index": 0, "startAngle": 0.000000000000000, "endAngle": 2.443460952792061, "padAngle": 0}
+]
+```
+
+Note that the returned array is in the same order as the data, even though this pie chart is [sorted](#pie_sortValues) by descending value, starting with the arc for the last datum (value 21) at 12 o’clock.
+
+# pie.value([value]) · [Source](https://github.com/d3/d3-shape/blob/main/src/pie.js)
+
+If *value* is specified, sets the value accessor to the specified function or number and returns this pie generator. If *value* is not specified, returns the current value accessor, which defaults to:
+
+```js
+function value(d) {
+ return d;
+}
+```
+
+When a pie is [generated](#_pie), the value accessor will be invoked for each element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. The default value accessor assumes that the input data are numbers, or that they are coercible to numbers using [valueOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf). If your data are not simply numbers, then you should specify an accessor that returns the corresponding numeric value for a given datum. For example:
+
+```js
+const data = [
+ {"number": 4, "name": "Locke"},
+ {"number": 8, "name": "Reyes"},
+ {"number": 15, "name": "Ford"},
+ {"number": 16, "name": "Jarrah"},
+ {"number": 23, "name": "Shephard"},
+ {"number": 42, "name": "Kwon"}
+];
+
+const arcs = d3.pie()
+ .value(d => d.number)
+ (data);
+```
+
+This is similar to [mapping](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) your data to values before invoking the pie generator:
+
+```js
+const arcs = d3.pie()(data.map(d => d.number));
+```
+
+The benefit of an accessor is that the input data remains associated with the returned objects, thereby making it easier to access other fields of the data, for example to set the color or to add text labels.
+
+# pie.sort([compare]) · [Source](https://github.com/d3/d3-shape/blob/main/src/pie.js)
+
+If *compare* is specified, sets the data comparator to the specified function and returns this pie generator. If *compare* is not specified, returns the current data comparator, which defaults to null. If both the data comparator and the value comparator are null, then arcs are positioned in the original input order. Otherwise, the data is sorted according to the data comparator, and the resulting order is used. Setting the data comparator implicitly sets the [value comparator](#pie_sortValues) to null.
+
+The *compare* function takes two arguments *a* and *b*, each elements from the input data array. If the arc for *a* should be before the arc for *b*, then the comparator must return a number less than zero; if the arc for *a* should be after the arc for *b*, then the comparator must return a number greater than zero; returning zero means that the relative order of *a* and *b* is unspecified. For example, to sort arcs by their associated name:
+
+```js
+pie.sort((a, b) => a.name.localeCompare(b.name));
+```
+
+Sorting does not affect the order of the [generated arc array](#_pie) which is always in the same order as the input data array; it merely affects the computed angles of each arc. The first arc starts at the [start angle](#pie_startAngle) and the last arc ends at the [end angle](#pie_endAngle).
+
+# pie.sortValues([compare]) · [Source](https://github.com/d3/d3-shape/blob/main/src/pie.js)
+
+If *compare* is specified, sets the value comparator to the specified function and returns this pie generator. If *compare* is not specified, returns the current value comparator, which defaults to descending value. The default value comparator is implemented as:
+
+```js
+function compare(a, b) {
+ return b - a;
+}
+```
+
+If both the data comparator and the value comparator are null, then arcs are positioned in the original input order. Otherwise, the data is sorted according to the data comparator, and the resulting order is used. Setting the value comparator implicitly sets the [data comparator](#pie_sort) to null.
+
+The value comparator is similar to the [data comparator](#pie_sort), except the two arguments *a* and *b* are values derived from the input data array using the [value accessor](#pie_value), not the data elements. If the arc for *a* should be before the arc for *b*, then the comparator must return a number less than zero; if the arc for *a* should be after the arc for *b*, then the comparator must return a number greater than zero; returning zero means that the relative order of *a* and *b* is unspecified. For example, to sort arcs by ascending value:
+
+```js
+pie.sortValues((a, b) => a - b);
+```
+
+Sorting does not affect the order of the [generated arc array](#_pie) which is always in the same order as the input data array; it merely affects the computed angles of each arc. The first arc starts at the [start angle](#pie_startAngle) and the last arc ends at the [end angle](#pie_endAngle).
+
+# pie.startAngle([angle]) · [Source](https://github.com/d3/d3-shape/blob/main/src/pie.js)
+
+If *angle* is specified, sets the overall start angle of the pie to the specified function or number and returns this pie generator. If *angle* is not specified, returns the current start angle accessor, which defaults to:
+
+```js
+function startAngle() {
+ return 0;
+}
+```
+
+The start angle here means the *overall* start angle of the pie, *i.e.*, the start angle of the first arc. The start angle accessor is invoked once, being passed the same arguments and `this` context as the [pie generator](#_pie). The units of *angle* are arbitrary, but if you plan to use the pie generator in conjunction with an [arc generator](#arcs), you should specify an angle in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise.
+
+# pie.endAngle([angle]) · [Source](https://github.com/d3/d3-shape/blob/main/src/pie.js)
+
+If *angle* is specified, sets the overall end angle of the pie to the specified function or number and returns this pie generator. If *angle* is not specified, returns the current end angle accessor, which defaults to:
+
+```js
+function endAngle() {
+ return 2 * Math.PI;
+}
+```
+
+The end angle here means the *overall* end angle of the pie, *i.e.*, the end angle of the last arc. The end angle accessor is invoked once, being passed the same arguments and `this` context as the [pie generator](#_pie). The units of *angle* are arbitrary, but if you plan to use the pie generator in conjunction with an [arc generator](#arcs), you should specify an angle in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise.
+
+The value of the end angle is constrained to [startAngle](#pie_startAngle) ± τ, such that |endAngle - startAngle| ≤ τ.
+
+# pie.padAngle([angle]) · [Source](https://github.com/d3/d3-shape/blob/main/src/pie.js)
+
+If *angle* is specified, sets the pad angle to the specified function or number and returns this pie generator. If *angle* is not specified, returns the current pad angle accessor, which defaults to:
+
+```js
+function padAngle() {
+ return 0;
+}
+```
+
+The pad angle here means the angular separation between each adjacent arc. The total amount of padding reserved is the specified *angle* times the number of elements in the input data array, and at most |endAngle - startAngle|; the remaining space is then divided proportionally by [value](#pie_value) such that the relative area of each arc is preserved. See the [pie padding animation](https://observablehq.com/@d3/arc-pad-angle) for illustration. The pad angle accessor is invoked once, being passed the same arguments and `this` context as the [pie generator](#_pie). The units of *angle* are arbitrary, but if you plan to use the pie generator in conjunction with an [arc generator](#arcs), you should specify an angle in radians.
+
+### Lines
+
+[
](https://observablehq.com/@d3/line-chart)
+
+The line generator produces a [spline](https://en.wikipedia.org/wiki/Spline_\(mathematics\)) or [polyline](https://en.wikipedia.org/wiki/Polygonal_chain), as in a line chart. Lines also appear in many other visualization types, such as the links in [hierarchical edge bundling](https://observablehq.com/@d3/hierarchical-edge-bundling).
+
+# d3.line([x][, y]) · [Source](https://github.com/d3/d3-shape/blob/main/src/line.js), [Examples](https://observablehq.com/@d3/d3-line)
+
+Constructs a new line generator with the default settings. If *x* or *y* are specified, sets the corresponding accessors to the specified function or number and returns this line generator.
+
+# line(data) · [Source](https://github.com/d3/d3-shape/blob/main/src/line.js), [Examples](https://observablehq.com/@d3/d3-line)
+
+Generates a line for the given array of *data*. Depending on this line generator’s associated [curve](#line_curve), the given input *data* may need to be sorted by *x*-value before being passed to the line generator. If the line generator has a [context](#line_context), then the line is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls and this function returns void. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string is returned.
+
+# line.x([x]) · [Source](https://github.com/d3/d3-shape/blob/main/src/line.js), [Examples](https://observablehq.com/@d3/d3-line)
+
+If *x* is specified, sets the x accessor to the specified function or number and returns this line generator. If *x* is not specified, returns the current x accessor, which defaults to:
+
+```js
+function x(d) {
+ return d[0];
+}
+```
+
+When a line is [generated](#_line), the x accessor will be invoked for each [defined](#line_defined) element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. The default x accessor assumes that the input data are two-element arrays of numbers. If your data are in a different format, or if you wish to transform the data before rendering, then you should specify a custom accessor. For example, if `x` is a [time scale](https://github.com/d3/d3-scale#time-scales) and `y` is a [linear scale](https://github.com/d3/d3-scale#linear-scales):
+
+```js
+const data = [
+ {date: new Date(2007, 3, 24), value: 93.24},
+ {date: new Date(2007, 3, 25), value: 95.35},
+ {date: new Date(2007, 3, 26), value: 98.84},
+ {date: new Date(2007, 3, 27), value: 99.92},
+ {date: new Date(2007, 3, 30), value: 99.80},
+ {date: new Date(2007, 4, 1), value: 99.47},
+ …
+];
+
+const line = d3.line()
+ .x(d => x(d.date))
+ .y(d => y(d.value));
+```
+
+# line.y([y]) · [Source](https://github.com/d3/d3-shape/blob/main/src/line.js), [Examples](https://observablehq.com/@d3/d3-line)
+
+If *y* is specified, sets the y accessor to the specified function or number and returns this line generator. If *y* is not specified, returns the current y accessor, which defaults to:
+
+```js
+function y(d) {
+ return d[1];
+}
+```
+
+When a line is [generated](#_line), the y accessor will be invoked for each [defined](#line_defined) element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. The default y accessor assumes that the input data are two-element arrays of numbers. See [*line*.x](#line_x) for more information.
+
+# line.defined([defined]) · [Source](https://github.com/d3/d3-shape/blob/main/src/line.js), [Examples](https://observablehq.com/@d3/d3-line)
+
+If *defined* is specified, sets the defined accessor to the specified function or boolean and returns this line generator. If *defined* is not specified, returns the current defined accessor, which defaults to:
+
+```js
+function defined() {
+ return true;
+}
+```
+
+The default accessor thus assumes that the input data is always defined. When a line is [generated](#_line), the defined accessor will be invoked for each element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. If the given element is defined (*i.e.*, if the defined accessor returns a truthy value for this element), the [x](#line_x) and [y](#line_y) accessors will subsequently be evaluated and the point will be added to the current line segment. Otherwise, the element will be skipped, the current line segment will be ended, and a new line segment will be generated for the next defined point. As a result, the generated line may have several discrete segments. For example:
+
+[
](https://observablehq.com/@d3/line-with-missing-data)
+
+Note that if a line segment consists of only a single point, it may appear invisible unless rendered with rounded or square [line caps](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-linecap). In addition, some curves such as [curveCardinalOpen](#curveCardinalOpen) only render a visible segment if it contains multiple points.
+
+# line.curve([curve]) · [Source](https://github.com/d3/d3-shape/blob/main/src/line.js), [Examples](https://observablehq.com/@d3/d3-line)
+
+If *curve* is specified, sets the [curve factory](#curves) and returns this line generator. If *curve* is not specified, returns the current curve factory, which defaults to [curveLinear](#curveLinear).
+
+# line.context([context]) · [Source](https://github.com/d3/d3-shape/blob/main/src/line.js), [Examples](https://observablehq.com/@d3/d3-line)
+
+If *context* is specified, sets the context and returns this line generator. If *context* is not specified, returns the current context, which defaults to null. If the context is not null, then the [generated line](#_line) is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string representing the generated line is returned.
+
+# line.digits([digits]) · [Source](https://github.com/d3/d3-shape/blob/main/src/line.js)
+
+If *digits* is specified, sets the maximum number of digits after the decimal separator and returns this line generator. If *digits* is not specified, returns the current maximum fraction digits, which defaults to 3. This option only applies when the associated [*context*](#line_context) is null, as when this line generator is used to produce [path data](http://www.w3.org/TR/SVG/paths.html#PathData).
+
+# d3.lineRadial() · [Source](https://github.com/d3/d3-shape/blob/main/src/lineRadial.js), [Examples](https://observablehq.com/@d3/d3-lineradial)
+
+
+
+Constructs a new radial line generator with the default settings. A radial line generator is equivalent to the standard Cartesian [line generator](#line), except the [x](#line_x) and [y](#line_y) accessors are replaced with [angle](#lineRadial_angle) and [radius](#lineRadial_radius) accessors. Radial lines are always positioned relative to ⟨0,0⟩; use a transform (see: [SVG](http://www.w3.org/TR/SVG/coords.html#TransformAttribute), [Canvas](http://www.w3.org/TR/2dcontext/#transformations)) to change the origin.
+
+# lineRadial(data) · [Source](https://github.com/d3/d3-shape/blob/main/src/lineRadial.js#L4), [Examples](https://observablehq.com/@d3/d3-lineradial)
+
+Equivalent to [*line*](#_line).
+
+# lineRadial.angle([angle]) · [Source](https://github.com/d3/d3-shape/blob/main/src/lineRadial.js#L7), [Examples](https://observablehq.com/@d3/d3-lineradial)
+
+Equivalent to [*line*.x](#line_x), except the accessor returns the angle in radians, with 0 at -*y* (12 o’clock).
+
+# lineRadial.radius([radius]) · [Source](https://github.com/d3/d3-shape/blob/main/src/lineRadial.js#L8), [Examples](https://observablehq.com/@d3/d3-lineradial)
+
+Equivalent to [*line*.y](#line_y), except the accessor returns the radius: the distance from the origin ⟨0,0⟩.
+
+# lineRadial.defined([defined])
+
+Equivalent to [*line*.defined](#line_defined).
+
+# lineRadial.curve([curve]) · [Source](https://github.com/d3/d3-shape/blob/main/src/lineRadial.js), [Examples](https://observablehq.com/@d3/d3-lineradial)
+
+Equivalent to [*line*.curve](#line_curve). Note that [curveMonotoneX](#curveMonotoneX) or [curveMonotoneY](#curveMonotoneY) are not recommended for radial lines because they assume that the data is monotonic in *x* or *y*, which is typically untrue of radial lines.
+
+# lineRadial.context([context])
+
+Equivalent to [*line*.context](#line_context).
+
+### Areas
+
+[
](https://observablehq.com/@d3/area-chart)[
](https://observablehq.com/@d3/stacked-area-chart)[
](https://observablehq.com/@d3/difference-chart)
+
+The area generator produces an area, as in an area chart. An area is defined by two bounding [lines](#lines), either splines or polylines. Typically, the two lines share the same [*x*-values](#area_x) ([x0](#area_x0) = [x1](#area_x1)), differing only in *y*-value ([y0](#area_y0) and [y1](#area_y1)); most commonly, y0 is defined as a constant representing [zero](http://www.vox.com/2015/11/19/9758062/y-axis-zero-chart). The first line (the topline) is defined by x1 and y1 and is rendered first; the second line (the baseline) is defined by x0 and y0 and is rendered second, with the points in reverse order. With a [curveLinear](#curveLinear) [curve](#area_curve), this produces a clockwise polygon.
+
+# d3.area([x][, y0][, y1]) · [Source](https://github.com/d3/d3-shape/blob/main/src/area.js)
+
+Constructs a new area generator with the default settings. If *x*, *y0* or *y1* are specified, sets the corresponding accessors to the specified function or number and returns this area generator.
+
+# area(data) · [Source](https://github.com/d3/d3-shape/blob/main/src/area.js)
+
+Generates an area for the given array of *data*. Depending on this area generator’s associated [curve](#area_curve), the given input *data* may need to be sorted by *x*-value before being passed to the area generator. If the area generator has a [context](#line_context), then the area is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls and this function returns void. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string is returned.
+
+# area.x([x]) · [Source](https://github.com/d3/d3-shape/blob/main/src/area.js)
+
+If *x* is specified, sets [x0](#area_x0) to *x* and [x1](#area_x1) to null and returns this area generator. If *x* is not specified, returns the current x0 accessor.
+
+# area.x0([x]) · [Source](https://github.com/d3/d3-shape/blob/main/src/area.js)
+
+If *x* is specified, sets the x0 accessor to the specified function or number and returns this area generator. If *x* is not specified, returns the current x0 accessor, which defaults to:
+
+```js
+function x(d) {
+ return d[0];
+}
+```
+
+When an area is [generated](#_area), the x0 accessor will be invoked for each [defined](#area_defined) element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. The default x0 accessor assumes that the input data are two-element arrays of numbers. If your data are in a different format, or if you wish to transform the data before rendering, then you should specify a custom accessor. For example, if `x` is a [time scale](https://github.com/d3/d3-scale#time-scales) and `y` is a [linear scale](https://github.com/d3/d3-scale#linear-scales):
+
+```js
+const data = [
+ {date: new Date(2007, 3, 24), value: 93.24},
+ {date: new Date(2007, 3, 25), value: 95.35},
+ {date: new Date(2007, 3, 26), value: 98.84},
+ {date: new Date(2007, 3, 27), value: 99.92},
+ {date: new Date(2007, 3, 30), value: 99.80},
+ {date: new Date(2007, 4, 1), value: 99.47},
+ …
+];
+
+const area = d3.area()
+ .x(d => x(d.date))
+ .y1(d => y(d.value))
+ .y0(y(0));
+```
+
+# area.x1([x]) · [Source](https://github.com/d3/d3-shape/blob/main/src/area.js)
+
+If *x* is specified, sets the x1 accessor to the specified function or number and returns this area generator. If *x* is not specified, returns the current x1 accessor, which defaults to null, indicating that the previously-computed [x0](#area_x0) value should be reused for the x1 value.
+
+When an area is [generated](#_area), the x1 accessor will be invoked for each [defined](#area_defined) element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. See [*area*.x0](#area_x0) for more information.
+
+# area.y([y]) · [Source](https://github.com/d3/d3-shape/blob/main/src/area.js)
+
+If *y* is specified, sets [y0](#area_y0) to *y* and [y1](#area_y1) to null and returns this area generator. If *y* is not specified, returns the current y0 accessor.
+
+# area.y0([y]) · [Source](https://github.com/d3/d3-shape/blob/main/src/area.js)
+
+If *y* is specified, sets the y0 accessor to the specified function or number and returns this area generator. If *y* is not specified, returns the current y0 accessor, which defaults to:
+
+```js
+function y() {
+ return 0;
+}
+```
+
+When an area is [generated](#_area), the y0 accessor will be invoked for each [defined](#area_defined) element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. See [*area*.x0](#area_x0) for more information.
+
+# area.y1([y]) · [Source](https://github.com/d3/d3-shape/blob/main/src/area.js)
+
+If *y* is specified, sets the y1 accessor to the specified function or number and returns this area generator. If *y* is not specified, returns the current y1 accessor, which defaults to:
+
+```js
+function y(d) {
+ return d[1];
+}
+```
+
+A null accessor is also allowed, indicating that the previously-computed [y0](#area_y0) value should be reused for the y1 value. When an area is [generated](#_area), the y1 accessor will be invoked for each [defined](#area_defined) element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. See [*area*.x0](#area_x0) for more information.
+
+# area.defined([defined]) · [Source](https://github.com/d3/d3-shape/blob/main/src/area.js)
+
+If *defined* is specified, sets the defined accessor to the specified function or boolean and returns this area generator. If *defined* is not specified, returns the current defined accessor, which defaults to:
+
+```js
+function defined() {
+ return true;
+}
+```
+
+The default accessor thus assumes that the input data is always defined. When an area is [generated](#_area), the defined accessor will be invoked for each element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. If the given element is defined (*i.e.*, if the defined accessor returns a truthy value for this element), the [x0](#area_x0), [x1](#area_x1), [y0](#area_y0) and [y1](#area_y1) accessors will subsequently be evaluated and the point will be added to the current area segment. Otherwise, the element will be skipped, the current area segment will be ended, and a new area segment will be generated for the next defined point. As a result, the generated area may have several discrete segments. For example:
+
+[
](https://observablehq.com/@d3/area-with-missing-data)
+
+Note that if an area segment consists of only a single point, it may appear invisible unless rendered with rounded or square [line caps](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-linecap). In addition, some curves such as [curveCardinalOpen](#curveCardinalOpen) only render a visible segment if it contains multiple points.
+
+# area.curve([curve]) · [Source](https://github.com/d3/d3-shape/blob/main/src/area.js)
+
+If *curve* is specified, sets the [curve factory](#curves) and returns this area generator. If *curve* is not specified, returns the current curve factory, which defaults to [curveLinear](#curveLinear).
+
+# area.context([context]) · [Source](https://github.com/d3/d3-shape/blob/main/src/area.js)
+
+If *context* is specified, sets the context and returns this area generator. If *context* is not specified, returns the current context, which defaults to null. If the context is not null, then the [generated area](#_area) is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string representing the generated area is returned.
+
+# area.digits([digits]) · [Source](https://github.com/d3/d3-shape/blob/main/src/area.js)
+
+If *digits* is specified, sets the maximum number of digits after the decimal separator and returns this area generator. If *digits* is not specified, returns the current maximum fraction digits, which defaults to 3. This option only applies when the associated [*context*](#area_context) is null, as when this area generator is used to produce [path data](http://www.w3.org/TR/SVG/paths.html#PathData).
+
+# area.lineX0() · [Source](https://github.com/d3/d3-shape/blob/main/src/area.js)
+
# area.lineY0() · [Source](https://github.com/d3/d3-shape/blob/main/src/area.js)
+
+Returns a new [line generator](#lines) that has this area generator’s current [defined accessor](#area_defined), [curve](#area_curve) and [context](#area_context). The line’s [*x*-accessor](#line_x) is this area’s [*x0*-accessor](#area_x0), and the line’s [*y*-accessor](#line_y) is this area’s [*y0*-accessor](#area_y0).
+
+# area.lineX1() · [Source](https://github.com/d3/d3-shape/blob/main/src/area.js)
+
+Returns a new [line generator](#lines) that has this area generator’s current [defined accessor](#area_defined), [curve](#area_curve) and [context](#area_context). The line’s [*x*-accessor](#line_x) is this area’s [*x1*-accessor](#area_x1), and the line’s [*y*-accessor](#line_y) is this area’s [*y0*-accessor](#area_y0).
+
+# area.lineY1() · [Source](https://github.com/d3/d3-shape/blob/main/src/area.js)
+
+Returns a new [line generator](#lines) that has this area generator’s current [defined accessor](#area_defined), [curve](#area_curve) and [context](#area_context). The line’s [*x*-accessor](#line_x) is this area’s [*x0*-accessor](#area_x0), and the line’s [*y*-accessor](#line_y) is this area’s [*y1*-accessor](#area_y1).
+
+# d3.areaRadial() · [Source](https://github.com/d3/d3-shape/blob/main/src/areaRadial.js)
+
+
+
+Constructs a new radial area generator with the default settings. A radial area generator is equivalent to the standard Cartesian [area generator](#area), except the [x](#area_x) and [y](#area_y) accessors are replaced with [angle](#areaRadial_angle) and [radius](#areaRadial_radius) accessors. Radial areas are always positioned relative to ⟨0,0⟩; use a transform (see: [SVG](http://www.w3.org/TR/SVG/coords.html#TransformAttribute), [Canvas](http://www.w3.org/TR/2dcontext/#transformations)) to change the origin.
+
+# areaRadial(data)
+
+Equivalent to [*area*](#_area).
+
+# areaRadial.angle([angle]) · [Source](https://github.com/d3/d3-shape/blob/main/src/areaRadial.js)
+
+Equivalent to [*area*.x](#area_x), except the accessor returns the angle in radians, with 0 at -*y* (12 o’clock).
+
+# areaRadial.startAngle([angle]) · [Source](https://github.com/d3/d3-shape/blob/main/src/areaRadial.js)
+
+Equivalent to [*area*.x0](#area_x0), except the accessor returns the angle in radians, with 0 at -*y* (12 o’clock). Note: typically [angle](#areaRadial_angle) is used instead of setting separate start and end angles.
+
+# areaRadial.endAngle([angle]) · [Source](https://github.com/d3/d3-shape/blob/main/src/areaRadial.js)
+
+Equivalent to [*area*.x1](#area_x1), except the accessor returns the angle in radians, with 0 at -*y* (12 o’clock). Note: typically [angle](#areaRadial_angle) is used instead of setting separate start and end angles.
+
+# areaRadial.radius([radius]) · [Source](https://github.com/d3/d3-shape/blob/main/src/areaRadial.js)
+
+Equivalent to [*area*.y](#area_y), except the accessor returns the radius: the distance from the origin ⟨0,0⟩.
+
+# areaRadial.innerRadius([radius]) · [Source](https://github.com/d3/d3-shape/blob/main/src/areaRadial.js)
+
+Equivalent to [*area*.y0](#area_y0), except the accessor returns the radius: the distance from the origin ⟨0,0⟩.
+
+# areaRadial.outerRadius([radius]) · [Source](https://github.com/d3/d3-shape/blob/main/src/areaRadial.js)
+
+Equivalent to [*area*.y1](#area_y1), except the accessor returns the radius: the distance from the origin ⟨0,0⟩.
+
+# areaRadial.defined([defined])
+
+Equivalent to [*area*.defined](#area_defined).
+
+# areaRadial.curve([curve]) · [Source](https://github.com/d3/d3-shape/blob/main/src/areaRadial.js)
+
+Equivalent to [*area*.curve](#area_curve). Note that [curveMonotoneX](#curveMonotoneX) or [curveMonotoneY](#curveMonotoneY) are not recommended for radial areas because they assume that the data is monotonic in *x* or *y*, which is typically untrue of radial areas.
+
+# areaRadial.context([context])
+
+Equivalent to [*line*.context](#line_context).
+
+# areaRadial.lineStartAngle() · [Source](https://github.com/d3/d3-shape/blob/main/src/areaRadial.js)
+
# areaRadial.lineInnerRadius() · [Source](https://github.com/d3/d3-shape/blob/main/src/areaRadial.js)
+
+Returns a new [radial line generator](#lineRadial) that has this radial area generator’s current [defined accessor](#areaRadial_defined), [curve](#areaRadial_curve) and [context](#areaRadial_context). The line’s [angle accessor](#lineRadial_angle) is this area’s [start angle accessor](#areaRadial_startAngle), and the line’s [radius accessor](#lineRadial_radius) is this area’s [inner radius accessor](#areaRadial_innerRadius).
+
+# areaRadial.lineEndAngle() · [Source](https://github.com/d3/d3-shape/blob/main/src/areaRadial.js)
+
+Returns a new [radial line generator](#lineRadial) that has this radial area generator’s current [defined accessor](#areaRadial_defined), [curve](#areaRadial_curve) and [context](#areaRadial_context). The line’s [angle accessor](#lineRadial_angle) is this area’s [end angle accessor](#areaRadial_endAngle), and the line’s [radius accessor](#lineRadial_radius) is this area’s [inner radius accessor](#areaRadial_innerRadius).
+
+# areaRadial.lineOuterRadius() · [Source](https://github.com/d3/d3-shape/blob/main/src/areaRadial.js)
+
+Returns a new [radial line generator](#lineRadial) that has this radial area generator’s current [defined accessor](#areaRadial_defined), [curve](#areaRadial_curve) and [context](#areaRadial_context). The line’s [angle accessor](#lineRadial_angle) is this area’s [start angle accessor](#areaRadial_startAngle), and the line’s [radius accessor](#lineRadial_radius) is this area’s [outer radius accessor](#areaRadial_outerRadius).
+
+### Curves
+
+While [lines](#lines) are defined as a sequence of two-dimensional [*x*, *y*] points, and [areas](#areas) are similarly defined by a topline and a baseline, there remains the task of transforming this discrete representation into a continuous shape: *i.e.*, how to interpolate between the points. A variety of curves are provided for this purpose.
+
+Curves are typically not constructed or used directly, instead being passed to [*line*.curve](#line_curve) and [*area*.curve](#area_curve). For example:
+
+```js
+const line = d3.line(d => d.date, d => d.value)
+ .curve(d3.curveCatmullRom.alpha(0.5));
+```
+
+# d3.curveBasis(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/basis.js)
+
+
+
+Produces a cubic [basis spline](https://en.wikipedia.org/wiki/B-spline) using the specified control points. The first and last points are triplicated such that the spline starts at the first point and ends at the last point, and is tangent to the line between the first and second points, and to the line between the penultimate and last points.
+
+# d3.curveBasisClosed(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/basisClosed.js)
+
+
+
+Produces a closed cubic [basis spline](https://en.wikipedia.org/wiki/B-spline) using the specified control points. When a line segment ends, the first three control points are repeated, producing a closed loop with C2 continuity.
+
+# d3.curveBasisOpen(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/basisOpen.js)
+
+
+
+Produces a cubic [basis spline](https://en.wikipedia.org/wiki/B-spline) using the specified control points. Unlike [basis](#basis), the first and last points are not repeated, and thus the curve typically does not intersect these points.
+
+# d3.curveBumpX(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/bump.js)
+
+
+
+Produces a Bézier curve between each pair of points, with horizontal tangents at each point.
+
+# d3.curveBumpY(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/bump.js)
+
+
+
+Produces a Bézier curve between each pair of points, with vertical tangents at each point.
+
+# d3.curveBundle(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/bundle.js)
+
+
+
+Produces a straightened cubic [basis spline](https://en.wikipedia.org/wiki/B-spline) using the specified control points, with the spline straightened according to the curve’s [*beta*](#curveBundle_beta), which defaults to 0.85. This curve is typically used in [hierarchical edge bundling](https://observablehq.com/@d3/hierarchical-edge-bundling) to disambiguate connections, as proposed by [Danny Holten](https://www.win.tue.nl/vis1/home/dholten/) in [Hierarchical Edge Bundles: Visualization of Adjacency Relations in Hierarchical Data](https://www.win.tue.nl/vis1/home/dholten/papers/bundles_infovis.pdf). This curve does not implement [*curve*.areaStart](#curve_areaStart) and [*curve*.areaEnd](#curve_areaEnd); it is intended to work with [d3.line](#lines), not [d3.area](#areas).
+
+# bundle.beta(beta) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/bundle.js)
+
+Returns a bundle curve with the specified *beta* in the range [0, 1], representing the bundle strength. If *beta* equals zero, a straight line between the first and last point is produced; if *beta* equals one, a standard [basis](#basis) spline is produced. For example:
+
+```js
+const line = d3.line().curve(d3.curveBundle.beta(0.5));
+```
+
+# d3.curveCardinal(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/cardinal.js)
+
+
+
+Produces a cubic [cardinal spline](https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Cardinal_spline) using the specified control points, with one-sided differences used for the first and last piece. The default [tension](#curveCardinal_tension) is 0.
+
+# d3.curveCardinalClosed(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/cardinalClosed.js)
+
+
+
+Produces a closed cubic [cardinal spline](https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Cardinal_spline) using the specified control points. When a line segment ends, the first three control points are repeated, producing a closed loop. The default [tension](#curveCardinal_tension) is 0.
+
+# d3.curveCardinalOpen(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/cardinalOpen.js)
+
+
+
+Produces a cubic [cardinal spline](https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Cardinal_spline) using the specified control points. Unlike [curveCardinal](#curveCardinal), one-sided differences are not used for the first and last piece, and thus the curve starts at the second point and ends at the penultimate point. The default [tension](#curveCardinal_tension) is 0.
+
+# cardinal.tension(tension) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/cardinalOpen.js)
+
+Returns a cardinal curve with the specified *tension* in the range [0, 1]. The *tension* determines the length of the tangents: a *tension* of one yields all zero tangents, equivalent to [curveLinear](#curveLinear); a *tension* of zero produces a uniform [Catmull–Rom](#curveCatmullRom) spline. For example:
+
+```js
+const line = d3.line().curve(d3.curveCardinal.tension(0.5));
+```
+
+# d3.curveCatmullRom(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/catmullRom.js)
+
+
+
+Produces a cubic Catmull–Rom spline using the specified control points and the parameter [*alpha*](#curveCatmullRom_alpha), which defaults to 0.5, as proposed by Yuksel et al. in [On the Parameterization of Catmull–Rom Curves](http://www.cemyuksel.com/research/catmullrom_param/), with one-sided differences used for the first and last piece.
+
+# d3.curveCatmullRomClosed(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/catmullRomClosed.js)
+
+
+
+Produces a closed cubic Catmull–Rom spline using the specified control points and the parameter [*alpha*](#curveCatmullRom_alpha), which defaults to 0.5, as proposed by Yuksel et al. When a line segment ends, the first three control points are repeated, producing a closed loop.
+
+# d3.curveCatmullRomOpen(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/catmullRomOpen.js)
+
+
+
+Produces a cubic Catmull–Rom spline using the specified control points and the parameter [*alpha*](#curveCatmullRom_alpha), which defaults to 0.5, as proposed by Yuksel et al. Unlike [curveCatmullRom](#curveCatmullRom), one-sided differences are not used for the first and last piece, and thus the curve starts at the second point and ends at the penultimate point.
+
+# catmullRom.alpha(alpha) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/catmullRom.js)
+
+Returns a cubic Catmull–Rom curve with the specified *alpha* in the range [0, 1]. If *alpha* is zero, produces a uniform spline, equivalent to [curveCardinal](#curveCardinal) with a tension of zero; if *alpha* is one, produces a chordal spline; if *alpha* is 0.5, produces a [centripetal spline](https://en.wikipedia.org/wiki/Centripetal_Catmull–Rom_spline). Centripetal splines are recommended to avoid self-intersections and overshoot. For example:
+
+```js
+const line = d3.line().curve(d3.curveCatmullRom.alpha(0.5));
+```
+
+# d3.curveLinear(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/linear.js)
+
+
+
+Produces a polyline through the specified points.
+
+# d3.curveLinearClosed(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/linearClosed.js)
+
+
+
+Produces a closed polyline through the specified points by repeating the first point when the line segment ends.
+
+# d3.curveMonotoneX(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/monotone.js)
+
+
+
+Produces a cubic spline that [preserves monotonicity](https://en.wikipedia.org/wiki/Monotone_cubic_interpolation) in *y*, assuming monotonicity in *x*, as proposed by Steffen in [A simple method for monotonic interpolation in one dimension](http://adsabs.harvard.edu/full/1990A%26A...239..443S): “a smooth curve with continuous first-order derivatives that passes through any given set of data points without spurious oscillations. Local extrema can occur only at grid points where they are given by the data, but not in between two adjacent grid points.”
+
+# d3.curveMonotoneY(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/monotone.js)
+
+
+
+Produces a cubic spline that [preserves monotonicity](https://en.wikipedia.org/wiki/Monotone_cubic_interpolation) in *x*, assuming monotonicity in *y*, as proposed by Steffen in [A simple method for monotonic interpolation in one dimension](http://adsabs.harvard.edu/full/1990A%26A...239..443S): “a smooth curve with continuous first-order derivatives that passes through any given set of data points without spurious oscillations. Local extrema can occur only at grid points where they are given by the data, but not in between two adjacent grid points.”
+
+# d3.curveNatural(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/natural.js)
+
+
+
+Produces a [natural](https://en.wikipedia.org/wiki/Spline_interpolation) [cubic spline](http://mathworld.wolfram.com/CubicSpline.html) with the second derivative of the spline set to zero at the endpoints.
+
+# d3.curveStep(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/step.js)
+
+
+
+Produces a piecewise constant function (a [step function](https://en.wikipedia.org/wiki/Step_function)) consisting of alternating horizontal and vertical lines. The *y*-value changes at the midpoint of each pair of adjacent *x*-values.
+
+# d3.curveStepAfter(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/step.js)
+
+
+
+Produces a piecewise constant function (a [step function](https://en.wikipedia.org/wiki/Step_function)) consisting of alternating horizontal and vertical lines. The *y*-value changes after the *x*-value.
+
+# d3.curveStepBefore(context) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/step.js)
+
+
+
+Produces a piecewise constant function (a [step function](https://en.wikipedia.org/wiki/Step_function)) consisting of alternating horizontal and vertical lines. The *y*-value changes before the *x*-value.
+
+### Custom Curves
+
+Curves are typically not used directly, instead being passed to [*line*.curve](#line_curve) and [*area*.curve](#area_curve). However, you can define your own curve implementation should none of the built-in curves satisfy your needs using the following interface. You can also use this low-level interface with a built-in curve type as an alternative to the line and area generators.
+
+# curve.areaStart() · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/step.js#L7)
+
+Indicates the start of a new area segment. Each area segment consists of exactly two [line segments](#curve_lineStart): the topline, followed by the baseline, with the baseline points in reverse order.
+
+# curve.areaEnd() · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/step.js)
+
+Indicates the end of the current area segment.
+
+# curve.lineStart() · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/step.js)
+
+Indicates the start of a new line segment. Zero or more [points](#curve_point) will follow.
+
+# curve.lineEnd() · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/step.js)
+
+Indicates the end of the current line segment.
+
+# curve.point(x, y) · [Source](https://github.com/d3/d3-shape/blob/main/src/curve/step.js)
+
+Indicates a new point in the current line segment with the given *x*- and *y*-values.
+
+### Links
+
+[
](https://observablehq.com/@d3/tidy-tree)
+
+The **link** shape generates a smooth cubic Bézier curve from a source point to a target point. The tangents of the curve at the start and end are either [vertical](#linkVertical), [horizontal](#linkHorizontal) or [radial](#linkRadial).
+
+# d3.link(curve) · [Source](https://github.com/d3/d3-shape/blob/main/src/link.js)
+
+Returns a new [link generator](#_link) using the specified curve. For example, to visualize [links](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_links) in a [tree diagram](https://github.com/d3/d3-hierarchy/blob/master/README.md#tree) rooted on the top edge of the display, you might say:
+
+```js
+const link = d3.link(d3.curveBumpY)
+ .x(d => d.x)
+ .y(d => d.y);
+```
+
+# d3.linkVertical() · [Source](https://github.com/d3/d3-shape/blob/main/src/link.js)
+
+Shorthand for [d3.link](#link) with [d3.curveBumpY](#curveBumpY); suitable for visualizing [links](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_links) in a [tree diagram](https://github.com/d3/d3-hierarchy/blob/master/README.md#tree) rooted on the top edge of the display. Equivalent to:
+
+```js
+const link = d3.link(d3.curveBumpY);
+```
+
+# d3.linkHorizontal() · [Source](https://github.com/d3/d3-shape/blob/main/src/link.js)
+
+Shorthand for [d3.link](#link) with [d3.curveBumpX](#curveBumpX); suitable for visualizing [links](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_links) in a [tree diagram](https://github.com/d3/d3-hierarchy/blob/master/README.md#tree) rooted on the left edge of the display. Equivalent to:
+
+```js
+const link = d3.link(d3.curveBumpX);
+```
+
+# link(arguments…) · [Source](https://github.com/d3/d3-shape/blob/main/src/link.js)
+
+Generates a link for the given *arguments*. The *arguments* are arbitrary; they are simply propagated to the link generator’s accessor functions along with the `this` object. For example, with the default settings, an object expected:
+
+```js
+link({
+ source: [100, 100],
+ target: [300, 300]
+});
+```
+
+# link.source([source]) · [Source](https://github.com/d3/d3-shape/blob/main/src/link.js)
+
+If *source* is specified, sets the source accessor to the specified function and returns this link generator. If *source* is not specified, returns the current source accessor, which defaults to:
+
+```js
+function source(d) {
+ return d.source;
+}
+```
+
+# link.target([target]) · [Source](https://github.com/d3/d3-shape/blob/main/src/link.js)
+
+If *target* is specified, sets the target accessor to the specified function and returns this link generator. If *target* is not specified, returns the current target accessor, which defaults to:
+
+```js
+function target(d) {
+ return d.target;
+}
+```
+
+# link.x([x]) · [Source](https://github.com/d3/d3-shape/blob/main/src/link.js)
+
+If *x* is specified, sets the *x*-accessor to the specified function or number and returns this link generator. If *x* is not specified, returns the current *x*-accessor, which defaults to:
+
+```js
+function x(d) {
+ return d[0];
+}
+```
+
+# link.y([y]) · [Source](https://github.com/d3/d3-shape/blob/main/src/link.js)
+
+If *y* is specified, sets the *y*-accessor to the specified function or number and returns this link generator. If *y* is not specified, returns the current *y*-accessor, which defaults to:
+
+```js
+function y(d) {
+ return d[1];
+}
+```
+
+# link.context([context]) · [Source](https://github.com/d3/d3-shape/blob/main/src/link.js)
+
+If *context* is specified, sets the context and returns this link generator. If *context* is not specified, returns the current context, which defaults to null. If the context is not null, then the [generated link](#_link) is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string representing the generated link is returned. See also [d3-path](https://github.com/d3/d3-path).
+
+# link.digits([digits]) · [Source](https://github.com/d3/d3-shape/blob/main/src/link.js)
+
+If *digits* is specified, sets the maximum number of digits after the decimal separator and returns this link generator. If *digits* is not specified, returns the current maximum fraction digits, which defaults to 3. This option only applies when the associated [*context*](#link_context) is null, as when this link generator is used to produce [path data](http://www.w3.org/TR/SVG/paths.html#PathData).
+
+# d3.linkRadial() · [Source](https://github.com/d3/d3-shape/blob/main/src/link.js)
+
+Returns a new [link generator](#_link) with radial tangents. For example, to visualize [links](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_links) in a [tree diagram](https://github.com/d3/d3-hierarchy/blob/master/README.md#tree) rooted in the center of the display, you might say:
+
+```js
+const link = d3.linkRadial()
+ .angle(d => d.x)
+ .radius(d => d.y);
+```
+
+# linkRadial.angle([angle]) · [Source](https://github.com/d3/d3-shape/blob/main/src/link.js)
+
+Equivalent to [*link*.x](#link_x), except the accessor returns the angle in radians, with 0 at -*y* (12 o’clock).
+
+# linkRadial.radius([radius]) · [Source](https://github.com/d3/d3-shape/blob/main/src/link.js)
+
+Equivalent to [*link*.y](#link_y), except the accessor returns the radius: the distance from the origin ⟨0,0⟩.
+
+### Symbols
+
+Symbols provide a categorical shape encoding as is commonly used in scatterplots. Symbols are always centered at ⟨0,0⟩; use a transform (see: [SVG](http://www.w3.org/TR/SVG/coords.html#TransformAttribute), [Canvas](http://www.w3.org/TR/2dcontext/#transformations)) to move the symbol to a different position.
+
+# d3.symbol([type][, size]) · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol.js), [Examples](https://observablehq.com/@d3/fitted-symbols)
+
+Constructs a new symbol generator of the specified [type](#symbol_type) and [size](#symbol_size). If not specified, *type* defaults to a circle, and *size* defaults to 64.
+
+# symbol(arguments…) · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol.js)
+
+Generates a symbol for the given *arguments*. The *arguments* are arbitrary; they are simply propagated to the symbol generator’s accessor functions along with the `this` object. For example, with the default settings, no arguments are needed to produce a circle with area 64 square pixels. If the symbol generator has a [context](#symbol_context), then the symbol is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls and this function returns void. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string is returned.
+
+# symbol.type([type]) · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol.js)
+
+If *type* is specified, sets the symbol type to the specified function or symbol type and returns this symbol generator. If *type* is a function, the symbol generator’s arguments and *this* are passed through. (See [*selection*.attr](https://github.com/d3/d3-selection/blob/master/README.md#selection_attr) if you are using d3-selection.) If *type* is not specified, returns the current symbol type accessor, which defaults to:
+
+```js
+function type() {
+ return circle;
+}
+```
+
+See [symbolsFill](#symbolsFill) and [symbolsStroke](#symbolsStroke) for built-in symbol types. To implement a custom symbol type, pass an object that implements [*symbolType*.draw](#symbolType_draw).
+
+# symbol.size([size]) · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol.js)
+
+If *size* is specified, sets the size to the specified function or number and returns this symbol generator. If *size* is a function, the symbol generator’s arguments and *this* are passed through. (See [*selection*.attr](https://github.com/d3/d3-selection/blob/master/README.md#selection_attr) if you are using d3-selection.) If *size* is not specified, returns the current size accessor, which defaults to:
+
+```js
+function size() {
+ return 64;
+}
+```
+
+Specifying the size as a function is useful for constructing a scatterplot with a size encoding. If you wish to scale the symbol to fit a given bounding box, rather than by area, try [SVG’s getBBox](https://observablehq.com/d/1fac2626b9e1b65f).
+
+# symbol.context([context]) · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol.js)
+
+If *context* is specified, sets the context and returns this symbol generator. If *context* is not specified, returns the current context, which defaults to null. If the context is not null, then the [generated symbol](#_symbol) is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string representing the generated symbol is returned.
+
+# symbol.digits([digits]) · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol.js)
+
+If *digits* is specified, sets the maximum number of digits after the decimal separator and returns this symbol generator. If *digits* is not specified, returns the current maximum fraction digits, which defaults to 3. This option only applies when the associated [*context*](#symbol_context) is null, as when this symbol generator is used to produce [path data](http://www.w3.org/TR/SVG/paths.html#PathData).
+
+# d3.symbolsFill · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol.js)
+
+





+
+An array containing a set of symbol types designed for filling: [circle](#symbolCircle), [cross](#symbolCross), [diamond](#symbolDiamond), [square](#symbolSquare), [star](#symbolStar), [triangle](#symbolTriangle), and [wye](#symbolWye). Useful for constructing the range of an [ordinal scale](https://github.com/d3/d3-scale#ordinal-scales) should you wish to use a shape encoding for categorical data.
+
+# d3.symbolsStroke · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol.js)
+
+An array containing a set of symbol types designed for stroking: [circle](#symbolCircle), [plus](#symbolPlus), [times](#symbolTimes), [triangle2](#symbolTriangle2), [asterisk](#symbolAsterisk), [square2](#symbolSquare2), and [diamond2](#symbolDiamond2). Useful for constructing the range of an [ordinal scale](https://github.com/d3/d3-scale#ordinal-scales) should you wish to use a shape encoding for categorical data.
+
+# d3.symbolAsterisk · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol/asterisk.js)
+
+The asterisk symbol type; intended for stroking.
+
+# d3.symbolCircle · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol/circle.js)
+
+The circle symbol type; intended for either filling or stroking.
+
+# d3.symbolCross · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol/cross.js)
+
+The Greek cross symbol type, with arms of equal length; intended for filling.
+
+# d3.symbolDiamond · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol/diamond.js)
+
+The rhombus symbol type; intended for filling.
+
+# d3.symbolDiamond2 · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol/diamond.js)
+
+The rotated square symbol type; intended for stroking.
+
+# d3.symbolPlus · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol/plus.js)
+
+The plus symbol type; intended for stroking.
+
+# d3.symbolSquare · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol/square.js)
+
+The square symbol type; intended for filling.
+
+# d3.symbolSquare2 · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol/square2.js)
+
+The square2 symbol type; intended for stroking.
+
+# d3.symbolStar · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol/star.js)
+
+The pentagonal star (pentagram) symbol type; intended for filling.
+
+# d3.symbolTriangle · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol/triangle.js)
+
+The up-pointing triangle symbol type; intended for filling.
+
+# d3.symbolTriangle2 · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol/triangle2.js)
+
+The up-pointing triangle symbol type; intended for stroking.
+
+# d3.symbolWye · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol/wye.js)
+
+The Y-shape symbol type; intended for filling.
+
+# d3.symbolTimes · [Source](https://github.com/d3/d3-shape/blob/main/src/symbol/times.js)
+
+The X-shape symbol type; intended for stroking.
+
+# d3.pointRadial(angle, radius) · [Source](https://github.com/d3/d3-shape/blob/main/src/pointRadial.js), [Examples](https://observablehq.com/@d3/radial-area-chart)
+
+Returns the point [x, y] for the given *angle* in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise, and the given *radius*.
+
+### Custom Symbol Types
+
+Symbol types are typically not used directly, instead being passed to [*symbol*.type](#symbol_type). However, you can define your own symbol type implementation should none of the built-in types satisfy your needs using the following interface. You can also use this low-level interface with a built-in symbol type as an alternative to the symbol generator.
+
+# symbolType.draw(context, size)
+
+Renders this symbol type to the specified *context* with the specified *size* in square pixels. The *context* implements the [CanvasPathMethods](http://www.w3.org/TR/2dcontext/#canvaspathmethods) interface. (Note that this is a subset of the CanvasRenderingContext2D interface!)
+
+### Stacks
+
+[
](https://observablehq.com/@d3/stacked-bar-chart)[
](https://observablehq.com/@mbostock/streamgraph-transitions)
+
+Some shape types can be stacked, placing one shape adjacent to another. For example, a bar chart of monthly sales might be broken down into a multi-series bar chart by product category, stacking bars vertically. This is equivalent to subdividing a bar chart by an ordinal dimension (such as product category) and applying a color encoding.
+
+Stacked charts can show overall value and per-category value simultaneously; however, it is typically harder to compare across categories, as only the bottom layer of the stack is aligned. So, chose the [stack order](#stack_order) carefully, and consider a [streamgraph](#stackOffsetWiggle). (See also [grouped charts](https://observablehq.com/@d3/grouped-bar-chart).)
+
+Like the [pie generator](#pies), the stack generator does not produce a shape directly. Instead it computes positions which you can then pass to an [area generator](#areas) or use directly, say to position bars.
+
+# d3.stack() · [Source](https://github.com/d3/d3-shape/blob/main/src/stack.js)
+
+Constructs a new stack generator with the default settings.
+
+# stack(data[, arguments…]) · [Source](https://github.com/d3/d3-shape/blob/main/src/stack.js)
+
+Generates a stack for the given array of *data*, returning an array representing each series. Any additional *arguments* are arbitrary; they are simply propagated to accessors along with the `this` object.
+
+The series are determined by the [keys accessor](#stack_keys); each series *i* in the returned array corresponds to the *i*th key. Each series is an array of points, where each point *j* corresponds to the *j*th element in the input *data*. Lastly, each point is represented as an array [*y0*, *y1*] where *y0* is the lower value (baseline) and *y1* is the upper value (topline); the difference between *y0* and *y1* corresponds to the computed [value](#stack_value) for this point. The key for each series is available as *series*.key, and the [index](#stack_order) as *series*.index. The input data element for each point is available as *point*.data.
+
+For example, consider the following table representing monthly sales of fruits:
+
+Month | Apples | Bananas | Cherries | Durians
+--------|--------|---------|----------|---------
+ 1/2015 | 3840 | 1920 | 960 | 400
+ 2/2015 | 1600 | 1440 | 960 | 400
+ 3/2015 | 640 | 960 | 640 | 400
+ 4/2015 | 320 | 480 | 640 | 400
+
+This might be represented in JavaScript as an array of objects:
+
+```js
+const data = [
+ {month: new Date(2015, 0, 1), apples: 3840, bananas: 1920, cherries: 960, durians: 400},
+ {month: new Date(2015, 1, 1), apples: 1600, bananas: 1440, cherries: 960, durians: 400},
+ {month: new Date(2015, 2, 1), apples: 640, bananas: 960, cherries: 640, durians: 400},
+ {month: new Date(2015, 3, 1), apples: 320, bananas: 480, cherries: 640, durians: 400}
+];
+```
+
+To produce a stack for this data:
+
+```js
+const stack = d3.stack()
+ .keys(["apples", "bananas", "cherries", "durians"])
+ .order(d3.stackOrderNone)
+ .offset(d3.stackOffsetNone);
+
+const series = stack(data);
+```
+
+The resulting array has one element per *series*. Each series has one point per month, and each point has a lower and upper value defining the baseline and topline:
+
+```js
+[
+ [[ 0, 3840], [ 0, 1600], [ 0, 640], [ 0, 320]], // apples
+ [[3840, 5760], [1600, 3040], [ 640, 1600], [ 320, 800]], // bananas
+ [[5760, 6720], [3040, 4000], [1600, 2240], [ 800, 1440]], // cherries
+ [[6720, 7120], [4000, 4400], [2240, 2640], [1440, 1840]], // durians
+]
+```
+
+Each series in then typically passed to an [area generator](#areas) to render an area chart, or used to construct rectangles for a bar chart.
+
+# stack.keys([keys]) · [Source](https://github.com/d3/d3-shape/blob/main/src/stack.js)
+
+If *keys* is specified, sets the keys accessor to the specified function or array and returns this stack generator. If *keys* is not specified, returns the current keys accessor, which defaults to the empty array. A series (layer) is [generated](#_stack) for each key. Keys are typically strings, but they may be arbitrary values. The series’ key is passed to the [value accessor](#stack_value), along with each data point, to compute the point’s value.
+
+# stack.value([value]) · [Source](https://github.com/d3/d3-shape/blob/main/src/stack.js)
+
+If *value* is specified, sets the value accessor to the specified function or number and returns this stack generator. If *value* is not specified, returns the current value accessor, which defaults to:
+
+```js
+function value(d, key) {
+ return d[key];
+}
+```
+
+Thus, by default the stack generator assumes that the input data is an array of objects, with each object exposing named properties with numeric values; see [*stack*](#_stack) for an example.
+
+# stack.order([order]) · [Source](https://github.com/d3/d3-shape/blob/main/src/stack.js)
+
+If *order* is specified, sets the order accessor to the specified function or array and returns this stack generator. If *order* is not specified, returns the current order accessor, which defaults to [stackOrderNone](#stackOrderNone); this uses the order given by the [key accessor](#stack_key). See [stack orders](#stack-orders) for the built-in orders.
+
+If *order* is a function, it is passed the generated series array and must return an array of numeric indexes representing the stack order. For example, the default order is defined as:
+
+```js
+function orderNone(series) {
+ let n = series.length;
+ const o = new Array(n);
+ while (--n >= 0) o[n] = n;
+ return o;
+}
+```
+
+The stack order is computed prior to the [offset](#stack_offset); thus, the lower value for all points is zero at the time the order is computed. The index attribute for each series is also not set until after the order is computed.
+
+# stack.offset([offset]) · [Source](https://github.com/d3/d3-shape/blob/main/src/stack.js)
+
+If *offset* is specified, sets the offset accessor to the specified function and returns this stack generator. If *offset* is not specified, returns the current offset acccesor, which defaults to [stackOffsetNone](#stackOffsetNone); this uses a zero baseline. See [stack offsets](#stack-offsets) for the built-in offsets.
+
+The offset function is passed the generated series array and the order index array; it is then responsible for updating the lower and upper values in the series array. For example, the default offset is defined as:
+
+```js
+function offsetNone(series, order) {
+ if (!((n = series.length) > 1)) return;
+ for (let i = 1, s0, s1 = series[order[0]], n, m = s1.length; i < n; ++i) {
+ s0 = s1, s1 = series[order[i]];
+ for (let j = 0; j < m; ++j) {
+ s1[j][1] += s1[j][0] = s0[j][1];
+ }
+ }
+}
+```
+
+### Stack Orders
+
+Stack orders are typically not used directly, but are instead passed to [*stack*.order](#stack_order).
+
+# d3.stackOrderAppearance(series) · [Source](https://github.com/d3/d3-shape/blob/main/src/order/appearance.js)
+
+Returns a series order such that the earliest series (according to the maximum value) is at the bottom.
+
+# d3.stackOrderAscending(series) · [Source](https://github.com/d3/d3-shape/blob/main/src/order/ascending.js)
+
+Returns a series order such that the smallest series (according to the sum of values) is at the bottom.
+
+# d3.stackOrderDescending(series) · [Source](https://github.com/d3/d3-shape/blob/main/src/order/descending.js)
+
+Returns a series order such that the largest series (according to the sum of values) is at the bottom.
+
+# d3.stackOrderInsideOut(series) · [Source](https://github.com/d3/d3-shape/blob/main/src/order/insideOut.js)
+
+Returns a series order such that the earliest series (according to the maximum value) are on the inside and the later series are on the outside. This order is recommended for streamgraphs in conjunction with the [wiggle offset](#stackOffsetWiggle). See [Stacked Graphs—Geometry & Aesthetics](http://leebyron.com/streamgraph/) by Byron & Wattenberg for more information.
+
+# d3.stackOrderNone(series) · [Source](https://github.com/d3/d3-shape/blob/main/src/order/none.js)
+
+Returns the given series order [0, 1, … *n* - 1] where *n* is the number of elements in *series*. Thus, the stack order is given by the [key accessor](#stack_keys).
+
+# d3.stackOrderReverse(series) · [Source](https://github.com/d3/d3-shape/blob/main/src/order/reverse.js)
+
+Returns the reverse of the given series order [*n* - 1, *n* - 2, … 0] where *n* is the number of elements in *series*. Thus, the stack order is given by the reverse of the [key accessor](#stack_keys).
+
+### Stack Offsets
+
+Stack offsets are typically not used directly, but are instead passed to [*stack*.offset](#stack_offset).
+
+# d3.stackOffsetExpand(series, order) · [Source](https://github.com/d3/d3-shape/blob/main/src/offset/expand.js)
+
+Applies a zero baseline and normalizes the values for each point such that the topline is always one.
+
+# d3.stackOffsetDiverging(series, order) · [Source](https://github.com/d3/d3-shape/blob/main/src/offset/diverging.js)
+
+Positive values are stacked above zero, negative values are [stacked below zero](https://observablehq.com/@d3/diverging-stacked-bar-chart), and zero values are stacked at zero.
+
+# d3.stackOffsetNone(series, order) · [Source](https://github.com/d3/d3-shape/blob/main/src/offset/none.js)
+
+Applies a zero baseline.
+
+# d3.stackOffsetSilhouette(series, order) · [Source](https://github.com/d3/d3-shape/blob/main/src/offset/silhouette.js)
+
+Shifts the baseline down such that the center of the streamgraph is always at zero.
+
+# d3.stackOffsetWiggle(series, order) · [Source](https://github.com/d3/d3-shape/blob/main/src/offset/wiggle.js)
+
+Shifts the baseline so as to minimize the weighted wiggle of layers. This offset is recommended for streamgraphs in conjunction with the [inside-out order](#stackOrderInsideOut). See [Stacked Graphs—Geometry & Aesthetics](http://leebyron.com/streamgraph/) by Bryon & Wattenberg for more information.
diff --git a/node_modules/d3-shape/dist/d3-shape.js b/node_modules/d3-shape/dist/d3-shape.js
new file mode 100644
index 0000000000000000000000000000000000000000..62e76d08f1c3bf006d787bccc9ddd1956ad73080
--- /dev/null
+++ b/node_modules/d3-shape/dist/d3-shape.js
@@ -0,0 +1,2141 @@
+// https://d3js.org/d3-shape/ v3.2.0 Copyright 2010-2022 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-path')) :
+typeof define === 'function' && define.amd ? define(['exports', 'd3-path'], factory) :
+(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.d3 = global.d3 || {}, global.d3));
+})(this, (function (exports, d3Path) { 'use strict';
+
+function constant(x) {
+ return function constant() {
+ return x;
+ };
+}
+
+const abs = Math.abs;
+const atan2 = Math.atan2;
+const cos = Math.cos;
+const max = Math.max;
+const min = Math.min;
+const sin = Math.sin;
+const sqrt = Math.sqrt;
+
+const epsilon = 1e-12;
+const pi = Math.PI;
+const halfPi = pi / 2;
+const tau = 2 * pi;
+
+function acos(x) {
+ return x > 1 ? 0 : x < -1 ? pi : Math.acos(x);
+}
+
+function asin(x) {
+ return x >= 1 ? halfPi : x <= -1 ? -halfPi : Math.asin(x);
+}
+
+function withPath(shape) {
+ let digits = 3;
+
+ shape.digits = function(_) {
+ if (!arguments.length) return digits;
+ if (_ == null) {
+ digits = null;
+ } else {
+ const d = Math.floor(_);
+ if (!(d >= 0)) throw new RangeError(`invalid digits: ${_}`);
+ digits = d;
+ }
+ return shape;
+ };
+
+ return () => new d3Path.Path(digits);
+}
+
+function arcInnerRadius(d) {
+ return d.innerRadius;
+}
+
+function arcOuterRadius(d) {
+ return d.outerRadius;
+}
+
+function arcStartAngle(d) {
+ return d.startAngle;
+}
+
+function arcEndAngle(d) {
+ return d.endAngle;
+}
+
+function arcPadAngle(d) {
+ return d && d.padAngle; // Note: optional!
+}
+
+function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
+ var x10 = x1 - x0, y10 = y1 - y0,
+ x32 = x3 - x2, y32 = y3 - y2,
+ t = y32 * x10 - x32 * y10;
+ if (t * t < epsilon) return;
+ t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / t;
+ return [x0 + t * x10, y0 + t * y10];
+}
+
+// Compute perpendicular offset line of length rc.
+// http://mathworld.wolfram.com/Circle-LineIntersection.html
+function cornerTangents(x0, y0, x1, y1, r1, rc, cw) {
+ var x01 = x0 - x1,
+ y01 = y0 - y1,
+ lo = (cw ? rc : -rc) / sqrt(x01 * x01 + y01 * y01),
+ ox = lo * y01,
+ oy = -lo * x01,
+ x11 = x0 + ox,
+ y11 = y0 + oy,
+ x10 = x1 + ox,
+ y10 = y1 + oy,
+ x00 = (x11 + x10) / 2,
+ y00 = (y11 + y10) / 2,
+ dx = x10 - x11,
+ dy = y10 - y11,
+ d2 = dx * dx + dy * dy,
+ r = r1 - rc,
+ D = x11 * y10 - x10 * y11,
+ d = (dy < 0 ? -1 : 1) * sqrt(max(0, r * r * d2 - D * D)),
+ cx0 = (D * dy - dx * d) / d2,
+ cy0 = (-D * dx - dy * d) / d2,
+ cx1 = (D * dy + dx * d) / d2,
+ cy1 = (-D * dx + dy * d) / d2,
+ dx0 = cx0 - x00,
+ dy0 = cy0 - y00,
+ dx1 = cx1 - x00,
+ dy1 = cy1 - y00;
+
+ // Pick the closer of the two intersection points.
+ // TODO Is there a faster way to determine which intersection to use?
+ if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;
+
+ return {
+ cx: cx0,
+ cy: cy0,
+ x01: -ox,
+ y01: -oy,
+ x11: cx0 * (r1 / r - 1),
+ y11: cy0 * (r1 / r - 1)
+ };
+}
+
+function arc() {
+ var innerRadius = arcInnerRadius,
+ outerRadius = arcOuterRadius,
+ cornerRadius = constant(0),
+ padRadius = null,
+ startAngle = arcStartAngle,
+ endAngle = arcEndAngle,
+ padAngle = arcPadAngle,
+ context = null,
+ path = withPath(arc);
+
+ function arc() {
+ var buffer,
+ r,
+ r0 = +innerRadius.apply(this, arguments),
+ r1 = +outerRadius.apply(this, arguments),
+ a0 = startAngle.apply(this, arguments) - halfPi,
+ a1 = endAngle.apply(this, arguments) - halfPi,
+ da = abs(a1 - a0),
+ cw = a1 > a0;
+
+ if (!context) context = buffer = path();
+
+ // Ensure that the outer radius is always larger than the inner radius.
+ if (r1 < r0) r = r1, r1 = r0, r0 = r;
+
+ // Is it a point?
+ if (!(r1 > epsilon)) context.moveTo(0, 0);
+
+ // Or is it a circle or annulus?
+ else if (da > tau - epsilon) {
+ context.moveTo(r1 * cos(a0), r1 * sin(a0));
+ context.arc(0, 0, r1, a0, a1, !cw);
+ if (r0 > epsilon) {
+ context.moveTo(r0 * cos(a1), r0 * sin(a1));
+ context.arc(0, 0, r0, a1, a0, cw);
+ }
+ }
+
+ // Or is it a circular or annular sector?
+ else {
+ var a01 = a0,
+ a11 = a1,
+ a00 = a0,
+ a10 = a1,
+ da0 = da,
+ da1 = da,
+ ap = padAngle.apply(this, arguments) / 2,
+ rp = (ap > epsilon) && (padRadius ? +padRadius.apply(this, arguments) : sqrt(r0 * r0 + r1 * r1)),
+ rc = min(abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),
+ rc0 = rc,
+ rc1 = rc,
+ t0,
+ t1;
+
+ // Apply padding? Note that since r1 ≥ r0, da1 ≥ da0.
+ if (rp > epsilon) {
+ var p0 = asin(rp / r0 * sin(ap)),
+ p1 = asin(rp / r1 * sin(ap));
+ if ((da0 -= p0 * 2) > epsilon) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0;
+ else da0 = 0, a00 = a10 = (a0 + a1) / 2;
+ if ((da1 -= p1 * 2) > epsilon) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1;
+ else da1 = 0, a01 = a11 = (a0 + a1) / 2;
+ }
+
+ var x01 = r1 * cos(a01),
+ y01 = r1 * sin(a01),
+ x10 = r0 * cos(a10),
+ y10 = r0 * sin(a10);
+
+ // Apply rounded corners?
+ if (rc > epsilon) {
+ var x11 = r1 * cos(a11),
+ y11 = r1 * sin(a11),
+ x00 = r0 * cos(a00),
+ y00 = r0 * sin(a00),
+ oc;
+
+ // Restrict the corner radius according to the sector angle. If this
+ // intersection fails, it’s probably because the arc is too small, so
+ // disable the corner radius entirely.
+ if (da < pi) {
+ if (oc = intersect(x01, y01, x00, y00, x11, y11, x10, y10)) {
+ var ax = x01 - oc[0],
+ ay = y01 - oc[1],
+ bx = x11 - oc[0],
+ by = y11 - oc[1],
+ kc = 1 / sin(acos((ax * bx + ay * by) / (sqrt(ax * ax + ay * ay) * sqrt(bx * bx + by * by))) / 2),
+ lc = sqrt(oc[0] * oc[0] + oc[1] * oc[1]);
+ rc0 = min(rc, (r0 - lc) / (kc - 1));
+ rc1 = min(rc, (r1 - lc) / (kc + 1));
+ } else {
+ rc0 = rc1 = 0;
+ }
+ }
+ }
+
+ // Is the sector collapsed to a line?
+ if (!(da1 > epsilon)) context.moveTo(x01, y01);
+
+ // Does the sector’s outer ring have rounded corners?
+ else if (rc1 > epsilon) {
+ t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);
+ t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);
+
+ context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);
+
+ // Have the corners merged?
+ if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);
+
+ // Otherwise, draw the two corners and the ring.
+ else {
+ context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);
+ context.arc(0, 0, r1, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), !cw);
+ context.arc(t1.cx, t1.cy, rc1, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);
+ }
+ }
+
+ // Or is the outer ring just a circular arc?
+ else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw);
+
+ // Is there no inner ring, and it’s a circular sector?
+ // Or perhaps it’s an annular sector collapsed due to padding?
+ if (!(r0 > epsilon) || !(da0 > epsilon)) context.lineTo(x10, y10);
+
+ // Does the sector’s inner ring (or point) have rounded corners?
+ else if (rc0 > epsilon) {
+ t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);
+ t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);
+
+ context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);
+
+ // Have the corners merged?
+ if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);
+
+ // Otherwise, draw the two corners and the ring.
+ else {
+ context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);
+ context.arc(0, 0, r0, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), cw);
+ context.arc(t1.cx, t1.cy, rc0, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);
+ }
+ }
+
+ // Or is the inner ring just a circular arc?
+ else context.arc(0, 0, r0, a10, a00, cw);
+ }
+
+ context.closePath();
+
+ if (buffer) return context = null, buffer + "" || null;
+ }
+
+ arc.centroid = function() {
+ var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2,
+ a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi / 2;
+ return [cos(a) * r, sin(a) * r];
+ };
+
+ arc.innerRadius = function(_) {
+ return arguments.length ? (innerRadius = typeof _ === "function" ? _ : constant(+_), arc) : innerRadius;
+ };
+
+ arc.outerRadius = function(_) {
+ return arguments.length ? (outerRadius = typeof _ === "function" ? _ : constant(+_), arc) : outerRadius;
+ };
+
+ arc.cornerRadius = function(_) {
+ return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant(+_), arc) : cornerRadius;
+ };
+
+ arc.padRadius = function(_) {
+ return arguments.length ? (padRadius = _ == null ? null : typeof _ === "function" ? _ : constant(+_), arc) : padRadius;
+ };
+
+ arc.startAngle = function(_) {
+ return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant(+_), arc) : startAngle;
+ };
+
+ arc.endAngle = function(_) {
+ return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant(+_), arc) : endAngle;
+ };
+
+ arc.padAngle = function(_) {
+ return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant(+_), arc) : padAngle;
+ };
+
+ arc.context = function(_) {
+ return arguments.length ? ((context = _ == null ? null : _), arc) : context;
+ };
+
+ return arc;
+}
+
+var slice = Array.prototype.slice;
+
+function array(x) {
+ return typeof x === "object" && "length" in x
+ ? x // Array, TypedArray, NodeList, array-like
+ : Array.from(x); // Map, Set, iterable, string, or anything else
+}
+
+function Linear(context) {
+ this._context = context;
+}
+
+Linear.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._point = 0;
+ },
+ lineEnd: function() {
+ if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
+ this._line = 1 - this._line;
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+ switch (this._point) {
+ case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
+ case 1: this._point = 2; // falls through
+ default: this._context.lineTo(x, y); break;
+ }
+ }
+};
+
+function curveLinear(context) {
+ return new Linear(context);
+}
+
+function x(p) {
+ return p[0];
+}
+
+function y(p) {
+ return p[1];
+}
+
+function line(x$1, y$1) {
+ var defined = constant(true),
+ context = null,
+ curve = curveLinear,
+ output = null,
+ path = withPath(line);
+
+ x$1 = typeof x$1 === "function" ? x$1 : (x$1 === undefined) ? x : constant(x$1);
+ y$1 = typeof y$1 === "function" ? y$1 : (y$1 === undefined) ? y : constant(y$1);
+
+ function line(data) {
+ var i,
+ n = (data = array(data)).length,
+ d,
+ defined0 = false,
+ buffer;
+
+ if (context == null) output = curve(buffer = path());
+
+ for (i = 0; i <= n; ++i) {
+ if (!(i < n && defined(d = data[i], i, data)) === defined0) {
+ if (defined0 = !defined0) output.lineStart();
+ else output.lineEnd();
+ }
+ if (defined0) output.point(+x$1(d, i, data), +y$1(d, i, data));
+ }
+
+ if (buffer) return output = null, buffer + "" || null;
+ }
+
+ line.x = function(_) {
+ return arguments.length ? (x$1 = typeof _ === "function" ? _ : constant(+_), line) : x$1;
+ };
+
+ line.y = function(_) {
+ return arguments.length ? (y$1 = typeof _ === "function" ? _ : constant(+_), line) : y$1;
+ };
+
+ line.defined = function(_) {
+ return arguments.length ? (defined = typeof _ === "function" ? _ : constant(!!_), line) : defined;
+ };
+
+ line.curve = function(_) {
+ return arguments.length ? (curve = _, context != null && (output = curve(context)), line) : curve;
+ };
+
+ line.context = function(_) {
+ return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), line) : context;
+ };
+
+ return line;
+}
+
+function area(x0, y0, y1) {
+ var x1 = null,
+ defined = constant(true),
+ context = null,
+ curve = curveLinear,
+ output = null,
+ path = withPath(area);
+
+ x0 = typeof x0 === "function" ? x0 : (x0 === undefined) ? x : constant(+x0);
+ y0 = typeof y0 === "function" ? y0 : (y0 === undefined) ? constant(0) : constant(+y0);
+ y1 = typeof y1 === "function" ? y1 : (y1 === undefined) ? y : constant(+y1);
+
+ function area(data) {
+ var i,
+ j,
+ k,
+ n = (data = array(data)).length,
+ d,
+ defined0 = false,
+ buffer,
+ x0z = new Array(n),
+ y0z = new Array(n);
+
+ if (context == null) output = curve(buffer = path());
+
+ for (i = 0; i <= n; ++i) {
+ if (!(i < n && defined(d = data[i], i, data)) === defined0) {
+ if (defined0 = !defined0) {
+ j = i;
+ output.areaStart();
+ output.lineStart();
+ } else {
+ output.lineEnd();
+ output.lineStart();
+ for (k = i - 1; k >= j; --k) {
+ output.point(x0z[k], y0z[k]);
+ }
+ output.lineEnd();
+ output.areaEnd();
+ }
+ }
+ if (defined0) {
+ x0z[i] = +x0(d, i, data), y0z[i] = +y0(d, i, data);
+ output.point(x1 ? +x1(d, i, data) : x0z[i], y1 ? +y1(d, i, data) : y0z[i]);
+ }
+ }
+
+ if (buffer) return output = null, buffer + "" || null;
+ }
+
+ function arealine() {
+ return line().defined(defined).curve(curve).context(context);
+ }
+
+ area.x = function(_) {
+ return arguments.length ? (x0 = typeof _ === "function" ? _ : constant(+_), x1 = null, area) : x0;
+ };
+
+ area.x0 = function(_) {
+ return arguments.length ? (x0 = typeof _ === "function" ? _ : constant(+_), area) : x0;
+ };
+
+ area.x1 = function(_) {
+ return arguments.length ? (x1 = _ == null ? null : typeof _ === "function" ? _ : constant(+_), area) : x1;
+ };
+
+ area.y = function(_) {
+ return arguments.length ? (y0 = typeof _ === "function" ? _ : constant(+_), y1 = null, area) : y0;
+ };
+
+ area.y0 = function(_) {
+ return arguments.length ? (y0 = typeof _ === "function" ? _ : constant(+_), area) : y0;
+ };
+
+ area.y1 = function(_) {
+ return arguments.length ? (y1 = _ == null ? null : typeof _ === "function" ? _ : constant(+_), area) : y1;
+ };
+
+ area.lineX0 =
+ area.lineY0 = function() {
+ return arealine().x(x0).y(y0);
+ };
+
+ area.lineY1 = function() {
+ return arealine().x(x0).y(y1);
+ };
+
+ area.lineX1 = function() {
+ return arealine().x(x1).y(y0);
+ };
+
+ area.defined = function(_) {
+ return arguments.length ? (defined = typeof _ === "function" ? _ : constant(!!_), area) : defined;
+ };
+
+ area.curve = function(_) {
+ return arguments.length ? (curve = _, context != null && (output = curve(context)), area) : curve;
+ };
+
+ area.context = function(_) {
+ return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), area) : context;
+ };
+
+ return area;
+}
+
+function descending$1(a, b) {
+ return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
+}
+
+function identity(d) {
+ return d;
+}
+
+function pie() {
+ var value = identity,
+ sortValues = descending$1,
+ sort = null,
+ startAngle = constant(0),
+ endAngle = constant(tau),
+ padAngle = constant(0);
+
+ function pie(data) {
+ var i,
+ n = (data = array(data)).length,
+ j,
+ k,
+ sum = 0,
+ index = new Array(n),
+ arcs = new Array(n),
+ a0 = +startAngle.apply(this, arguments),
+ da = Math.min(tau, Math.max(-tau, endAngle.apply(this, arguments) - a0)),
+ a1,
+ p = Math.min(Math.abs(da) / n, padAngle.apply(this, arguments)),
+ pa = p * (da < 0 ? -1 : 1),
+ v;
+
+ for (i = 0; i < n; ++i) {
+ if ((v = arcs[index[i] = i] = +value(data[i], i, data)) > 0) {
+ sum += v;
+ }
+ }
+
+ // Optionally sort the arcs by previously-computed values or by data.
+ if (sortValues != null) index.sort(function(i, j) { return sortValues(arcs[i], arcs[j]); });
+ else if (sort != null) index.sort(function(i, j) { return sort(data[i], data[j]); });
+
+ // Compute the arcs! They are stored in the original data's order.
+ for (i = 0, k = sum ? (da - n * pa) / sum : 0; i < n; ++i, a0 = a1) {
+ j = index[i], v = arcs[j], a1 = a0 + (v > 0 ? v * k : 0) + pa, arcs[j] = {
+ data: data[j],
+ index: i,
+ value: v,
+ startAngle: a0,
+ endAngle: a1,
+ padAngle: p
+ };
+ }
+
+ return arcs;
+ }
+
+ pie.value = function(_) {
+ return arguments.length ? (value = typeof _ === "function" ? _ : constant(+_), pie) : value;
+ };
+
+ pie.sortValues = function(_) {
+ return arguments.length ? (sortValues = _, sort = null, pie) : sortValues;
+ };
+
+ pie.sort = function(_) {
+ return arguments.length ? (sort = _, sortValues = null, pie) : sort;
+ };
+
+ pie.startAngle = function(_) {
+ return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant(+_), pie) : startAngle;
+ };
+
+ pie.endAngle = function(_) {
+ return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant(+_), pie) : endAngle;
+ };
+
+ pie.padAngle = function(_) {
+ return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant(+_), pie) : padAngle;
+ };
+
+ return pie;
+}
+
+var curveRadialLinear = curveRadial(curveLinear);
+
+function Radial(curve) {
+ this._curve = curve;
+}
+
+Radial.prototype = {
+ areaStart: function() {
+ this._curve.areaStart();
+ },
+ areaEnd: function() {
+ this._curve.areaEnd();
+ },
+ lineStart: function() {
+ this._curve.lineStart();
+ },
+ lineEnd: function() {
+ this._curve.lineEnd();
+ },
+ point: function(a, r) {
+ this._curve.point(r * Math.sin(a), r * -Math.cos(a));
+ }
+};
+
+function curveRadial(curve) {
+
+ function radial(context) {
+ return new Radial(curve(context));
+ }
+
+ radial._curve = curve;
+
+ return radial;
+}
+
+function lineRadial(l) {
+ var c = l.curve;
+
+ l.angle = l.x, delete l.x;
+ l.radius = l.y, delete l.y;
+
+ l.curve = function(_) {
+ return arguments.length ? c(curveRadial(_)) : c()._curve;
+ };
+
+ return l;
+}
+
+function lineRadial$1() {
+ return lineRadial(line().curve(curveRadialLinear));
+}
+
+function areaRadial() {
+ var a = area().curve(curveRadialLinear),
+ c = a.curve,
+ x0 = a.lineX0,
+ x1 = a.lineX1,
+ y0 = a.lineY0,
+ y1 = a.lineY1;
+
+ a.angle = a.x, delete a.x;
+ a.startAngle = a.x0, delete a.x0;
+ a.endAngle = a.x1, delete a.x1;
+ a.radius = a.y, delete a.y;
+ a.innerRadius = a.y0, delete a.y0;
+ a.outerRadius = a.y1, delete a.y1;
+ a.lineStartAngle = function() { return lineRadial(x0()); }, delete a.lineX0;
+ a.lineEndAngle = function() { return lineRadial(x1()); }, delete a.lineX1;
+ a.lineInnerRadius = function() { return lineRadial(y0()); }, delete a.lineY0;
+ a.lineOuterRadius = function() { return lineRadial(y1()); }, delete a.lineY1;
+
+ a.curve = function(_) {
+ return arguments.length ? c(curveRadial(_)) : c()._curve;
+ };
+
+ return a;
+}
+
+function pointRadial(x, y) {
+ return [(y = +y) * Math.cos(x -= Math.PI / 2), y * Math.sin(x)];
+}
+
+class Bump {
+ constructor(context, x) {
+ this._context = context;
+ this._x = x;
+ }
+ areaStart() {
+ this._line = 0;
+ }
+ areaEnd() {
+ this._line = NaN;
+ }
+ lineStart() {
+ this._point = 0;
+ }
+ lineEnd() {
+ if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
+ this._line = 1 - this._line;
+ }
+ point(x, y) {
+ x = +x, y = +y;
+ switch (this._point) {
+ case 0: {
+ this._point = 1;
+ if (this._line) this._context.lineTo(x, y);
+ else this._context.moveTo(x, y);
+ break;
+ }
+ case 1: this._point = 2; // falls through
+ default: {
+ if (this._x) this._context.bezierCurveTo(this._x0 = (this._x0 + x) / 2, this._y0, this._x0, y, x, y);
+ else this._context.bezierCurveTo(this._x0, this._y0 = (this._y0 + y) / 2, x, this._y0, x, y);
+ break;
+ }
+ }
+ this._x0 = x, this._y0 = y;
+ }
+}
+
+class BumpRadial {
+ constructor(context) {
+ this._context = context;
+ }
+ lineStart() {
+ this._point = 0;
+ }
+ lineEnd() {}
+ point(x, y) {
+ x = +x, y = +y;
+ if (this._point === 0) {
+ this._point = 1;
+ } else {
+ const p0 = pointRadial(this._x0, this._y0);
+ const p1 = pointRadial(this._x0, this._y0 = (this._y0 + y) / 2);
+ const p2 = pointRadial(x, this._y0);
+ const p3 = pointRadial(x, y);
+ this._context.moveTo(...p0);
+ this._context.bezierCurveTo(...p1, ...p2, ...p3);
+ }
+ this._x0 = x, this._y0 = y;
+ }
+}
+
+function bumpX(context) {
+ return new Bump(context, true);
+}
+
+function bumpY(context) {
+ return new Bump(context, false);
+}
+
+function bumpRadial(context) {
+ return new BumpRadial(context);
+}
+
+function linkSource(d) {
+ return d.source;
+}
+
+function linkTarget(d) {
+ return d.target;
+}
+
+function link(curve) {
+ let source = linkSource,
+ target = linkTarget,
+ x$1 = x,
+ y$1 = y,
+ context = null,
+ output = null,
+ path = withPath(link);
+
+ function link() {
+ let buffer;
+ const argv = slice.call(arguments);
+ const s = source.apply(this, argv);
+ const t = target.apply(this, argv);
+ if (context == null) output = curve(buffer = path());
+ output.lineStart();
+ argv[0] = s, output.point(+x$1.apply(this, argv), +y$1.apply(this, argv));
+ argv[0] = t, output.point(+x$1.apply(this, argv), +y$1.apply(this, argv));
+ output.lineEnd();
+ if (buffer) return output = null, buffer + "" || null;
+ }
+
+ link.source = function(_) {
+ return arguments.length ? (source = _, link) : source;
+ };
+
+ link.target = function(_) {
+ return arguments.length ? (target = _, link) : target;
+ };
+
+ link.x = function(_) {
+ return arguments.length ? (x$1 = typeof _ === "function" ? _ : constant(+_), link) : x$1;
+ };
+
+ link.y = function(_) {
+ return arguments.length ? (y$1 = typeof _ === "function" ? _ : constant(+_), link) : y$1;
+ };
+
+ link.context = function(_) {
+ return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), link) : context;
+ };
+
+ return link;
+}
+
+function linkHorizontal() {
+ return link(bumpX);
+}
+
+function linkVertical() {
+ return link(bumpY);
+}
+
+function linkRadial() {
+ const l = link(bumpRadial);
+ l.angle = l.x, delete l.x;
+ l.radius = l.y, delete l.y;
+ return l;
+}
+
+const sqrt3$2 = sqrt(3);
+
+var asterisk = {
+ draw(context, size) {
+ const r = sqrt(size + min(size / 28, 0.75)) * 0.59436;
+ const t = r / 2;
+ const u = t * sqrt3$2;
+ context.moveTo(0, r);
+ context.lineTo(0, -r);
+ context.moveTo(-u, -t);
+ context.lineTo(u, t);
+ context.moveTo(-u, t);
+ context.lineTo(u, -t);
+ }
+};
+
+var circle = {
+ draw(context, size) {
+ const r = sqrt(size / pi);
+ context.moveTo(r, 0);
+ context.arc(0, 0, r, 0, tau);
+ }
+};
+
+var cross = {
+ draw(context, size) {
+ const r = sqrt(size / 5) / 2;
+ context.moveTo(-3 * r, -r);
+ context.lineTo(-r, -r);
+ context.lineTo(-r, -3 * r);
+ context.lineTo(r, -3 * r);
+ context.lineTo(r, -r);
+ context.lineTo(3 * r, -r);
+ context.lineTo(3 * r, r);
+ context.lineTo(r, r);
+ context.lineTo(r, 3 * r);
+ context.lineTo(-r, 3 * r);
+ context.lineTo(-r, r);
+ context.lineTo(-3 * r, r);
+ context.closePath();
+ }
+};
+
+const tan30 = sqrt(1 / 3);
+const tan30_2 = tan30 * 2;
+
+var diamond = {
+ draw(context, size) {
+ const y = sqrt(size / tan30_2);
+ const x = y * tan30;
+ context.moveTo(0, -y);
+ context.lineTo(x, 0);
+ context.lineTo(0, y);
+ context.lineTo(-x, 0);
+ context.closePath();
+ }
+};
+
+var diamond2 = {
+ draw(context, size) {
+ const r = sqrt(size) * 0.62625;
+ context.moveTo(0, -r);
+ context.lineTo(r, 0);
+ context.lineTo(0, r);
+ context.lineTo(-r, 0);
+ context.closePath();
+ }
+};
+
+var plus = {
+ draw(context, size) {
+ const r = sqrt(size - min(size / 7, 2)) * 0.87559;
+ context.moveTo(-r, 0);
+ context.lineTo(r, 0);
+ context.moveTo(0, r);
+ context.lineTo(0, -r);
+ }
+};
+
+var square = {
+ draw(context, size) {
+ const w = sqrt(size);
+ const x = -w / 2;
+ context.rect(x, x, w, w);
+ }
+};
+
+var square2 = {
+ draw(context, size) {
+ const r = sqrt(size) * 0.4431;
+ context.moveTo(r, r);
+ context.lineTo(r, -r);
+ context.lineTo(-r, -r);
+ context.lineTo(-r, r);
+ context.closePath();
+ }
+};
+
+const ka = 0.89081309152928522810;
+const kr = sin(pi / 10) / sin(7 * pi / 10);
+const kx = sin(tau / 10) * kr;
+const ky = -cos(tau / 10) * kr;
+
+var star = {
+ draw(context, size) {
+ const r = sqrt(size * ka);
+ const x = kx * r;
+ const y = ky * r;
+ context.moveTo(0, -r);
+ context.lineTo(x, y);
+ for (let i = 1; i < 5; ++i) {
+ const a = tau * i / 5;
+ const c = cos(a);
+ const s = sin(a);
+ context.lineTo(s * r, -c * r);
+ context.lineTo(c * x - s * y, s * x + c * y);
+ }
+ context.closePath();
+ }
+};
+
+const sqrt3$1 = sqrt(3);
+
+var triangle = {
+ draw(context, size) {
+ const y = -sqrt(size / (sqrt3$1 * 3));
+ context.moveTo(0, y * 2);
+ context.lineTo(-sqrt3$1 * y, -y);
+ context.lineTo(sqrt3$1 * y, -y);
+ context.closePath();
+ }
+};
+
+const sqrt3 = sqrt(3);
+
+var triangle2 = {
+ draw(context, size) {
+ const s = sqrt(size) * 0.6824;
+ const t = s / 2;
+ const u = (s * sqrt3) / 2; // cos(Math.PI / 6)
+ context.moveTo(0, -s);
+ context.lineTo(u, t);
+ context.lineTo(-u, t);
+ context.closePath();
+ }
+};
+
+const c = -0.5;
+const s = sqrt(3) / 2;
+const k = 1 / sqrt(12);
+const a = (k / 2 + 1) * 3;
+
+var wye = {
+ draw(context, size) {
+ const r = sqrt(size / a);
+ const x0 = r / 2, y0 = r * k;
+ const x1 = x0, y1 = r * k + r;
+ const x2 = -x1, y2 = y1;
+ context.moveTo(x0, y0);
+ context.lineTo(x1, y1);
+ context.lineTo(x2, y2);
+ context.lineTo(c * x0 - s * y0, s * x0 + c * y0);
+ context.lineTo(c * x1 - s * y1, s * x1 + c * y1);
+ context.lineTo(c * x2 - s * y2, s * x2 + c * y2);
+ context.lineTo(c * x0 + s * y0, c * y0 - s * x0);
+ context.lineTo(c * x1 + s * y1, c * y1 - s * x1);
+ context.lineTo(c * x2 + s * y2, c * y2 - s * x2);
+ context.closePath();
+ }
+};
+
+var times = {
+ draw(context, size) {
+ const r = sqrt(size - min(size / 6, 1.7)) * 0.6189;
+ context.moveTo(-r, -r);
+ context.lineTo(r, r);
+ context.moveTo(-r, r);
+ context.lineTo(r, -r);
+ }
+};
+
+// These symbols are designed to be filled.
+const symbolsFill = [
+ circle,
+ cross,
+ diamond,
+ square,
+ star,
+ triangle,
+ wye
+];
+
+// These symbols are designed to be stroked (with a width of 1.5px and round caps).
+const symbolsStroke = [
+ circle,
+ plus,
+ times,
+ triangle2,
+ asterisk,
+ square2,
+ diamond2
+];
+
+function Symbol(type, size) {
+ let context = null,
+ path = withPath(symbol);
+
+ type = typeof type === "function" ? type : constant(type || circle);
+ size = typeof size === "function" ? size : constant(size === undefined ? 64 : +size);
+
+ function symbol() {
+ let buffer;
+ if (!context) context = buffer = path();
+ type.apply(this, arguments).draw(context, +size.apply(this, arguments));
+ if (buffer) return context = null, buffer + "" || null;
+ }
+
+ symbol.type = function(_) {
+ return arguments.length ? (type = typeof _ === "function" ? _ : constant(_), symbol) : type;
+ };
+
+ symbol.size = function(_) {
+ return arguments.length ? (size = typeof _ === "function" ? _ : constant(+_), symbol) : size;
+ };
+
+ symbol.context = function(_) {
+ return arguments.length ? (context = _ == null ? null : _, symbol) : context;
+ };
+
+ return symbol;
+}
+
+function noop() {}
+
+function point$3(that, x, y) {
+ that._context.bezierCurveTo(
+ (2 * that._x0 + that._x1) / 3,
+ (2 * that._y0 + that._y1) / 3,
+ (that._x0 + 2 * that._x1) / 3,
+ (that._y0 + 2 * that._y1) / 3,
+ (that._x0 + 4 * that._x1 + x) / 6,
+ (that._y0 + 4 * that._y1 + y) / 6
+ );
+}
+
+function Basis(context) {
+ this._context = context;
+}
+
+Basis.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._x0 = this._x1 =
+ this._y0 = this._y1 = NaN;
+ this._point = 0;
+ },
+ lineEnd: function() {
+ switch (this._point) {
+ case 3: point$3(this, this._x1, this._y1); // falls through
+ case 2: this._context.lineTo(this._x1, this._y1); break;
+ }
+ if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
+ this._line = 1 - this._line;
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+ switch (this._point) {
+ case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
+ case 1: this._point = 2; break;
+ case 2: this._point = 3; this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6); // falls through
+ default: point$3(this, x, y); break;
+ }
+ this._x0 = this._x1, this._x1 = x;
+ this._y0 = this._y1, this._y1 = y;
+ }
+};
+
+function basis(context) {
+ return new Basis(context);
+}
+
+function BasisClosed(context) {
+ this._context = context;
+}
+
+BasisClosed.prototype = {
+ areaStart: noop,
+ areaEnd: noop,
+ lineStart: function() {
+ this._x0 = this._x1 = this._x2 = this._x3 = this._x4 =
+ this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = NaN;
+ this._point = 0;
+ },
+ lineEnd: function() {
+ switch (this._point) {
+ case 1: {
+ this._context.moveTo(this._x2, this._y2);
+ this._context.closePath();
+ break;
+ }
+ case 2: {
+ this._context.moveTo((this._x2 + 2 * this._x3) / 3, (this._y2 + 2 * this._y3) / 3);
+ this._context.lineTo((this._x3 + 2 * this._x2) / 3, (this._y3 + 2 * this._y2) / 3);
+ this._context.closePath();
+ break;
+ }
+ case 3: {
+ this.point(this._x2, this._y2);
+ this.point(this._x3, this._y3);
+ this.point(this._x4, this._y4);
+ break;
+ }
+ }
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+ switch (this._point) {
+ case 0: this._point = 1; this._x2 = x, this._y2 = y; break;
+ case 1: this._point = 2; this._x3 = x, this._y3 = y; break;
+ case 2: this._point = 3; this._x4 = x, this._y4 = y; this._context.moveTo((this._x0 + 4 * this._x1 + x) / 6, (this._y0 + 4 * this._y1 + y) / 6); break;
+ default: point$3(this, x, y); break;
+ }
+ this._x0 = this._x1, this._x1 = x;
+ this._y0 = this._y1, this._y1 = y;
+ }
+};
+
+function basisClosed(context) {
+ return new BasisClosed(context);
+}
+
+function BasisOpen(context) {
+ this._context = context;
+}
+
+BasisOpen.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._x0 = this._x1 =
+ this._y0 = this._y1 = NaN;
+ this._point = 0;
+ },
+ lineEnd: function() {
+ if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
+ this._line = 1 - this._line;
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+ switch (this._point) {
+ case 0: this._point = 1; break;
+ case 1: this._point = 2; break;
+ case 2: this._point = 3; var x0 = (this._x0 + 4 * this._x1 + x) / 6, y0 = (this._y0 + 4 * this._y1 + y) / 6; this._line ? this._context.lineTo(x0, y0) : this._context.moveTo(x0, y0); break;
+ case 3: this._point = 4; // falls through
+ default: point$3(this, x, y); break;
+ }
+ this._x0 = this._x1, this._x1 = x;
+ this._y0 = this._y1, this._y1 = y;
+ }
+};
+
+function basisOpen(context) {
+ return new BasisOpen(context);
+}
+
+function Bundle(context, beta) {
+ this._basis = new Basis(context);
+ this._beta = beta;
+}
+
+Bundle.prototype = {
+ lineStart: function() {
+ this._x = [];
+ this._y = [];
+ this._basis.lineStart();
+ },
+ lineEnd: function() {
+ var x = this._x,
+ y = this._y,
+ j = x.length - 1;
+
+ if (j > 0) {
+ var x0 = x[0],
+ y0 = y[0],
+ dx = x[j] - x0,
+ dy = y[j] - y0,
+ i = -1,
+ t;
+
+ while (++i <= j) {
+ t = i / j;
+ this._basis.point(
+ this._beta * x[i] + (1 - this._beta) * (x0 + t * dx),
+ this._beta * y[i] + (1 - this._beta) * (y0 + t * dy)
+ );
+ }
+ }
+
+ this._x = this._y = null;
+ this._basis.lineEnd();
+ },
+ point: function(x, y) {
+ this._x.push(+x);
+ this._y.push(+y);
+ }
+};
+
+var bundle = (function custom(beta) {
+
+ function bundle(context) {
+ return beta === 1 ? new Basis(context) : new Bundle(context, beta);
+ }
+
+ bundle.beta = function(beta) {
+ return custom(+beta);
+ };
+
+ return bundle;
+})(0.85);
+
+function point$2(that, x, y) {
+ that._context.bezierCurveTo(
+ that._x1 + that._k * (that._x2 - that._x0),
+ that._y1 + that._k * (that._y2 - that._y0),
+ that._x2 + that._k * (that._x1 - x),
+ that._y2 + that._k * (that._y1 - y),
+ that._x2,
+ that._y2
+ );
+}
+
+function Cardinal(context, tension) {
+ this._context = context;
+ this._k = (1 - tension) / 6;
+}
+
+Cardinal.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._x0 = this._x1 = this._x2 =
+ this._y0 = this._y1 = this._y2 = NaN;
+ this._point = 0;
+ },
+ lineEnd: function() {
+ switch (this._point) {
+ case 2: this._context.lineTo(this._x2, this._y2); break;
+ case 3: point$2(this, this._x1, this._y1); break;
+ }
+ if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
+ this._line = 1 - this._line;
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+ switch (this._point) {
+ case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
+ case 1: this._point = 2; this._x1 = x, this._y1 = y; break;
+ case 2: this._point = 3; // falls through
+ default: point$2(this, x, y); break;
+ }
+ this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
+ this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
+ }
+};
+
+var cardinal = (function custom(tension) {
+
+ function cardinal(context) {
+ return new Cardinal(context, tension);
+ }
+
+ cardinal.tension = function(tension) {
+ return custom(+tension);
+ };
+
+ return cardinal;
+})(0);
+
+function CardinalClosed(context, tension) {
+ this._context = context;
+ this._k = (1 - tension) / 6;
+}
+
+CardinalClosed.prototype = {
+ areaStart: noop,
+ areaEnd: noop,
+ lineStart: function() {
+ this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
+ this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
+ this._point = 0;
+ },
+ lineEnd: function() {
+ switch (this._point) {
+ case 1: {
+ this._context.moveTo(this._x3, this._y3);
+ this._context.closePath();
+ break;
+ }
+ case 2: {
+ this._context.lineTo(this._x3, this._y3);
+ this._context.closePath();
+ break;
+ }
+ case 3: {
+ this.point(this._x3, this._y3);
+ this.point(this._x4, this._y4);
+ this.point(this._x5, this._y5);
+ break;
+ }
+ }
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+ switch (this._point) {
+ case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
+ case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
+ case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
+ default: point$2(this, x, y); break;
+ }
+ this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
+ this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
+ }
+};
+
+var cardinalClosed = (function custom(tension) {
+
+ function cardinal(context) {
+ return new CardinalClosed(context, tension);
+ }
+
+ cardinal.tension = function(tension) {
+ return custom(+tension);
+ };
+
+ return cardinal;
+})(0);
+
+function CardinalOpen(context, tension) {
+ this._context = context;
+ this._k = (1 - tension) / 6;
+}
+
+CardinalOpen.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._x0 = this._x1 = this._x2 =
+ this._y0 = this._y1 = this._y2 = NaN;
+ this._point = 0;
+ },
+ lineEnd: function() {
+ if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
+ this._line = 1 - this._line;
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+ switch (this._point) {
+ case 0: this._point = 1; break;
+ case 1: this._point = 2; break;
+ case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
+ case 3: this._point = 4; // falls through
+ default: point$2(this, x, y); break;
+ }
+ this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
+ this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
+ }
+};
+
+var cardinalOpen = (function custom(tension) {
+
+ function cardinal(context) {
+ return new CardinalOpen(context, tension);
+ }
+
+ cardinal.tension = function(tension) {
+ return custom(+tension);
+ };
+
+ return cardinal;
+})(0);
+
+function point$1(that, x, y) {
+ var x1 = that._x1,
+ y1 = that._y1,
+ x2 = that._x2,
+ y2 = that._y2;
+
+ if (that._l01_a > epsilon) {
+ var a = 2 * that._l01_2a + 3 * that._l01_a * that._l12_a + that._l12_2a,
+ n = 3 * that._l01_a * (that._l01_a + that._l12_a);
+ x1 = (x1 * a - that._x0 * that._l12_2a + that._x2 * that._l01_2a) / n;
+ y1 = (y1 * a - that._y0 * that._l12_2a + that._y2 * that._l01_2a) / n;
+ }
+
+ if (that._l23_a > epsilon) {
+ var b = 2 * that._l23_2a + 3 * that._l23_a * that._l12_a + that._l12_2a,
+ m = 3 * that._l23_a * (that._l23_a + that._l12_a);
+ x2 = (x2 * b + that._x1 * that._l23_2a - x * that._l12_2a) / m;
+ y2 = (y2 * b + that._y1 * that._l23_2a - y * that._l12_2a) / m;
+ }
+
+ that._context.bezierCurveTo(x1, y1, x2, y2, that._x2, that._y2);
+}
+
+function CatmullRom(context, alpha) {
+ this._context = context;
+ this._alpha = alpha;
+}
+
+CatmullRom.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._x0 = this._x1 = this._x2 =
+ this._y0 = this._y1 = this._y2 = NaN;
+ this._l01_a = this._l12_a = this._l23_a =
+ this._l01_2a = this._l12_2a = this._l23_2a =
+ this._point = 0;
+ },
+ lineEnd: function() {
+ switch (this._point) {
+ case 2: this._context.lineTo(this._x2, this._y2); break;
+ case 3: this.point(this._x2, this._y2); break;
+ }
+ if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
+ this._line = 1 - this._line;
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+
+ if (this._point) {
+ var x23 = this._x2 - x,
+ y23 = this._y2 - y;
+ this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
+ }
+
+ switch (this._point) {
+ case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
+ case 1: this._point = 2; break;
+ case 2: this._point = 3; // falls through
+ default: point$1(this, x, y); break;
+ }
+
+ this._l01_a = this._l12_a, this._l12_a = this._l23_a;
+ this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
+ this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
+ this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
+ }
+};
+
+var catmullRom = (function custom(alpha) {
+
+ function catmullRom(context) {
+ return alpha ? new CatmullRom(context, alpha) : new Cardinal(context, 0);
+ }
+
+ catmullRom.alpha = function(alpha) {
+ return custom(+alpha);
+ };
+
+ return catmullRom;
+})(0.5);
+
+function CatmullRomClosed(context, alpha) {
+ this._context = context;
+ this._alpha = alpha;
+}
+
+CatmullRomClosed.prototype = {
+ areaStart: noop,
+ areaEnd: noop,
+ lineStart: function() {
+ this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
+ this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
+ this._l01_a = this._l12_a = this._l23_a =
+ this._l01_2a = this._l12_2a = this._l23_2a =
+ this._point = 0;
+ },
+ lineEnd: function() {
+ switch (this._point) {
+ case 1: {
+ this._context.moveTo(this._x3, this._y3);
+ this._context.closePath();
+ break;
+ }
+ case 2: {
+ this._context.lineTo(this._x3, this._y3);
+ this._context.closePath();
+ break;
+ }
+ case 3: {
+ this.point(this._x3, this._y3);
+ this.point(this._x4, this._y4);
+ this.point(this._x5, this._y5);
+ break;
+ }
+ }
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+
+ if (this._point) {
+ var x23 = this._x2 - x,
+ y23 = this._y2 - y;
+ this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
+ }
+
+ switch (this._point) {
+ case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
+ case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
+ case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
+ default: point$1(this, x, y); break;
+ }
+
+ this._l01_a = this._l12_a, this._l12_a = this._l23_a;
+ this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
+ this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
+ this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
+ }
+};
+
+var catmullRomClosed = (function custom(alpha) {
+
+ function catmullRom(context) {
+ return alpha ? new CatmullRomClosed(context, alpha) : new CardinalClosed(context, 0);
+ }
+
+ catmullRom.alpha = function(alpha) {
+ return custom(+alpha);
+ };
+
+ return catmullRom;
+})(0.5);
+
+function CatmullRomOpen(context, alpha) {
+ this._context = context;
+ this._alpha = alpha;
+}
+
+CatmullRomOpen.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._x0 = this._x1 = this._x2 =
+ this._y0 = this._y1 = this._y2 = NaN;
+ this._l01_a = this._l12_a = this._l23_a =
+ this._l01_2a = this._l12_2a = this._l23_2a =
+ this._point = 0;
+ },
+ lineEnd: function() {
+ if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
+ this._line = 1 - this._line;
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+
+ if (this._point) {
+ var x23 = this._x2 - x,
+ y23 = this._y2 - y;
+ this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
+ }
+
+ switch (this._point) {
+ case 0: this._point = 1; break;
+ case 1: this._point = 2; break;
+ case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
+ case 3: this._point = 4; // falls through
+ default: point$1(this, x, y); break;
+ }
+
+ this._l01_a = this._l12_a, this._l12_a = this._l23_a;
+ this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
+ this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
+ this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
+ }
+};
+
+var catmullRomOpen = (function custom(alpha) {
+
+ function catmullRom(context) {
+ return alpha ? new CatmullRomOpen(context, alpha) : new CardinalOpen(context, 0);
+ }
+
+ catmullRom.alpha = function(alpha) {
+ return custom(+alpha);
+ };
+
+ return catmullRom;
+})(0.5);
+
+function LinearClosed(context) {
+ this._context = context;
+}
+
+LinearClosed.prototype = {
+ areaStart: noop,
+ areaEnd: noop,
+ lineStart: function() {
+ this._point = 0;
+ },
+ lineEnd: function() {
+ if (this._point) this._context.closePath();
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+ if (this._point) this._context.lineTo(x, y);
+ else this._point = 1, this._context.moveTo(x, y);
+ }
+};
+
+function linearClosed(context) {
+ return new LinearClosed(context);
+}
+
+function sign(x) {
+ return x < 0 ? -1 : 1;
+}
+
+// Calculate the slopes of the tangents (Hermite-type interpolation) based on
+// the following paper: Steffen, M. 1990. A Simple Method for Monotonic
+// Interpolation in One Dimension. Astronomy and Astrophysics, Vol. 239, NO.
+// NOV(II), P. 443, 1990.
+function slope3(that, x2, y2) {
+ var h0 = that._x1 - that._x0,
+ h1 = x2 - that._x1,
+ s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0),
+ s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0),
+ p = (s0 * h1 + s1 * h0) / (h0 + h1);
+ return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;
+}
+
+// Calculate a one-sided slope.
+function slope2(that, t) {
+ var h = that._x1 - that._x0;
+ return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t;
+}
+
+// According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations
+// "you can express cubic Hermite interpolation in terms of cubic Bézier curves
+// with respect to the four values p0, p0 + m0 / 3, p1 - m1 / 3, p1".
+function point(that, t0, t1) {
+ var x0 = that._x0,
+ y0 = that._y0,
+ x1 = that._x1,
+ y1 = that._y1,
+ dx = (x1 - x0) / 3;
+ that._context.bezierCurveTo(x0 + dx, y0 + dx * t0, x1 - dx, y1 - dx * t1, x1, y1);
+}
+
+function MonotoneX(context) {
+ this._context = context;
+}
+
+MonotoneX.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._x0 = this._x1 =
+ this._y0 = this._y1 =
+ this._t0 = NaN;
+ this._point = 0;
+ },
+ lineEnd: function() {
+ switch (this._point) {
+ case 2: this._context.lineTo(this._x1, this._y1); break;
+ case 3: point(this, this._t0, slope2(this, this._t0)); break;
+ }
+ if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
+ this._line = 1 - this._line;
+ },
+ point: function(x, y) {
+ var t1 = NaN;
+
+ x = +x, y = +y;
+ if (x === this._x1 && y === this._y1) return; // Ignore coincident points.
+ switch (this._point) {
+ case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
+ case 1: this._point = 2; break;
+ case 2: this._point = 3; point(this, slope2(this, t1 = slope3(this, x, y)), t1); break;
+ default: point(this, this._t0, t1 = slope3(this, x, y)); break;
+ }
+
+ this._x0 = this._x1, this._x1 = x;
+ this._y0 = this._y1, this._y1 = y;
+ this._t0 = t1;
+ }
+};
+
+function MonotoneY(context) {
+ this._context = new ReflectContext(context);
+}
+
+(MonotoneY.prototype = Object.create(MonotoneX.prototype)).point = function(x, y) {
+ MonotoneX.prototype.point.call(this, y, x);
+};
+
+function ReflectContext(context) {
+ this._context = context;
+}
+
+ReflectContext.prototype = {
+ moveTo: function(x, y) { this._context.moveTo(y, x); },
+ closePath: function() { this._context.closePath(); },
+ lineTo: function(x, y) { this._context.lineTo(y, x); },
+ bezierCurveTo: function(x1, y1, x2, y2, x, y) { this._context.bezierCurveTo(y1, x1, y2, x2, y, x); }
+};
+
+function monotoneX(context) {
+ return new MonotoneX(context);
+}
+
+function monotoneY(context) {
+ return new MonotoneY(context);
+}
+
+function Natural(context) {
+ this._context = context;
+}
+
+Natural.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._x = [];
+ this._y = [];
+ },
+ lineEnd: function() {
+ var x = this._x,
+ y = this._y,
+ n = x.length;
+
+ if (n) {
+ this._line ? this._context.lineTo(x[0], y[0]) : this._context.moveTo(x[0], y[0]);
+ if (n === 2) {
+ this._context.lineTo(x[1], y[1]);
+ } else {
+ var px = controlPoints(x),
+ py = controlPoints(y);
+ for (var i0 = 0, i1 = 1; i1 < n; ++i0, ++i1) {
+ this._context.bezierCurveTo(px[0][i0], py[0][i0], px[1][i0], py[1][i0], x[i1], y[i1]);
+ }
+ }
+ }
+
+ if (this._line || (this._line !== 0 && n === 1)) this._context.closePath();
+ this._line = 1 - this._line;
+ this._x = this._y = null;
+ },
+ point: function(x, y) {
+ this._x.push(+x);
+ this._y.push(+y);
+ }
+};
+
+// See https://www.particleincell.com/2012/bezier-splines/ for derivation.
+function controlPoints(x) {
+ var i,
+ n = x.length - 1,
+ m,
+ a = new Array(n),
+ b = new Array(n),
+ r = new Array(n);
+ a[0] = 0, b[0] = 2, r[0] = x[0] + 2 * x[1];
+ for (i = 1; i < n - 1; ++i) a[i] = 1, b[i] = 4, r[i] = 4 * x[i] + 2 * x[i + 1];
+ a[n - 1] = 2, b[n - 1] = 7, r[n - 1] = 8 * x[n - 1] + x[n];
+ for (i = 1; i < n; ++i) m = a[i] / b[i - 1], b[i] -= m, r[i] -= m * r[i - 1];
+ a[n - 1] = r[n - 1] / b[n - 1];
+ for (i = n - 2; i >= 0; --i) a[i] = (r[i] - a[i + 1]) / b[i];
+ b[n - 1] = (x[n] + a[n - 1]) / 2;
+ for (i = 0; i < n - 1; ++i) b[i] = 2 * x[i + 1] - a[i + 1];
+ return [a, b];
+}
+
+function natural(context) {
+ return new Natural(context);
+}
+
+function Step(context, t) {
+ this._context = context;
+ this._t = t;
+}
+
+Step.prototype = {
+ areaStart: function() {
+ this._line = 0;
+ },
+ areaEnd: function() {
+ this._line = NaN;
+ },
+ lineStart: function() {
+ this._x = this._y = NaN;
+ this._point = 0;
+ },
+ lineEnd: function() {
+ if (0 < this._t && this._t < 1 && this._point === 2) this._context.lineTo(this._x, this._y);
+ if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
+ if (this._line >= 0) this._t = 1 - this._t, this._line = 1 - this._line;
+ },
+ point: function(x, y) {
+ x = +x, y = +y;
+ switch (this._point) {
+ case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
+ case 1: this._point = 2; // falls through
+ default: {
+ if (this._t <= 0) {
+ this._context.lineTo(this._x, y);
+ this._context.lineTo(x, y);
+ } else {
+ var x1 = this._x * (1 - this._t) + x * this._t;
+ this._context.lineTo(x1, this._y);
+ this._context.lineTo(x1, y);
+ }
+ break;
+ }
+ }
+ this._x = x, this._y = y;
+ }
+};
+
+function step(context) {
+ return new Step(context, 0.5);
+}
+
+function stepBefore(context) {
+ return new Step(context, 0);
+}
+
+function stepAfter(context) {
+ return new Step(context, 1);
+}
+
+function none$1(series, order) {
+ if (!((n = series.length) > 1)) return;
+ for (var i = 1, j, s0, s1 = series[order[0]], n, m = s1.length; i < n; ++i) {
+ s0 = s1, s1 = series[order[i]];
+ for (j = 0; j < m; ++j) {
+ s1[j][1] += s1[j][0] = isNaN(s0[j][1]) ? s0[j][0] : s0[j][1];
+ }
+ }
+}
+
+function none(series) {
+ var n = series.length, o = new Array(n);
+ while (--n >= 0) o[n] = n;
+ return o;
+}
+
+function stackValue(d, key) {
+ return d[key];
+}
+
+function stackSeries(key) {
+ const series = [];
+ series.key = key;
+ return series;
+}
+
+function stack() {
+ var keys = constant([]),
+ order = none,
+ offset = none$1,
+ value = stackValue;
+
+ function stack(data) {
+ var sz = Array.from(keys.apply(this, arguments), stackSeries),
+ i, n = sz.length, j = -1,
+ oz;
+
+ for (const d of data) {
+ for (i = 0, ++j; i < n; ++i) {
+ (sz[i][j] = [0, +value(d, sz[i].key, j, data)]).data = d;
+ }
+ }
+
+ for (i = 0, oz = array(order(sz)); i < n; ++i) {
+ sz[oz[i]].index = i;
+ }
+
+ offset(sz, oz);
+ return sz;
+ }
+
+ stack.keys = function(_) {
+ return arguments.length ? (keys = typeof _ === "function" ? _ : constant(Array.from(_)), stack) : keys;
+ };
+
+ stack.value = function(_) {
+ return arguments.length ? (value = typeof _ === "function" ? _ : constant(+_), stack) : value;
+ };
+
+ stack.order = function(_) {
+ return arguments.length ? (order = _ == null ? none : typeof _ === "function" ? _ : constant(Array.from(_)), stack) : order;
+ };
+
+ stack.offset = function(_) {
+ return arguments.length ? (offset = _ == null ? none$1 : _, stack) : offset;
+ };
+
+ return stack;
+}
+
+function expand(series, order) {
+ if (!((n = series.length) > 0)) return;
+ for (var i, n, j = 0, m = series[0].length, y; j < m; ++j) {
+ for (y = i = 0; i < n; ++i) y += series[i][j][1] || 0;
+ if (y) for (i = 0; i < n; ++i) series[i][j][1] /= y;
+ }
+ none$1(series, order);
+}
+
+function diverging(series, order) {
+ if (!((n = series.length) > 0)) return;
+ for (var i, j = 0, d, dy, yp, yn, n, m = series[order[0]].length; j < m; ++j) {
+ for (yp = yn = 0, i = 0; i < n; ++i) {
+ if ((dy = (d = series[order[i]][j])[1] - d[0]) > 0) {
+ d[0] = yp, d[1] = yp += dy;
+ } else if (dy < 0) {
+ d[1] = yn, d[0] = yn += dy;
+ } else {
+ d[0] = 0, d[1] = dy;
+ }
+ }
+ }
+}
+
+function silhouette(series, order) {
+ if (!((n = series.length) > 0)) return;
+ for (var j = 0, s0 = series[order[0]], n, m = s0.length; j < m; ++j) {
+ for (var i = 0, y = 0; i < n; ++i) y += series[i][j][1] || 0;
+ s0[j][1] += s0[j][0] = -y / 2;
+ }
+ none$1(series, order);
+}
+
+function wiggle(series, order) {
+ if (!((n = series.length) > 0) || !((m = (s0 = series[order[0]]).length) > 0)) return;
+ for (var y = 0, j = 1, s0, m, n; j < m; ++j) {
+ for (var i = 0, s1 = 0, s2 = 0; i < n; ++i) {
+ var si = series[order[i]],
+ sij0 = si[j][1] || 0,
+ sij1 = si[j - 1][1] || 0,
+ s3 = (sij0 - sij1) / 2;
+ for (var k = 0; k < i; ++k) {
+ var sk = series[order[k]],
+ skj0 = sk[j][1] || 0,
+ skj1 = sk[j - 1][1] || 0;
+ s3 += skj0 - skj1;
+ }
+ s1 += sij0, s2 += s3 * sij0;
+ }
+ s0[j - 1][1] += s0[j - 1][0] = y;
+ if (s1) y -= s2 / s1;
+ }
+ s0[j - 1][1] += s0[j - 1][0] = y;
+ none$1(series, order);
+}
+
+function appearance(series) {
+ var peaks = series.map(peak);
+ return none(series).sort(function(a, b) { return peaks[a] - peaks[b]; });
+}
+
+function peak(series) {
+ var i = -1, j = 0, n = series.length, vi, vj = -Infinity;
+ while (++i < n) if ((vi = +series[i][1]) > vj) vj = vi, j = i;
+ return j;
+}
+
+function ascending(series) {
+ var sums = series.map(sum);
+ return none(series).sort(function(a, b) { return sums[a] - sums[b]; });
+}
+
+function sum(series) {
+ var s = 0, i = -1, n = series.length, v;
+ while (++i < n) if (v = +series[i][1]) s += v;
+ return s;
+}
+
+function descending(series) {
+ return ascending(series).reverse();
+}
+
+function insideOut(series) {
+ var n = series.length,
+ i,
+ j,
+ sums = series.map(sum),
+ order = appearance(series),
+ top = 0,
+ bottom = 0,
+ tops = [],
+ bottoms = [];
+
+ for (i = 0; i < n; ++i) {
+ j = order[i];
+ if (top < bottom) {
+ top += sums[j];
+ tops.push(j);
+ } else {
+ bottom += sums[j];
+ bottoms.push(j);
+ }
+ }
+
+ return bottoms.reverse().concat(tops);
+}
+
+function reverse(series) {
+ return none(series).reverse();
+}
+
+exports.arc = arc;
+exports.area = area;
+exports.areaRadial = areaRadial;
+exports.curveBasis = basis;
+exports.curveBasisClosed = basisClosed;
+exports.curveBasisOpen = basisOpen;
+exports.curveBumpX = bumpX;
+exports.curveBumpY = bumpY;
+exports.curveBundle = bundle;
+exports.curveCardinal = cardinal;
+exports.curveCardinalClosed = cardinalClosed;
+exports.curveCardinalOpen = cardinalOpen;
+exports.curveCatmullRom = catmullRom;
+exports.curveCatmullRomClosed = catmullRomClosed;
+exports.curveCatmullRomOpen = catmullRomOpen;
+exports.curveLinear = curveLinear;
+exports.curveLinearClosed = linearClosed;
+exports.curveMonotoneX = monotoneX;
+exports.curveMonotoneY = monotoneY;
+exports.curveNatural = natural;
+exports.curveStep = step;
+exports.curveStepAfter = stepAfter;
+exports.curveStepBefore = stepBefore;
+exports.line = line;
+exports.lineRadial = lineRadial$1;
+exports.link = link;
+exports.linkHorizontal = linkHorizontal;
+exports.linkRadial = linkRadial;
+exports.linkVertical = linkVertical;
+exports.pie = pie;
+exports.pointRadial = pointRadial;
+exports.radialArea = areaRadial;
+exports.radialLine = lineRadial$1;
+exports.stack = stack;
+exports.stackOffsetDiverging = diverging;
+exports.stackOffsetExpand = expand;
+exports.stackOffsetNone = none$1;
+exports.stackOffsetSilhouette = silhouette;
+exports.stackOffsetWiggle = wiggle;
+exports.stackOrderAppearance = appearance;
+exports.stackOrderAscending = ascending;
+exports.stackOrderDescending = descending;
+exports.stackOrderInsideOut = insideOut;
+exports.stackOrderNone = none;
+exports.stackOrderReverse = reverse;
+exports.symbol = Symbol;
+exports.symbolAsterisk = asterisk;
+exports.symbolCircle = circle;
+exports.symbolCross = cross;
+exports.symbolDiamond = diamond;
+exports.symbolDiamond2 = diamond2;
+exports.symbolPlus = plus;
+exports.symbolSquare = square;
+exports.symbolSquare2 = square2;
+exports.symbolStar = star;
+exports.symbolTimes = times;
+exports.symbolTriangle = triangle;
+exports.symbolTriangle2 = triangle2;
+exports.symbolWye = wye;
+exports.symbolX = times;
+exports.symbols = symbolsFill;
+exports.symbolsFill = symbolsFill;
+exports.symbolsStroke = symbolsStroke;
+
+}));
diff --git a/node_modules/d3-shape/dist/d3-shape.min.js b/node_modules/d3-shape/dist/d3-shape.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..7cc20385414e4596e83ac9a82ac41d3a59351522
--- /dev/null
+++ b/node_modules/d3-shape/dist/d3-shape.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-shape/ v3.2.0 Copyright 2010-2022 Mike Bostock
+!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("d3-path")):"function"==typeof define&&define.amd?define(["exports","d3-path"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).d3=t.d3||{},t.d3)}(this,(function(t,n){"use strict";function i(t){return function(){return t}}const e=Math.abs,s=Math.atan2,o=Math.cos,h=Math.max,_=Math.min,r=Math.sin,a=Math.sqrt,l=1e-12,c=Math.PI,u=c/2,f=2*c;function y(t){return t>1?0:t<-1?c:Math.acos(t)}function x(t){return t>=1?u:t<=-1?-u:Math.asin(t)}function p(t){let i=3;return t.digits=function(n){if(!arguments.length)return i;if(null==n)i=null;else{const t=Math.floor(n);if(!(t>=0))throw new RangeError(`invalid digits: ${n}`);i=t}return t},()=>new n.Path(i)}function v(t){return t.innerRadius}function d(t){return t.outerRadius}function T(t){return t.startAngle}function g(t){return t.endAngle}function m(t){return t&&t.padAngle}function b(t,n,i,e,s,o,h,_){var r=i-t,a=e-n,c=h-s,u=_-o,f=u*r-c*a;if(!(f*f=0;)i[n]=n;return i}function en(t,n){return t[n]}function sn(t){const n=[];return n.key=t,n}function on(t){var n=t.map(hn);return nn(t).sort((function(t,i){return n[t]-n[i]}))}function hn(t){for(var n,i=-1,e=0,s=t.length,o=-1/0;++io&&(o=n,e=i);return e}function _n(t){var n=t.map(rn);return nn(t).sort((function(t,i){return n[t]-n[i]}))}function rn(t){for(var n,i=0,e=-1,s=t.length;++e=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var i=this._x*(1-this._t)+t*this._t;this._context.lineTo(i,this._y),this._context.lineTo(i,n)}}this._x=t,this._y=n}},t.arc=function(){var t=v,n=d,h=i(0),k=null,N=T,S=g,E=m,A=null,P=p(M);function M(){var i,p,v=+t.apply(this,arguments),d=+n.apply(this,arguments),T=N.apply(this,arguments)-u,g=S.apply(this,arguments)-u,m=e(g-T),M=g>T;if(A||(A=i=P()),d
# d3.utcMillisecond
+
+Milliseconds; the shortest available time unit.
+
+# d3.timeSecond · [Source](https://github.com/d3/d3-time/blob/main/src/second.js "Source")
+
# d3.utcSecond
+
+Seconds (e.g., 01:23:45.0000 AM); 1,000 milliseconds.
+
+# d3.timeMinute · [Source](https://github.com/d3/d3-time/blob/main/src/minute.js "Source")
+
# d3.utcMinute · [Source](https://github.com/d3/d3-time/blob/main/src/utcMinute.js "Source")
+
+Minutes (e.g., 01:02:00 AM); 60 seconds. Note that ECMAScript [ignores leap seconds](http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.1).
+
+# d3.timeHour · [Source](https://github.com/d3/d3-time/blob/main/src/hour.js "Source")
+
# d3.utcHour · [Source](https://github.com/d3/d3-time/blob/main/src/utcHour.js "Source")
+
+Hours (e.g., 01:00 AM); 60 minutes. Note that advancing time by one hour in local time can return the same hour or skip an hour due to daylight saving.
+
+# d3.timeDay · [Source](https://github.com/d3/d3-time/blob/main/src/day.js "Source")
+
# d3.utcDay · [Source](https://github.com/d3/d3-time/blob/main/src/utcDay.js "Source")
+
# d3.unixDay · [Source](https://github.com/d3/d3-time/blob/main/src/unixDay.js "Source")
+
+Days (e.g., February 7, 2012 at 12:00 AM); typically 24 hours. Days in local time may range from 23 to 25 hours due to daylight saving. d3.unixDay is like [d3.utcDay](#timeDay), except it counts days since the UNIX epoch (January 1, 1970) such that *interval*.every returns uniformly-spaced dates rather than varying based on day-of-month.
+
+# d3.timeWeek · [Source](https://github.com/d3/d3-time/blob/main/src/week.js "Source")
+
# d3.utcWeek · [Source](https://github.com/d3/d3-time/blob/main/src/utcWeek.js "Source")
+
+Alias for [d3.timeSunday](#timeSunday); 7 days and typically 168 hours. Weeks in local time may range from 167 to 169 hours due to daylight saving.
+
+# d3.timeSunday · [Source](https://github.com/d3/d3-time/blob/main/src/week.js)
+
# d3.utcSunday · [Source](https://github.com/d3/d3-time/blob/main/src/utcWeek.js)
+
+Sunday-based weeks (e.g., February 5, 2012 at 12:00 AM).
+
+# d3.timeMonday · [Source](https://github.com/d3/d3-time/blob/main/src/week.js)
+
# d3.utcMonday · [Source](https://github.com/d3/d3-time/blob/main/src/utcWeek.js)
+
+Monday-based weeks (e.g., February 6, 2012 at 12:00 AM).
+
+# d3.timeTuesday · [Source](https://github.com/d3/d3-time/blob/main/src/week.js)
+
# d3.utcTuesday · [Source](https://github.com/d3/d3-time/blob/main/src/utcWeek.js)
+
+Tuesday-based weeks (e.g., February 7, 2012 at 12:00 AM).
+
+# d3.timeWednesday · [Source](https://github.com/d3/d3-time/blob/main/src/week.js)
+
# d3.utcWednesday · [Source](https://github.com/d3/d3-time/blob/main/src/utcWeek.js)
+
+Wednesday-based weeks (e.g., February 8, 2012 at 12:00 AM).
+
+# d3.timeThursday · [Source](https://github.com/d3/d3-time/blob/main/src/week.js)
+
# d3.utcThursday · [Source](https://github.com/d3/d3-time/blob/main/src/utcWeek.js)
+
+Thursday-based weeks (e.g., February 9, 2012 at 12:00 AM).
+
+# d3.timeFriday · [Source](https://github.com/d3/d3-time/blob/main/src/week.js)
+
# d3.utcFriday · [Source](https://github.com/d3/d3-time/blob/main/src/utcWeek.js)
+
+Friday-based weeks (e.g., February 10, 2012 at 12:00 AM).
+
+# d3.timeSaturday · [Source](https://github.com/d3/d3-time/blob/main/src/week.js)
+
# d3.utcSaturday · [Source](https://github.com/d3/d3-time/blob/main/src/utcWeek.js)
+
+Saturday-based weeks (e.g., February 11, 2012 at 12:00 AM).
+
+# d3.timeMonth · [Source](https://github.com/d3/d3-time/blob/main/src/month.js "Source")
+
# d3.utcMonth · [Source](https://github.com/d3/d3-time/blob/main/src/utcMonth.js "Source")
+
+Months (e.g., February 1, 2012 at 12:00 AM); ranges from 28 to 31 days.
+
+# d3.timeYear · [Source](https://github.com/d3/d3-time/blob/main/src/year.js "Source")
+
# d3.utcYear · [Source](https://github.com/d3/d3-time/blob/main/src/utcYear.js "Source")
+
+Years (e.g., January 1, 2012 at 12:00 AM); ranges from 365 to 366 days.
+
+### Ranges
+
+For convenience, aliases for [*interval*.range](#interval_range) are also provided as plural forms of the corresponding interval.
+
+# d3.timeMilliseconds(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/millisecond.js)
+
# d3.utcMilliseconds(start, stop[, step])
+
+Aliases for [d3.timeMillisecond](#timeMillisecond).[range](#interval_range) and [d3.utcMillisecond](#timeMillisecond).[range](#interval_range).
+
+# d3.timeSeconds(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/second.js)
+
# d3.utcSeconds(start, stop[, step])
+
+Aliases for [d3.timeSecond](#timeSecond).[range](#interval_range) and [d3.utcSecond](#timeSecond).[range](#interval_range).
+
+# d3.timeMinutes(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/minute.js)
+
# d3.utcMinutes(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/utcMinute.js)
+
+Aliases for [d3.timeMinute](#timeMinute).[range](#interval_range) and [d3.utcMinute](#timeMinute).[range](#interval_range).
+
+# d3.timeHours(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/hour.js)
+
# d3.utcHours(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/utcHour.js)
+
+Aliases for [d3.timeHour](#timeHour).[range](#interval_range) and [d3.utcHour](#timeHour).[range](#interval_range).
+
+# d3.timeDays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/day.js)
+
# d3.utcDays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/utcDay.js)
+
# d3.unixDays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/unixDay.js)
+
+Aliases for [d3.timeDay](#timeDay).[range](#interval_range), [d3.utcDay](#timeDay).[range](#interval_range), and [d3.unixDay](#timeDay).[range](#interval_range).
+
+# d3.timeWeeks(start, stop[, step])
+
# d3.utcWeeks(start, stop[, step])
+
+Aliases for [d3.timeWeek](#timeWeek).[range](#interval_range) and [d3.utcWeek](#timeWeek).[range](#interval_range).
+
+# d3.timeSundays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/week.js)
+
# d3.utcSundays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/utcWeek.js)
+
+Aliases for [d3.timeSunday](#timeSunday).[range](#interval_range) and [d3.utcSunday](#timeSunday).[range](#interval_range).
+
+# d3.timeMondays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/week.js)
+
# d3.utcMondays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/utcWeek.js)
+
+Aliases for [d3.timeMonday](#timeMonday).[range](#interval_range) and [d3.utcMonday](#timeMonday).[range](#interval_range).
+
+# d3.timeTuesdays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/week.js)
+
# d3.utcTuesdays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/utcWeek.js)
+
+Aliases for [d3.timeTuesday](#timeTuesday).[range](#interval_range) and [d3.utcTuesday](#timeTuesday).[range](#interval_range).
+
+# d3.timeWednesdays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/week.js)
+
# d3.utcWednesdays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/utcWeek.js)
+
+Aliases for [d3.timeWednesday](#timeWednesday).[range](#interval_range) and [d3.utcWednesday](#timeWednesday).[range](#interval_range).
+
+# d3.timeThursdays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/week.js)
+
# d3.utcThursdays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/utcWeek.js)
+
+Aliases for [d3.timeThursday](#timeThursday).[range](#interval_range) and [d3.utcThursday](#timeThursday).[range](#interval_range).
+
+# d3.timeFridays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/week.js)
+
# d3.utcFridays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/utcWeek.js)
+
+Aliases for [d3.timeFriday](#timeFriday).[range](#interval_range) and [d3.utcFriday](#timeFriday).[range](#interval_range).
+
+# d3.timeSaturdays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/week.js)
+
# d3.utcSaturdays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/utcWeek.js)
+
+Aliases for [d3.timeSaturday](#timeSaturday).[range](#interval_range) and [d3.utcSaturday](#timeSaturday).[range](#interval_range).
+
+# d3.timeMonths(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/month.js)
+
# d3.utcMonths(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/utcMonth.js)
+
+Aliases for [d3.timeMonth](#timeMonth).[range](#interval_range) and [d3.utcMonth](#timeMonth).[range](#interval_range).
+
+# d3.timeYears(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/year.js)
+
# d3.utcYears(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/utcYear.js)
+
+Aliases for [d3.timeYear](#timeYear).[range](#interval_range) and [d3.utcYear](#timeYear).[range](#interval_range).
+
+### Ticks
+
+# d3.timeTicks(start, stop, count) · [Source](https://github.com/d3/d3-time/blob/main/src/ticks.js)
+
+Equivalent to [d3.utcTicks](#utcTicks), but in local time.
+
+# d3.timeTickInterval(start, stop, count) · [Source](https://github.com/d3/d3-time/blob/main/src/ticks.js)
+
+Returns the time interval that would be used by [d3.timeTicks](#timeTicks) given the same arguments.
+
+# d3.utcTicks(start, stop, count) · [Source](https://github.com/d3/d3-time/blob/main/src/ticks.js)
+
+Returns an array of approximately *count* dates at regular intervals between *start* and *stop* (inclusive). If *stop* is before *start*, dates are returned in reverse chronological order; otherwise dates are returned in chronological order. The following UTC time intervals are considered:
+
+* 1 second
+* 5 seconds
+* 15 seconds
+* 30 seconds
+* 1 minute
+* 5 minutes
+* 15 minutes
+* 30 minutes
+* 1 hour
+* 3 hours
+* 6 hours
+* 12 hours
+* 1 day
+* 2 days
+* 1 week
+* 1 month
+* 3 months
+* 1 year
+
+Multiples of milliseconds (for small ranges) and years (for large ranges) are also considered, following the rules of [d3.ticks](https://github.com/d3/d3-array/blob/main/README.md#ticks). The interval producing the number of dates that is closest to *count* is used. For example:
+
+```js
+start = new Date(Date.UTC(1970, 2, 1))
+stop = new Date(Date.UTC(1996, 2, 19))
+count = 4
+d3.utcTicks(start, stop, count) // [1975-01-01, 1980-01-01, 1985-01-01, 1990-01-01, 1995-01-01]
+```
+
+If *count* is a time interval, this function behaves similarly to [*interval*.range](#interval_range) except that both *start* and *stop* are inclusive and it may return dates in reverse chronological order if *stop* is before *start*.
+
+# d3.utcTickInterval(start, stop, count) · [Source](https://github.com/d3/d3-time/blob/main/src/ticks.js)
+
+Returns the time interval that would be used by [d3.utcTicks](#utcTicks) given the same arguments. If there is no associated interval, such as when *start* or *stop* is invalid, returns null.
diff --git a/node_modules/d3-time/dist/d3-time.js b/node_modules/d3-time/dist/d3-time.js
new file mode 100644
index 0000000000000000000000000000000000000000..6ca6e2d21e814cbb0e5baa457a34ed4c679b21be
--- /dev/null
+++ b/node_modules/d3-time/dist/d3-time.js
@@ -0,0 +1,445 @@
+// https://d3js.org/d3-time/ v3.1.0 Copyright 2010-2022 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-array')) :
+typeof define === 'function' && define.amd ? define(['exports', 'd3-array'], factory) :
+(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.d3 = global.d3 || {}, global.d3));
+})(this, (function (exports, d3Array) { 'use strict';
+
+const t0 = new Date, t1 = new Date;
+
+function timeInterval(floori, offseti, count, field) {
+
+ function interval(date) {
+ return floori(date = arguments.length === 0 ? new Date : new Date(+date)), date;
+ }
+
+ interval.floor = (date) => {
+ return floori(date = new Date(+date)), date;
+ };
+
+ interval.ceil = (date) => {
+ return floori(date = new Date(date - 1)), offseti(date, 1), floori(date), date;
+ };
+
+ interval.round = (date) => {
+ const d0 = interval(date), d1 = interval.ceil(date);
+ return date - d0 < d1 - date ? d0 : d1;
+ };
+
+ interval.offset = (date, step) => {
+ return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date;
+ };
+
+ interval.range = (start, stop, step) => {
+ const range = [];
+ start = interval.ceil(start);
+ step = step == null ? 1 : Math.floor(step);
+ if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date
+ let previous;
+ do range.push(previous = new Date(+start)), offseti(start, step), floori(start);
+ while (previous < start && start < stop);
+ return range;
+ };
+
+ interval.filter = (test) => {
+ return timeInterval((date) => {
+ if (date >= date) while (floori(date), !test(date)) date.setTime(date - 1);
+ }, (date, step) => {
+ if (date >= date) {
+ if (step < 0) while (++step <= 0) {
+ while (offseti(date, -1), !test(date)) {} // eslint-disable-line no-empty
+ } else while (--step >= 0) {
+ while (offseti(date, +1), !test(date)) {} // eslint-disable-line no-empty
+ }
+ }
+ });
+ };
+
+ if (count) {
+ interval.count = (start, end) => {
+ t0.setTime(+start), t1.setTime(+end);
+ floori(t0), floori(t1);
+ return Math.floor(count(t0, t1));
+ };
+
+ interval.every = (step) => {
+ step = Math.floor(step);
+ return !isFinite(step) || !(step > 0) ? null
+ : !(step > 1) ? interval
+ : interval.filter(field
+ ? (d) => field(d) % step === 0
+ : (d) => interval.count(0, d) % step === 0);
+ };
+ }
+
+ return interval;
+}
+
+const millisecond = timeInterval(() => {
+ // noop
+}, (date, step) => {
+ date.setTime(+date + step);
+}, (start, end) => {
+ return end - start;
+});
+
+// An optimized implementation for this simple case.
+millisecond.every = (k) => {
+ k = Math.floor(k);
+ if (!isFinite(k) || !(k > 0)) return null;
+ if (!(k > 1)) return millisecond;
+ return timeInterval((date) => {
+ date.setTime(Math.floor(date / k) * k);
+ }, (date, step) => {
+ date.setTime(+date + step * k);
+ }, (start, end) => {
+ return (end - start) / k;
+ });
+};
+
+const milliseconds = millisecond.range;
+
+const durationSecond = 1000;
+const durationMinute = durationSecond * 60;
+const durationHour = durationMinute * 60;
+const durationDay = durationHour * 24;
+const durationWeek = durationDay * 7;
+const durationMonth = durationDay * 30;
+const durationYear = durationDay * 365;
+
+const second = timeInterval((date) => {
+ date.setTime(date - date.getMilliseconds());
+}, (date, step) => {
+ date.setTime(+date + step * durationSecond);
+}, (start, end) => {
+ return (end - start) / durationSecond;
+}, (date) => {
+ return date.getUTCSeconds();
+});
+
+const seconds = second.range;
+
+const timeMinute = timeInterval((date) => {
+ date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond);
+}, (date, step) => {
+ date.setTime(+date + step * durationMinute);
+}, (start, end) => {
+ return (end - start) / durationMinute;
+}, (date) => {
+ return date.getMinutes();
+});
+
+const timeMinutes = timeMinute.range;
+
+const utcMinute = timeInterval((date) => {
+ date.setUTCSeconds(0, 0);
+}, (date, step) => {
+ date.setTime(+date + step * durationMinute);
+}, (start, end) => {
+ return (end - start) / durationMinute;
+}, (date) => {
+ return date.getUTCMinutes();
+});
+
+const utcMinutes = utcMinute.range;
+
+const timeHour = timeInterval((date) => {
+ date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond - date.getMinutes() * durationMinute);
+}, (date, step) => {
+ date.setTime(+date + step * durationHour);
+}, (start, end) => {
+ return (end - start) / durationHour;
+}, (date) => {
+ return date.getHours();
+});
+
+const timeHours = timeHour.range;
+
+const utcHour = timeInterval((date) => {
+ date.setUTCMinutes(0, 0, 0);
+}, (date, step) => {
+ date.setTime(+date + step * durationHour);
+}, (start, end) => {
+ return (end - start) / durationHour;
+}, (date) => {
+ return date.getUTCHours();
+});
+
+const utcHours = utcHour.range;
+
+const timeDay = timeInterval(
+ date => date.setHours(0, 0, 0, 0),
+ (date, step) => date.setDate(date.getDate() + step),
+ (start, end) => (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationDay,
+ date => date.getDate() - 1
+);
+
+const timeDays = timeDay.range;
+
+const utcDay = timeInterval((date) => {
+ date.setUTCHours(0, 0, 0, 0);
+}, (date, step) => {
+ date.setUTCDate(date.getUTCDate() + step);
+}, (start, end) => {
+ return (end - start) / durationDay;
+}, (date) => {
+ return date.getUTCDate() - 1;
+});
+
+const utcDays = utcDay.range;
+
+const unixDay = timeInterval((date) => {
+ date.setUTCHours(0, 0, 0, 0);
+}, (date, step) => {
+ date.setUTCDate(date.getUTCDate() + step);
+}, (start, end) => {
+ return (end - start) / durationDay;
+}, (date) => {
+ return Math.floor(date / durationDay);
+});
+
+const unixDays = unixDay.range;
+
+function timeWeekday(i) {
+ return timeInterval((date) => {
+ date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7);
+ date.setHours(0, 0, 0, 0);
+ }, (date, step) => {
+ date.setDate(date.getDate() + step * 7);
+ }, (start, end) => {
+ return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationWeek;
+ });
+}
+
+const timeSunday = timeWeekday(0);
+const timeMonday = timeWeekday(1);
+const timeTuesday = timeWeekday(2);
+const timeWednesday = timeWeekday(3);
+const timeThursday = timeWeekday(4);
+const timeFriday = timeWeekday(5);
+const timeSaturday = timeWeekday(6);
+
+const timeSundays = timeSunday.range;
+const timeMondays = timeMonday.range;
+const timeTuesdays = timeTuesday.range;
+const timeWednesdays = timeWednesday.range;
+const timeThursdays = timeThursday.range;
+const timeFridays = timeFriday.range;
+const timeSaturdays = timeSaturday.range;
+
+function utcWeekday(i) {
+ return timeInterval((date) => {
+ date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7);
+ date.setUTCHours(0, 0, 0, 0);
+ }, (date, step) => {
+ date.setUTCDate(date.getUTCDate() + step * 7);
+ }, (start, end) => {
+ return (end - start) / durationWeek;
+ });
+}
+
+const utcSunday = utcWeekday(0);
+const utcMonday = utcWeekday(1);
+const utcTuesday = utcWeekday(2);
+const utcWednesday = utcWeekday(3);
+const utcThursday = utcWeekday(4);
+const utcFriday = utcWeekday(5);
+const utcSaturday = utcWeekday(6);
+
+const utcSundays = utcSunday.range;
+const utcMondays = utcMonday.range;
+const utcTuesdays = utcTuesday.range;
+const utcWednesdays = utcWednesday.range;
+const utcThursdays = utcThursday.range;
+const utcFridays = utcFriday.range;
+const utcSaturdays = utcSaturday.range;
+
+const timeMonth = timeInterval((date) => {
+ date.setDate(1);
+ date.setHours(0, 0, 0, 0);
+}, (date, step) => {
+ date.setMonth(date.getMonth() + step);
+}, (start, end) => {
+ return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12;
+}, (date) => {
+ return date.getMonth();
+});
+
+const timeMonths = timeMonth.range;
+
+const utcMonth = timeInterval((date) => {
+ date.setUTCDate(1);
+ date.setUTCHours(0, 0, 0, 0);
+}, (date, step) => {
+ date.setUTCMonth(date.getUTCMonth() + step);
+}, (start, end) => {
+ return end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12;
+}, (date) => {
+ return date.getUTCMonth();
+});
+
+const utcMonths = utcMonth.range;
+
+const timeYear = timeInterval((date) => {
+ date.setMonth(0, 1);
+ date.setHours(0, 0, 0, 0);
+}, (date, step) => {
+ date.setFullYear(date.getFullYear() + step);
+}, (start, end) => {
+ return end.getFullYear() - start.getFullYear();
+}, (date) => {
+ return date.getFullYear();
+});
+
+// An optimized implementation for this simple case.
+timeYear.every = (k) => {
+ return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : timeInterval((date) => {
+ date.setFullYear(Math.floor(date.getFullYear() / k) * k);
+ date.setMonth(0, 1);
+ date.setHours(0, 0, 0, 0);
+ }, (date, step) => {
+ date.setFullYear(date.getFullYear() + step * k);
+ });
+};
+
+const timeYears = timeYear.range;
+
+const utcYear = timeInterval((date) => {
+ date.setUTCMonth(0, 1);
+ date.setUTCHours(0, 0, 0, 0);
+}, (date, step) => {
+ date.setUTCFullYear(date.getUTCFullYear() + step);
+}, (start, end) => {
+ return end.getUTCFullYear() - start.getUTCFullYear();
+}, (date) => {
+ return date.getUTCFullYear();
+});
+
+// An optimized implementation for this simple case.
+utcYear.every = (k) => {
+ return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : timeInterval((date) => {
+ date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k);
+ date.setUTCMonth(0, 1);
+ date.setUTCHours(0, 0, 0, 0);
+ }, (date, step) => {
+ date.setUTCFullYear(date.getUTCFullYear() + step * k);
+ });
+};
+
+const utcYears = utcYear.range;
+
+function ticker(year, month, week, day, hour, minute) {
+
+ const tickIntervals = [
+ [second, 1, durationSecond],
+ [second, 5, 5 * durationSecond],
+ [second, 15, 15 * durationSecond],
+ [second, 30, 30 * durationSecond],
+ [minute, 1, durationMinute],
+ [minute, 5, 5 * durationMinute],
+ [minute, 15, 15 * durationMinute],
+ [minute, 30, 30 * durationMinute],
+ [ hour, 1, durationHour ],
+ [ hour, 3, 3 * durationHour ],
+ [ hour, 6, 6 * durationHour ],
+ [ hour, 12, 12 * durationHour ],
+ [ day, 1, durationDay ],
+ [ day, 2, 2 * durationDay ],
+ [ week, 1, durationWeek ],
+ [ month, 1, durationMonth ],
+ [ month, 3, 3 * durationMonth ],
+ [ year, 1, durationYear ]
+ ];
+
+ function ticks(start, stop, count) {
+ const reverse = stop < start;
+ if (reverse) [start, stop] = [stop, start];
+ const interval = count && typeof count.range === "function" ? count : tickInterval(start, stop, count);
+ const ticks = interval ? interval.range(start, +stop + 1) : []; // inclusive stop
+ return reverse ? ticks.reverse() : ticks;
+ }
+
+ function tickInterval(start, stop, count) {
+ const target = Math.abs(stop - start) / count;
+ const i = d3Array.bisector(([,, step]) => step).right(tickIntervals, target);
+ if (i === tickIntervals.length) return year.every(d3Array.tickStep(start / durationYear, stop / durationYear, count));
+ if (i === 0) return millisecond.every(Math.max(d3Array.tickStep(start, stop, count), 1));
+ const [t, step] = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i];
+ return t.every(step);
+ }
+
+ return [ticks, tickInterval];
+}
+
+const [utcTicks, utcTickInterval] = ticker(utcYear, utcMonth, utcSunday, unixDay, utcHour, utcMinute);
+const [timeTicks, timeTickInterval] = ticker(timeYear, timeMonth, timeSunday, timeDay, timeHour, timeMinute);
+
+exports.timeDay = timeDay;
+exports.timeDays = timeDays;
+exports.timeFriday = timeFriday;
+exports.timeFridays = timeFridays;
+exports.timeHour = timeHour;
+exports.timeHours = timeHours;
+exports.timeInterval = timeInterval;
+exports.timeMillisecond = millisecond;
+exports.timeMilliseconds = milliseconds;
+exports.timeMinute = timeMinute;
+exports.timeMinutes = timeMinutes;
+exports.timeMonday = timeMonday;
+exports.timeMondays = timeMondays;
+exports.timeMonth = timeMonth;
+exports.timeMonths = timeMonths;
+exports.timeSaturday = timeSaturday;
+exports.timeSaturdays = timeSaturdays;
+exports.timeSecond = second;
+exports.timeSeconds = seconds;
+exports.timeSunday = timeSunday;
+exports.timeSundays = timeSundays;
+exports.timeThursday = timeThursday;
+exports.timeThursdays = timeThursdays;
+exports.timeTickInterval = timeTickInterval;
+exports.timeTicks = timeTicks;
+exports.timeTuesday = timeTuesday;
+exports.timeTuesdays = timeTuesdays;
+exports.timeWednesday = timeWednesday;
+exports.timeWednesdays = timeWednesdays;
+exports.timeWeek = timeSunday;
+exports.timeWeeks = timeSundays;
+exports.timeYear = timeYear;
+exports.timeYears = timeYears;
+exports.unixDay = unixDay;
+exports.unixDays = unixDays;
+exports.utcDay = utcDay;
+exports.utcDays = utcDays;
+exports.utcFriday = utcFriday;
+exports.utcFridays = utcFridays;
+exports.utcHour = utcHour;
+exports.utcHours = utcHours;
+exports.utcMillisecond = millisecond;
+exports.utcMilliseconds = milliseconds;
+exports.utcMinute = utcMinute;
+exports.utcMinutes = utcMinutes;
+exports.utcMonday = utcMonday;
+exports.utcMondays = utcMondays;
+exports.utcMonth = utcMonth;
+exports.utcMonths = utcMonths;
+exports.utcSaturday = utcSaturday;
+exports.utcSaturdays = utcSaturdays;
+exports.utcSecond = second;
+exports.utcSeconds = seconds;
+exports.utcSunday = utcSunday;
+exports.utcSundays = utcSundays;
+exports.utcThursday = utcThursday;
+exports.utcThursdays = utcThursdays;
+exports.utcTickInterval = utcTickInterval;
+exports.utcTicks = utcTicks;
+exports.utcTuesday = utcTuesday;
+exports.utcTuesdays = utcTuesdays;
+exports.utcWednesday = utcWednesday;
+exports.utcWednesdays = utcWednesdays;
+exports.utcWeek = utcSunday;
+exports.utcWeeks = utcSundays;
+exports.utcYear = utcYear;
+exports.utcYears = utcYears;
+
+}));
diff --git a/node_modules/d3-time/dist/d3-time.min.js b/node_modules/d3-time/dist/d3-time.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..27b04dbbd76f57b75433ba3162fdfa1f0d3b6fe0
--- /dev/null
+++ b/node_modules/d3-time/dist/d3-time.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-time/ v3.1.0 Copyright 2010-2022 Mike Bostock
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("d3-array")):"function"==typeof define&&define.amd?define(["exports","d3-array"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).d3=e.d3||{},e.d3)}(this,(function(e,t){"use strict";const n=new Date,s=new Date;function r(e,t,a,u){function i(t){return e(t=0===arguments.length?new Date:new Date(+t)),t}return i.floor=t=>(e(t=new Date(+t)),t),i.ceil=n=>(e(n=new Date(n-1)),t(n,1),e(n),n),i.round=e=>{const t=i(e),n=i.ceil(e);return e-t0))return a;let u;do{a.push(u=new Date(+n)),t(n,r),e(n)}while(u