From 2014c63e2237b02178609df91789c11056e21a96 Mon Sep 17 00:00:00 2001 From: howlingsails Date: Sat, 4 Dec 2021 18:13:59 -0800 Subject: [PATCH] thecrack --- .DS_Store | Bin 0 -> 6148 bytes ._.DS_Store | Bin 0 -> 4096 bytes .gitignore | 4 +- index.html | 4 +- libs/.DS_Store | Bin 0 -> 6148 bytes libs/._.DS_Store | Bin 0 -> 4096 bytes libs/._d3-7.1.1.tgz | Bin 0 -> 4096 bytes libs/._d3.js | Bin 0 -> 4096 bytes libs/d3-7.1.1.tgz | Bin 0 -> 267356 bytes libs/d3.js | 20126 +++++++++++++++++++++++++++++++ main.js | 2792 ++--- map.sh | 2 + modules/burgs-and-states.js | 56 +- modules/cultures-generator.js | 287 +- modules/religions-generator.js | 1 + modules/river-generator.js | 4 + modules/ui/burg-editor.js | 4 +- 17 files changed, 21717 insertions(+), 1563 deletions(-) create mode 100644 .DS_Store create mode 100644 ._.DS_Store create mode 100644 libs/.DS_Store create mode 100644 libs/._.DS_Store create mode 100644 libs/._d3-7.1.1.tgz create mode 100644 libs/._d3.js create mode 100644 libs/d3-7.1.1.tgz create mode 100644 libs/d3.js create mode 100644 map.sh diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..8cc10e81160022851ee56974675e6f5f82b6ceea GIT binary patch literal 6148 zcmZQzU|@7AO)+F(5MW?n;9!8zOq>i@0Z1N%F(jFwBCH_uz-APu6es5-<>%)xLZwEj zK^_92xMO9AXUJtpWGG-ji9aOavf!e;ocz3WNJKNRF=T=@q%))W)=oI3Wf$ornR-49O9~mww?*Ol~vU>wRO`$ z?q^_Ngr!`52p>+)U|?W?dk-x<;EF~WqaiRF0;3@?G(rGc)NybR4d;%!ax?@+Lx7GU z04g68piMppDBS>|K~fBi3=H5d03)bn1a%i9xF5g(k^^Z4(IBlL8l;th5yS$U0oKaE z$iM>D$q4R-fb@a7Bp@2Boq>@7tet_80jwR~K4XMvXJCYAXJCZ(P#7WF85kkj85kkj z!FG%iqaiRF0*DY`hA;&{^}j0v1Frr*MAaxc8UmvsFf2oWk;Nt0#R*&~WA`7Zt_9Vn z2~cTJ?GLJs8A0_lLJV9LGeHIvC7{Bf>K>#OM1!khMg~YtKH3m~h0rKH8UpkW0RXcr BU~~Wg literal 0 HcmV?d00001 diff --git a/._.DS_Store b/._.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..8e82ed96c0d694f6a640da6c163a3ef7e4194513 GIT binary patch literal 4096 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3Cj$e65d#C?1_lNYpYIU^1EU;Nfr5ho0}kLA z5)#C~z`)4B0MfxwfkWA-@Ms8(hQMeDjE2By2#kinXb6mkz-S1JhQMeDjE2By2v9Wy z7$Kceh?#OB8JWcjMXAO4rA5i93TgR8*$SC?C8>EOnfZB%IXRUIIjLzS3Q0MMdD#jI U3J^_0n?&_L+%GZ=a{vDW0Os=?*8l(j literal 0 HcmV?d00001 diff --git a/.gitignore b/.gitignore index eb169d8d..64c29625 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .bat -.vscode \ No newline at end of file +.vscode +.idea +_maps diff --git a/index.html b/index.html index b8d13e3e..378d88a5 100644 --- a/index.html +++ b/index.html @@ -1098,10 +1098,10 @@ Growth rate - + - + diff --git a/libs/.DS_Store b/libs/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..e01cc83cf4769df245f5537c3bc658eb95499c25 GIT binary patch literal 6148 zcmZQzU|@7AO)+F(5MW?n;9!8z3~dZp0Z1N%F(jFwB8(vOz-A;eq%)*4C@>g#=0N2L zQ6RmX3XEDs!?(@1V%$( zScU*2i%YPJ6Sz{w?mtjn3#v~OplS|4l`(?qWr!F^38-oZSI10{K}89uGLSe(JBS8X X$BYaN;M#n&F#rppQF=54=o$Vqox1Ojhs@R)|o50+1L3Cj$e65d#C?1_lNYpYIU^1EU;Nfr5ho0}kLA z5)#C~z`)4B0MfxwfkWA-@Ms8(hQMeDjE2By2#kinXb6mkz-S1JhQMeDjE2By2v9Wy z7$Kceh?#OB8JWcjMXAO4rA5i93TgR8*$SC?C8>EOnfZB%IXRUIIjLzS3Q0MMdD#jI U3J^_0n?&_L+%GZ=a{vDW0Os=?*8l(j literal 0 HcmV?d00001 diff --git a/libs/._d3-7.1.1.tgz b/libs/._d3-7.1.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..fffed19c74a7d335cd8bd1e5e39d72af52d34a59 GIT binary patch literal 4096 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3Cj$e65d#C?1_lNYpYIU^1EU-RLEsn?62!p3 zz{tP=(!ubAfq~%@nkHrj2C%p#1A}OCey(0(K|xNcUSVlsQDR<6W?m{tyDS3(g9ifx zKSDk?F*%39)P#Y75u~7yfk72XF0~{vC9x#YD%;n^vm`Y)JR`Lz)vYK$x0u1ez{1el z%+Mk!EjcyG+Bu^rKR4Cd+|1F`%+$n4*UZt(K-a|5$Vk`H)zm`Q+||I%#nIKx$=S?= znITrM|L22OZWk989m^44Gcy3q8$@!G3UV@wOAHJaF*3yq=wy_X6ck(O>ldY_XBL+f zRqEvxZcg%n(GVFcMt}91JQq% JVUYX(9{|NWYw7?1 literal 0 HcmV?d00001 diff --git a/libs/._d3.js b/libs/._d3.js new file mode 100644 index 0000000000000000000000000000000000000000..0a1ed9a0dd56904754e328c4a2e43c7f858b103e GIT binary patch literal 4096 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3Cj$e65d#C?1_lNYpYIU^1EU-RLEsn?62!p3 zz{tP=(!nr;fq}siO%o#n158{rIX_n~v7jI)Rj;r#u_!UGBr`9S!N9=6(AvzC#L~z}*V5J0Lf72Yz|FJ-%mmG%QSN96 zjE2By2#kinXb6mkz-S1JhQMeDjE2By2#kin$O!>ZXA^|MK9&o~$ShVUN-fSWElN&R zNXswER>;gNNzE(C%+E{A$*EMxNlhzJNXkjf%T`cO0P7jz1jz3o4E6@1|1QHI_y0ct DQqeO9 literal 0 HcmV?d00001 diff --git a/libs/d3-7.1.1.tgz b/libs/d3-7.1.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..e6adc2125de2c41e68520144d2ac7d0f8a1208e3 GIT binary patch literal 267356 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%0AIv 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

ry4e+p8ctlv;@bu4~ed-K*O-cffUpl`b?c2_0 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℘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 CD`FV{ literal 0 HcmV?d00001 diff --git a/libs/d3.js b/libs/d3.js new file mode 100644 index 00000000..b9215f8c --- /dev/null +++ b/libs/d3.js @@ -0,0 +1,20126 @@ +// https://d3js.org v7.1.1 Copyright 2010-2021 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'; + +var version = "7.1.1"; + +function ascending$3(a, b) { + return a == null || b == null ? NaN : a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; +} + +function bisector(f) { + let delta = f; + let compare1 = f; + let compare2 = f; + + if (f.length !== 2) { + delta = (d, x) => f(d) - x; + compare1 = ascending$3; + compare2 = (d, x) => ascending$3(f(d), x); + } + + function left(a, x, lo = 0, hi = a.length) { + if (lo < hi) { + if (compare1(x, x) !== 0) return hi; + do { + const mid = (lo + hi) >>> 1; + if (compare2(a[mid], x) < 0) lo = mid + 1; + else hi = mid; + } while (lo < hi); + } + return lo; + } + + function right(a, x, lo = 0, hi = a.length) { + if (lo < hi) { + if (compare1(x, x) !== 0) return hi; + do { + const mid = (lo + hi) >>> 1; + if (compare2(a[mid], x) <= 0) lo = mid + 1; + else hi = mid; + } while (lo < hi); + } + return lo; + } + + function center(a, x, lo = 0, hi = a.length) { + const i = left(a, x, lo, hi - 1); + return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i; + } + + return {left, center, right}; +} + +function number$3(x) { + return x === null ? NaN : +x; +} + +function* numbers(values, valueof) { + if (valueof === undefined) { + for (let value of values) { + if (value != null && (value = +value) >= value) { + yield value; + } + } + } else { + let index = -1; + for (let value of values) { + if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) { + yield value; + } + } + } +} + +const ascendingBisect = bisector(ascending$3); +const bisectRight = ascendingBisect.right; +const bisectLeft = ascendingBisect.left; +const bisectCenter = bisector(number$3).center; +var bisect = bisectRight; + +function count$1(values, valueof) { + let count = 0; + if (valueof === undefined) { + for (let value of values) { + if (value != null && (value = +value) >= value) { + ++count; + } + } + } else { + let index = -1; + for (let value of values) { + if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) { + ++count; + } + } + } + return count; +} + +function length$3(array) { + return array.length | 0; +} + +function empty$2(length) { + return !(length > 0); +} + +function arrayify(values) { + return typeof values !== "object" || "length" in values ? values : Array.from(values); +} + +function reducer(reduce) { + return values => reduce(...values); +} + +function cross$2(...values) { + const reduce = typeof values[values.length - 1] === "function" && reducer(values.pop()); + values = values.map(arrayify); + const lengths = values.map(length$3); + const j = values.length - 1; + const index = new Array(j + 1).fill(0); + const product = []; + if (j < 0 || lengths.some(empty$2)) return product; + while (true) { + product.push(index.map((j, i) => values[i][j])); + let i = j; + while (++index[i] === lengths[i]) { + if (i === 0) return reduce ? product.map(reduce) : product; + index[i--] = 0; + } + } +} + +function cumsum(values, valueof) { + var sum = 0, index = 0; + return Float64Array.from(values, valueof === undefined + ? v => (sum += +v || 0) + : v => (sum += +valueof(v, index++, values) || 0)); +} + +function descending$2(a, b) { + return a == null || b == null ? NaN + : b < a ? -1 + : b > a ? 1 + : b >= a ? 0 + : NaN; +} + +function variance(values, valueof) { + let count = 0; + let delta; + let mean = 0; + let sum = 0; + if (valueof === undefined) { + for (let value of values) { + if (value != null && (value = +value) >= value) { + delta = value - mean; + mean += delta / ++count; + sum += delta * (value - mean); + } + } + } else { + let index = -1; + for (let value of values) { + if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) { + delta = value - mean; + mean += delta / ++count; + sum += delta * (value - mean); + } + } + } + if (count > 1) return sum / (count - 1); +} + +function deviation(values, valueof) { + const v = variance(values, valueof); + return v ? Math.sqrt(v) : v; +} + +function extent$1(values, valueof) { + let min; + let max; + if (valueof === undefined) { + for (const value of values) { + if (value != null) { + if (min === undefined) { + if (value >= value) min = max = value; + } else { + if (min > value) min = value; + if (max < value) max = value; + } + } + } + } else { + let index = -1; + for (let value of values) { + if ((value = valueof(value, ++index, values)) != null) { + if (min === undefined) { + if (value >= value) min = max = value; + } else { + if (min > value) min = value; + if (max < value) max = value; + } + } + } + } + return [min, max]; +} + +// https://github.com/python/cpython/blob/a74eea238f5baba15797e2e8b570d153bc8690a7/Modules/mathmodule.c#L1423 +class Adder { + constructor() { + this._partials = new Float64Array(32); + this._n = 0; + } + add(x) { + const p = this._partials; + let i = 0; + for (let j = 0; j < this._n && j < 32; j++) { + const y = p[j], + hi = x + y, + lo = Math.abs(x) < Math.abs(y) ? x - (hi - y) : y - (hi - x); + if (lo) p[i++] = lo; + x = hi; + } + p[i] = x; + this._n = i + 1; + return this; + } + valueOf() { + const p = this._partials; + let n = this._n, x, y, lo, hi = 0; + if (n > 0) { + hi = p[--n]; + while (n > 0) { + x = hi; + y = p[--n]; + hi = x + y; + lo = y - (hi - x); + if (lo) break; + } + if (n > 0 && ((lo < 0 && p[n - 1] < 0) || (lo > 0 && p[n - 1] > 0))) { + y = lo * 2; + x = hi + y; + if (y == x - hi) hi = x; + } + } + return hi; + } +} + +function fsum(values, valueof) { + const adder = new Adder(); + if (valueof === undefined) { + for (let value of values) { + if (value = +value) { + adder.add(value); + } + } + } else { + let index = -1; + for (let value of values) { + if (value = +valueof(value, ++index, values)) { + adder.add(value); + } + } + } + return +adder; +} + +function fcumsum(values, valueof) { + const adder = new Adder(); + let index = -1; + return Float64Array.from(values, valueof === undefined + ? v => adder.add(+v || 0) + : v => adder.add(+valueof(v, ++index, values) || 0) + ); +} + +class InternMap extends Map { + constructor(entries, key = keyof) { + super(); + Object.defineProperties(this, {_intern: {value: new Map()}, _key: {value: key}}); + if (entries != null) for (const [key, value] of entries) this.set(key, value); + } + get(key) { + return super.get(intern_get(this, key)); + } + has(key) { + return super.has(intern_get(this, key)); + } + set(key, value) { + return super.set(intern_set(this, key), value); + } + delete(key) { + return super.delete(intern_delete(this, key)); + } +} + +class InternSet extends Set { + constructor(values, key = keyof) { + super(); + Object.defineProperties(this, {_intern: {value: new Map()}, _key: {value: key}}); + if (values != null) for (const value of values) this.add(value); + } + has(value) { + return super.has(intern_get(this, value)); + } + add(value) { + return super.add(intern_set(this, value)); + } + delete(value) { + return super.delete(intern_delete(this, value)); + } +} + +function intern_get({_intern, _key}, value) { + const key = _key(value); + return _intern.has(key) ? _intern.get(key) : value; +} + +function intern_set({_intern, _key}, value) { + const key = _key(value); + if (_intern.has(key)) return _intern.get(key); + _intern.set(key, value); + return value; +} + +function intern_delete({_intern, _key}, value) { + const key = _key(value); + if (_intern.has(key)) { + value = _intern.get(key); + _intern.delete(key); + } + return value; +} + +function keyof(value) { + return value !== null && typeof value === "object" ? value.valueOf() : value; +} + +function identity$9(x) { + return x; +} + +function group(values, ...keys) { + return nest(values, identity$9, identity$9, keys); +} + +function groups(values, ...keys) { + return nest(values, Array.from, identity$9, keys); +} + +function flatten$1(groups, keys) { + for (let i = 1, n = keys.length; i < n; ++i) { + groups = groups.flatMap(g => g.pop().map(([key, value]) => [...g, key, value])); + } + return groups; +} + +function flatGroup(values, ...keys) { + return flatten$1(groups(values, ...keys), keys); +} + +function flatRollup(values, reduce, ...keys) { + return flatten$1(rollups(values, reduce, ...keys), keys); +} + +function rollup(values, reduce, ...keys) { + return nest(values, identity$9, reduce, keys); +} + +function rollups(values, reduce, ...keys) { + return nest(values, Array.from, reduce, keys); +} + +function index$4(values, ...keys) { + return nest(values, identity$9, unique, keys); +} + +function indexes(values, ...keys) { + return nest(values, Array.from, unique, keys); +} + +function unique(values) { + if (values.length !== 1) throw new Error("duplicate key"); + return values[0]; +} + +function nest(values, map, reduce, keys) { + return (function regroup(values, i) { + if (i >= keys.length) return reduce(values); + const groups = new InternMap(); + const keyof = keys[i++]; + let index = -1; + for (const value of values) { + const key = keyof(value, ++index, values); + const group = groups.get(key); + if (group) group.push(value); + else groups.set(key, [value]); + } + for (const [key, values] of groups) { + groups.set(key, regroup(values, i)); + } + return map(groups); + })(values, 0); +} + +function permute(source, keys) { + return Array.from(keys, key => source[key]); +} + +function sort(values, ...F) { + if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable"); + values = Array.from(values); + let [f] = F; + if ((f && f.length !== 2) || F.length > 1) { + const index = Uint32Array.from(values, (d, i) => i); + if (F.length > 1) { + F = F.map(f => values.map(f)); + index.sort((i, j) => { + for (const f of F) { + const c = ascendingDefined(f[i], f[j]); + if (c) return c; + } + }); + } else { + f = values.map(f); + index.sort((i, j) => ascendingDefined(f[i], f[j])); + } + return permute(values, index); + } + return values.sort(compareDefined(f)); +} + +function compareDefined(compare = ascending$3) { + if (compare === ascending$3) return ascendingDefined; + if (typeof compare !== "function") throw new TypeError("compare is not a function"); + return (a, b) => { + const x = compare(a, b); + if (x || x === 0) return x; + return (compare(b, b) === 0) - (compare(a, a) === 0); + }; +} + +function ascendingDefined(a, b) { + return (a == null || !(a >= a)) - (b == null || !(b >= b)) || (a < b ? -1 : a > b ? 1 : 0); +} + +function groupSort(values, reduce, key) { + return (reduce.length !== 2 + ? sort(rollup(values, reduce, key), (([ak, av], [bk, bv]) => ascending$3(av, bv) || ascending$3(ak, bk))) + : sort(group(values, key), (([ak, av], [bk, bv]) => reduce(av, bv) || ascending$3(ak, bk)))) + .map(([key]) => key); +} + +var array$5 = Array.prototype; + +var slice$3 = array$5.slice; + +function constant$b(x) { + return () => x; +} + +var e10 = Math.sqrt(50), + e5 = Math.sqrt(10), + e2 = Math.sqrt(2); + +function ticks(start, stop, count) { + var reverse, + i = -1, + n, + ticks, + step; + + stop = +stop, start = +start, count = +count; + if (start === stop && count > 0) return [start]; + if (reverse = stop < start) n = start, start = stop, stop = n; + if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return []; + + if (step > 0) { + let r0 = Math.round(start / step), r1 = Math.round(stop / step); + if (r0 * step < start) ++r0; + if (r1 * step > stop) --r1; + ticks = new Array(n = r1 - r0 + 1); + while (++i < n) ticks[i] = (r0 + i) * step; + } else { + step = -step; + let r0 = Math.round(start * step), r1 = Math.round(stop * step); + if (r0 / step < start) ++r0; + if (r1 / step > stop) --r1; + ticks = new Array(n = r1 - r0 + 1); + while (++i < n) ticks[i] = (r0 + i) / step; + } + + if (reverse) ticks.reverse(); + + return ticks; +} + +function tickIncrement(start, stop, count) { + var step = (stop - start) / Math.max(0, count), + power = Math.floor(Math.log(step) / Math.LN10), + error = step / Math.pow(10, power); + return power >= 0 + ? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power) + : -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1); +} + +function tickStep(start, stop, count) { + var step0 = Math.abs(stop - start) / Math.max(0, count), + step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)), + error = step0 / step1; + if (error >= e10) step1 *= 10; + else if (error >= e5) step1 *= 5; + else if (error >= e2) step1 *= 2; + return stop < start ? -step1 : step1; +} + +function nice$1(start, stop, count) { + let prestep; + while (true) { + const step = tickIncrement(start, stop, count); + if (step === prestep || step === 0 || !isFinite(step)) { + return [start, stop]; + } 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; + } + prestep = step; + } +} + +function thresholdSturges(values) { + return Math.ceil(Math.log(count$1(values)) / Math.LN2) + 1; +} + +function bin() { + var value = identity$9, + domain = extent$1, + threshold = thresholdSturges; + + function histogram(data) { + if (!Array.isArray(data)) data = Array.from(data); + + var i, + n = data.length, + x, + values = new Array(n); + + for (i = 0; i < n; ++i) { + values[i] = value(data[i], i, data); + } + + var xz = domain(values), + x0 = xz[0], + x1 = xz[1], + tz = threshold(values, x0, x1); + + // Convert number of thresholds into uniform thresholds, and nice the + // default domain accordingly. + if (!Array.isArray(tz)) { + const max = x1, tn = +tz; + if (domain === extent$1) [x0, x1] = nice$1(x0, x1, tn); + tz = ticks(x0, x1, tn); + + // If the last threshold is coincident with the domain’s upper bound, the + // last bin will be zero-width. If the default domain is used, and this + // last threshold is coincident with the maximum input value, we can + // extend the niced upper bound by one tick to ensure uniform bin widths; + // otherwise, we simply remove the last threshold. Note that we don’t + // coerce values or the domain to numbers, and thus must be careful to + // compare order (>=) rather than strict equality (===)! + if (tz[tz.length - 1] >= x1) { + if (max >= x1 && domain === extent$1) { + const step = tickIncrement(x0, x1, tn); + if (isFinite(step)) { + if (step > 0) { + x1 = (Math.floor(x1 / step) + 1) * step; + } else if (step < 0) { + x1 = (Math.ceil(x1 * -step) + 1) / -step; + } + } + } else { + tz.pop(); + } + } + } + + // Remove any thresholds outside the domain. + var m = tz.length; + while (tz[0] <= x0) tz.shift(), --m; + while (tz[m - 1] > x1) tz.pop(), --m; + + var bins = new Array(m + 1), + bin; + + // Initialize bins. + for (i = 0; i <= m; ++i) { + bin = bins[i] = []; + bin.x0 = i > 0 ? tz[i - 1] : x0; + bin.x1 = i < m ? tz[i] : x1; + } + + // Assign data to bins by value, ignoring any outside the domain. + for (i = 0; i < n; ++i) { + x = values[i]; + if (x != null && x0 <= x && x <= x1) { + bins[bisect(tz, x, 0, m)].push(data[i]); + } + } + + return bins; + } + + histogram.value = function(_) { + return arguments.length ? (value = typeof _ === "function" ? _ : constant$b(_), histogram) : value; + }; + + histogram.domain = function(_) { + return arguments.length ? (domain = typeof _ === "function" ? _ : constant$b([_[0], _[1]]), histogram) : domain; + }; + + histogram.thresholds = function(_) { + return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant$b(slice$3.call(_)) : constant$b(_), histogram) : threshold; + }; + + return histogram; +} + +function max$3(values, valueof) { + let max; + if (valueof === undefined) { + for (const value of values) { + if (value != null + && (max < value || (max === undefined && value >= value))) { + max = value; + } + } + } else { + let index = -1; + for (let value of values) { + if ((value = valueof(value, ++index, values)) != null + && (max < value || (max === undefined && value >= value))) { + max = value; + } + } + } + return max; +} + +function min$2(values, valueof) { + let min; + if (valueof === undefined) { + for (const value of values) { + if (value != null + && (min > value || (min === undefined && value >= value))) { + min = value; + } + } + } else { + let index = -1; + for (let value of values) { + if ((value = valueof(value, ++index, values)) != null + && (min > value || (min === undefined && value >= value))) { + min = value; + } + } + } + return min; +} + +// Based on https://github.com/mourner/quickselect +// ISC license, Copyright 2018 Vladimir Agafonkin. +function quickselect(array, k, left = 0, right = array.length - 1, compare) { + compare = compare === undefined ? ascendingDefined : compareDefined(compare); + + while (right > left) { + if (right - left > 600) { + const n = right - left + 1; + const m = k - left + 1; + const z = Math.log(n); + const s = 0.5 * Math.exp(2 * z / 3); + const sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1); + const newLeft = Math.max(left, Math.floor(k - m * s / n + sd)); + const newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd)); + quickselect(array, k, newLeft, newRight, compare); + } + + const t = array[k]; + let i = left; + let j = right; + + swap$1(array, left, k); + if (compare(array[right], t) > 0) swap$1(array, left, right); + + while (i < j) { + swap$1(array, i, j), ++i, --j; + while (compare(array[i], t) < 0) ++i; + while (compare(array[j], t) > 0) --j; + } + + if (compare(array[left], t) === 0) swap$1(array, left, j); + else ++j, swap$1(array, j, right); + + if (j <= k) left = j + 1; + if (k <= j) right = j - 1; + } + return array; +} + +function swap$1(array, i, j) { + const t = array[i]; + array[i] = array[j]; + array[j] = t; +} + +function quantile$1(values, p, valueof) { + values = Float64Array.from(numbers(values, valueof)); + if (!(n = values.length)) return; + if ((p = +p) <= 0 || n < 2) return min$2(values); + if (p >= 1) return max$3(values); + var n, + i = (n - 1) * p, + i0 = Math.floor(i), + value0 = max$3(quickselect(values, i0).subarray(0, i0 + 1)), + value1 = min$2(values.subarray(i0 + 1)); + return value0 + (value1 - value0) * (i - i0); +} + +function quantileSorted(values, p, valueof = number$3) { + if (!(n = values.length)) return; + if ((p = +p) <= 0 || n < 2) return +valueof(values[0], 0, values); + if (p >= 1) return +valueof(values[n - 1], n - 1, values); + var n, + i = (n - 1) * p, + i0 = Math.floor(i), + value0 = +valueof(values[i0], i0, values), + value1 = +valueof(values[i0 + 1], i0 + 1, values); + return value0 + (value1 - value0) * (i - i0); +} + +function thresholdFreedmanDiaconis(values, min, max) { + return Math.ceil((max - min) / (2 * (quantile$1(values, 0.75) - quantile$1(values, 0.25)) * Math.pow(count$1(values), -1 / 3))); +} + +function thresholdScott(values, min, max) { + return Math.ceil((max - min) / (3.5 * deviation(values) * Math.pow(count$1(values), -1 / 3))); +} + +function maxIndex(values, valueof) { + let max; + let maxIndex = -1; + let index = -1; + if (valueof === undefined) { + for (const value of values) { + ++index; + if (value != null + && (max < value || (max === undefined && value >= value))) { + max = value, maxIndex = index; + } + } + } else { + for (let value of values) { + if ((value = valueof(value, ++index, values)) != null + && (max < value || (max === undefined && value >= value))) { + max = value, maxIndex = index; + } + } + } + return maxIndex; +} + +function mean(values, valueof) { + let count = 0; + let sum = 0; + if (valueof === undefined) { + for (let value of values) { + if (value != null && (value = +value) >= value) { + ++count, sum += value; + } + } + } else { + let index = -1; + for (let value of values) { + if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) { + ++count, sum += value; + } + } + } + if (count) return sum / count; +} + +function median(values, valueof) { + return quantile$1(values, 0.5, valueof); +} + +function* flatten(arrays) { + for (const array of arrays) { + yield* array; + } +} + +function merge(arrays) { + return Array.from(flatten(arrays)); +} + +function minIndex(values, valueof) { + let min; + let minIndex = -1; + let index = -1; + if (valueof === undefined) { + for (const value of values) { + ++index; + if (value != null + && (min > value || (min === undefined && value >= value))) { + min = value, minIndex = index; + } + } + } else { + for (let value of values) { + if ((value = valueof(value, ++index, values)) != null + && (min > value || (min === undefined && value >= value))) { + min = value, minIndex = index; + } + } + } + return minIndex; +} + +function mode(values, valueof) { + const counts = new InternMap(); + if (valueof === undefined) { + for (let value of values) { + if (value != null && value >= value) { + counts.set(value, (counts.get(value) || 0) + 1); + } + } + } else { + let index = -1; + for (let value of values) { + if ((value = valueof(value, ++index, values)) != null && value >= value) { + counts.set(value, (counts.get(value) || 0) + 1); + } + } + } + let modeValue; + let modeCount = 0; + for (const [value, count] of counts) { + if (count > modeCount) { + modeCount = count; + modeValue = value; + } + } + return modeValue; +} + +function pairs(values, pairof = pair) { + const pairs = []; + let previous; + let first = false; + for (const value of values) { + if (first) pairs.push(pairof(previous, value)); + previous = value; + first = true; + } + return pairs; +} + +function pair(a, b) { + return [a, b]; +} + +function range$2(start, stop, step) { + start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step; + + var i = -1, + n = Math.max(0, Math.ceil((stop - start) / step)) | 0, + range = new Array(n); + + while (++i < n) { + range[i] = start + i * step; + } + + return range; +} + +function rank(values, valueof = ascending$3) { + if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable"); + let V = Array.from(values); + const R = new Float64Array(V.length); + if (valueof.length !== 2) V = V.map(valueof), valueof = ascending$3; + const compareIndex = (i, j) => valueof(V[i], V[j]); + let k, r; + Uint32Array + .from(V, (_, i) => i) + .sort(valueof === ascending$3 ? (i, j) => ascendingDefined(V[i], V[j]) : compareDefined(compareIndex)) + .forEach((j, i) => { + const c = compareIndex(j, k === undefined ? j : k); + if (c >= 0) { + if (k === undefined || c > 0) k = j, r = i; + R[j] = r; + } else { + R[j] = NaN; + } + }); + return R; +} + +function least(values, compare = ascending$3) { + let min; + let defined = false; + if (compare.length === 1) { + let minValue; + for (const element of values) { + const value = compare(element); + if (defined + ? ascending$3(value, minValue) < 0 + : ascending$3(value, value) === 0) { + min = element; + minValue = value; + defined = true; + } + } + } else { + for (const value of values) { + if (defined + ? compare(value, min) < 0 + : compare(value, value) === 0) { + min = value; + defined = true; + } + } + } + return min; +} + +function leastIndex(values, compare = ascending$3) { + if (compare.length === 1) return minIndex(values, compare); + let minValue; + let min = -1; + let index = -1; + for (const value of values) { + ++index; + if (min < 0 + ? compare(value, value) === 0 + : compare(value, minValue) < 0) { + minValue = value; + min = index; + } + } + return min; +} + +function greatest(values, compare = ascending$3) { + let max; + let defined = false; + if (compare.length === 1) { + let maxValue; + for (const element of values) { + const value = compare(element); + if (defined + ? ascending$3(value, maxValue) > 0 + : ascending$3(value, value) === 0) { + max = element; + maxValue = value; + defined = true; + } + } + } else { + for (const value of values) { + if (defined + ? compare(value, max) > 0 + : compare(value, value) === 0) { + max = value; + defined = true; + } + } + } + return max; +} + +function greatestIndex(values, compare = ascending$3) { + if (compare.length === 1) return maxIndex(values, compare); + let maxValue; + let max = -1; + let index = -1; + for (const value of values) { + ++index; + if (max < 0 + ? compare(value, value) === 0 + : compare(value, maxValue) > 0) { + maxValue = value; + max = index; + } + } + return max; +} + +function scan(values, compare) { + const index = leastIndex(values, compare); + return index < 0 ? undefined : index; +} + +var shuffle$1 = shuffler(Math.random); + +function shuffler(random) { + return function shuffle(array, i0 = 0, i1 = array.length) { + let m = i1 - (i0 = +i0); + while (m) { + const i = random() * m-- | 0, t = array[m + i0]; + array[m + i0] = array[i + i0]; + array[i + i0] = t; + } + return array; + }; +} + +function sum$2(values, valueof) { + let sum = 0; + if (valueof === undefined) { + for (let value of values) { + if (value = +value) { + sum += value; + } + } + } else { + let index = -1; + for (let value of values) { + if (value = +valueof(value, ++index, values)) { + sum += value; + } + } + } + return sum; +} + +function transpose(matrix) { + if (!(n = matrix.length)) return []; + for (var i = -1, m = min$2(matrix, length$2), transpose = new Array(m); ++i < m;) { + for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n;) { + row[j] = matrix[j][i]; + } + } + return transpose; +} + +function length$2(d) { + return d.length; +} + +function zip() { + return transpose(arguments); +} + +function every(values, test) { + if (typeof test !== "function") throw new TypeError("test is not a function"); + let index = -1; + for (const value of values) { + if (!test(value, ++index, values)) { + return false; + } + } + return true; +} + +function some(values, test) { + if (typeof test !== "function") throw new TypeError("test is not a function"); + let index = -1; + for (const value of values) { + if (test(value, ++index, values)) { + return true; + } + } + return false; +} + +function filter$1(values, test) { + if (typeof test !== "function") throw new TypeError("test is not a function"); + const array = []; + let index = -1; + for (const value of values) { + if (test(value, ++index, values)) { + array.push(value); + } + } + return array; +} + +function map$1(values, mapper) { + if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable"); + if (typeof mapper !== "function") throw new TypeError("mapper is not a function"); + return Array.from(values, (value, index) => mapper(value, index, values)); +} + +function reduce(values, reducer, value) { + if (typeof reducer !== "function") throw new TypeError("reducer is not a function"); + const iterator = values[Symbol.iterator](); + let done, next, index = -1; + if (arguments.length < 3) { + ({done, value} = iterator.next()); + if (done) return; + ++index; + } + while (({done, value: next} = iterator.next()), !done) { + value = reducer(value, next, ++index, values); + } + return value; +} + +function reverse$1(values) { + if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable"); + return Array.from(values).reverse(); +} + +function difference(values, ...others) { + values = new InternSet(values); + for (const other of others) { + for (const value of other) { + values.delete(value); + } + } + return values; +} + +function disjoint(values, other) { + const iterator = other[Symbol.iterator](), set = new InternSet(); + for (const v of values) { + if (set.has(v)) return false; + let value, done; + while (({value, done} = iterator.next())) { + if (done) break; + if (Object.is(v, value)) return false; + set.add(value); + } + } + return true; +} + +function intersection(values, ...others) { + values = new InternSet(values); + others = others.map(set$2); + out: for (const value of values) { + for (const other of others) { + if (!other.has(value)) { + values.delete(value); + continue out; + } + } + } + return values; +} + +function set$2(values) { + return values instanceof InternSet ? values : new InternSet(values); +} + +function superset(values, other) { + const iterator = values[Symbol.iterator](), set = new Set(); + for (const o of other) { + const io = intern(o); + if (set.has(io)) continue; + let value, done; + while (({value, done} = iterator.next())) { + if (done) return false; + const ivalue = intern(value); + set.add(ivalue); + if (Object.is(io, ivalue)) break; + } + } + return true; +} + +function intern(value) { + return value !== null && typeof value === "object" ? value.valueOf() : value; +} + +function subset(values, other) { + return superset(other, values); +} + +function union(...others) { + const set = new InternSet(); + for (const other of others) { + for (const o of other) { + set.add(o); + } + } + return set; +} + +function identity$8(x) { + return x; +} + +var top = 1, + right = 2, + bottom = 3, + left = 4, + epsilon$6 = 1e-6; + +function translateX(x) { + return "translate(" + x + ",0)"; +} + +function translateY(y) { + return "translate(0," + y + ")"; +} + +function number$2(scale) { + return d => +scale(d); +} + +function center$1(scale, offset) { + offset = Math.max(0, scale.bandwidth() - offset * 2) / 2; + if (scale.round()) offset = Math.round(offset); + return d => +scale(d) + offset; +} + +function entering() { + return !this.__axis; +} + +function axis(orient, scale) { + var tickArguments = [], + tickValues = null, + tickFormat = null, + tickSizeInner = 6, + tickSizeOuter = 6, + tickPadding = 3, + offset = typeof window !== "undefined" && window.devicePixelRatio > 1 ? 0 : 0.5, + k = orient === top || orient === left ? -1 : 1, + x = orient === left || orient === right ? "x" : "y", + transform = orient === top || orient === bottom ? translateX : translateY; + + function axis(context) { + var values = tickValues == null ? (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain()) : tickValues, + format = tickFormat == null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : identity$8) : tickFormat, + spacing = Math.max(tickSizeInner, 0) + tickPadding, + range = scale.range(), + range0 = +range[0] + offset, + range1 = +range[range.length - 1] + offset, + position = (scale.bandwidth ? center$1 : number$2)(scale.copy(), offset), + selection = context.selection ? context.selection() : context, + path = selection.selectAll(".domain").data([null]), + tick = selection.selectAll(".tick").data(values, scale).order(), + tickExit = tick.exit(), + tickEnter = tick.enter().append("g").attr("class", "tick"), + line = tick.select("line"), + text = tick.select("text"); + + path = path.merge(path.enter().insert("path", ".tick") + .attr("class", "domain") + .attr("stroke", "currentColor")); + + tick = tick.merge(tickEnter); + + line = line.merge(tickEnter.append("line") + .attr("stroke", "currentColor") + .attr(x + "2", k * tickSizeInner)); + + text = text.merge(tickEnter.append("text") + .attr("fill", "currentColor") + .attr(x, k * spacing) + .attr("dy", orient === top ? "0em" : orient === bottom ? "0.71em" : "0.32em")); + + if (context !== selection) { + path = path.transition(context); + tick = tick.transition(context); + line = line.transition(context); + text = text.transition(context); + + tickExit = tickExit.transition(context) + .attr("opacity", epsilon$6) + .attr("transform", function(d) { return isFinite(d = position(d)) ? transform(d + offset) : this.getAttribute("transform"); }); + + tickEnter + .attr("opacity", epsilon$6) + .attr("transform", function(d) { var p = this.parentNode.__axis; return transform((p && isFinite(p = p(d)) ? p : position(d)) + offset); }); + } + + tickExit.remove(); + + path + .attr("d", orient === left || orient === right + ? (tickSizeOuter ? "M" + k * tickSizeOuter + "," + range0 + "H" + offset + "V" + range1 + "H" + k * tickSizeOuter : "M" + offset + "," + range0 + "V" + range1) + : (tickSizeOuter ? "M" + range0 + "," + k * tickSizeOuter + "V" + offset + "H" + range1 + "V" + k * tickSizeOuter : "M" + range0 + "," + offset + "H" + range1)); + + tick + .attr("opacity", 1) + .attr("transform", function(d) { return transform(position(d) + offset); }); + + line + .attr(x + "2", k * tickSizeInner); + + text + .attr(x, k * spacing) + .text(format); + + selection.filter(entering) + .attr("fill", "none") + .attr("font-size", 10) + .attr("font-family", "sans-serif") + .attr("text-anchor", orient === right ? "start" : orient === left ? "end" : "middle"); + + selection + .each(function() { this.__axis = position; }); + } + + axis.scale = function(_) { + return arguments.length ? (scale = _, axis) : scale; + }; + + axis.ticks = function() { + return tickArguments = Array.from(arguments), axis; + }; + + axis.tickArguments = function(_) { + return arguments.length ? (tickArguments = _ == null ? [] : Array.from(_), axis) : tickArguments.slice(); + }; + + axis.tickValues = function(_) { + return arguments.length ? (tickValues = _ == null ? null : Array.from(_), axis) : tickValues && tickValues.slice(); + }; + + axis.tickFormat = function(_) { + return arguments.length ? (tickFormat = _, axis) : tickFormat; + }; + + axis.tickSize = function(_) { + return arguments.length ? (tickSizeInner = tickSizeOuter = +_, axis) : tickSizeInner; + }; + + axis.tickSizeInner = function(_) { + return arguments.length ? (tickSizeInner = +_, axis) : tickSizeInner; + }; + + axis.tickSizeOuter = function(_) { + return arguments.length ? (tickSizeOuter = +_, axis) : tickSizeOuter; + }; + + axis.tickPadding = function(_) { + return arguments.length ? (tickPadding = +_, axis) : tickPadding; + }; + + axis.offset = function(_) { + return arguments.length ? (offset = +_, axis) : offset; + }; + + return axis; +} + +function axisTop(scale) { + return axis(top, scale); +} + +function axisRight(scale) { + return axis(right, scale); +} + +function axisBottom(scale) { + return axis(bottom, scale); +} + +function axisLeft(scale) { + return axis(left, scale); +} + +var noop$3 = {value: () => {}}; + +function dispatch() { + for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) { + if (!(t = arguments[i] + "") || (t in _) || /[\s.]/.test(t)) throw new Error("illegal type: " + t); + _[t] = []; + } + return new Dispatch(_); +} + +function Dispatch(_) { + this._ = _; +} + +function parseTypenames$1(typenames, types) { + return typenames.trim().split(/^|\s+/).map(function(t) { + var name = "", i = t.indexOf("."); + if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i); + if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t); + return {type: t, name: name}; + }); +} + +Dispatch.prototype = dispatch.prototype = { + constructor: Dispatch, + on: function(typename, callback) { + var _ = this._, + T = parseTypenames$1(typename + "", _), + t, + i = -1, + n = T.length; + + // If no callback was specified, return the callback of the given type and name. + if (arguments.length < 2) { + while (++i < n) if ((t = (typename = T[i]).type) && (t = get$1(_[t], typename.name))) return t; + return; + } + + // If a type was specified, set the callback for the given type and name. + // Otherwise, if a null callback was specified, remove callbacks of the given name. + if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback); + while (++i < n) { + if (t = (typename = T[i]).type) _[t] = set$1(_[t], typename.name, callback); + else if (callback == null) for (t in _) _[t] = set$1(_[t], typename.name, null); + } + + return this; + }, + copy: function() { + var copy = {}, _ = this._; + for (var t in _) copy[t] = _[t].slice(); + return new Dispatch(copy); + }, + call: function(type, that) { + if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2]; + if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type); + for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args); + }, + apply: function(type, that, args) { + if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type); + for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args); + } +}; + +function get$1(type, name) { + for (var i = 0, n = type.length, c; i < n; ++i) { + if ((c = type[i]).name === name) { + return c.value; + } + } +} + +function set$1(type, name, callback) { + for (var i = 0, n = type.length; i < n; ++i) { + if (type[i].name === name) { + type[i] = noop$3, type = type.slice(0, i).concat(type.slice(i + 1)); + break; + } + } + if (callback != null) type.push({name: name, value: callback}); + return type; +} + +var xhtml = "http://www.w3.org/1999/xhtml"; + +var namespaces = { + svg: "http://www.w3.org/2000/svg", + xhtml: xhtml, + xlink: "http://www.w3.org/1999/xlink", + xml: "http://www.w3.org/XML/1998/namespace", + xmlns: "http://www.w3.org/2000/xmlns/" +}; + +function namespace(name) { + var prefix = name += "", i = prefix.indexOf(":"); + if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1); + return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name; // eslint-disable-line no-prototype-builtins +} + +function creatorInherit(name) { + return function() { + var document = this.ownerDocument, + uri = this.namespaceURI; + return uri === xhtml && document.documentElement.namespaceURI === xhtml + ? document.createElement(name) + : document.createElementNS(uri, name); + }; +} + +function creatorFixed(fullname) { + return function() { + return this.ownerDocument.createElementNS(fullname.space, fullname.local); + }; +} + +function creator(name) { + var fullname = namespace(name); + return (fullname.local + ? creatorFixed + : creatorInherit)(fullname); +} + +function none$2() {} + +function selector(selector) { + return selector == null ? none$2 : function() { + return this.querySelector(selector); + }; +} + +function selection_select(select) { + if (typeof select !== "function") select = selector(select); + + for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) { + if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) { + if ("__data__" in node) subnode.__data__ = node.__data__; + subgroup[i] = subnode; + } + } + } + + return new Selection$1(subgroups, this._parents); +} + +// Given something array like (or null), returns something that is strictly an +// array. This is used to ensure that array-like objects passed to d3.selectAll +// or selection.selectAll are converted into proper arrays when creating a +// selection; we don’t ever want to create a selection backed by a live +// HTMLCollection or NodeList. However, note that selection.selectAll will use a +// static NodeList as a group, since it safely derived from querySelectorAll. +function array$4(x) { + return x == null ? [] : Array.isArray(x) ? x : Array.from(x); +} + +function empty$1() { + return []; +} + +function selectorAll(selector) { + return selector == null ? empty$1 : function() { + return this.querySelectorAll(selector); + }; +} + +function arrayAll(select) { + return function() { + return array$4(select.apply(this, arguments)); + }; +} + +function selection_selectAll(select) { + if (typeof select === "function") select = arrayAll(select); + else select = selectorAll(select); + + for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) { + if (node = group[i]) { + subgroups.push(select.call(node, node.__data__, i, group)); + parents.push(node); + } + } + } + + return new Selection$1(subgroups, parents); +} + +function matcher(selector) { + return function() { + return this.matches(selector); + }; +} + +function childMatcher(selector) { + return function(node) { + return node.matches(selector); + }; +} + +var find$1 = Array.prototype.find; + +function childFind(match) { + return function() { + return find$1.call(this.children, match); + }; +} + +function childFirst() { + return this.firstElementChild; +} + +function selection_selectChild(match) { + return this.select(match == null ? childFirst + : childFind(typeof match === "function" ? match : childMatcher(match))); +} + +var filter = Array.prototype.filter; + +function children() { + return Array.from(this.children); +} + +function childrenFilter(match) { + return function() { + return filter.call(this.children, match); + }; +} + +function selection_selectChildren(match) { + return this.selectAll(match == null ? children + : childrenFilter(typeof match === "function" ? match : childMatcher(match))); +} + +function selection_filter(match) { + if (typeof match !== "function") match = matcher(match); + + for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) { + if ((node = group[i]) && match.call(node, node.__data__, i, group)) { + subgroup.push(node); + } + } + } + + return new Selection$1(subgroups, this._parents); +} + +function sparse(update) { + return new Array(update.length); +} + +function selection_enter() { + return new Selection$1(this._enter || this._groups.map(sparse), this._parents); +} + +function EnterNode(parent, datum) { + this.ownerDocument = parent.ownerDocument; + this.namespaceURI = parent.namespaceURI; + this._next = null; + this._parent = parent; + this.__data__ = datum; +} + +EnterNode.prototype = { + constructor: EnterNode, + appendChild: function(child) { return this._parent.insertBefore(child, this._next); }, + insertBefore: function(child, next) { return this._parent.insertBefore(child, next); }, + querySelector: function(selector) { return this._parent.querySelector(selector); }, + querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); } +}; + +function constant$a(x) { + return function() { + return x; + }; +} + +function bindIndex(parent, group, enter, update, exit, data) { + var i = 0, + node, + groupLength = group.length, + dataLength = data.length; + + // Put any non-null nodes that fit into update. + // Put any null nodes into enter. + // Put any remaining data into enter. + for (; i < dataLength; ++i) { + if (node = group[i]) { + node.__data__ = data[i]; + update[i] = node; + } else { + enter[i] = new EnterNode(parent, data[i]); + } + } + + // Put any non-null nodes that don’t fit into exit. + for (; i < groupLength; ++i) { + if (node = group[i]) { + exit[i] = node; + } + } +} + +function bindKey(parent, group, enter, update, exit, data, key) { + var i, + node, + nodeByKeyValue = new Map, + groupLength = group.length, + dataLength = data.length, + keyValues = new Array(groupLength), + keyValue; + + // Compute the key for each node. + // If multiple nodes have the same key, the duplicates are added to exit. + for (i = 0; i < groupLength; ++i) { + if (node = group[i]) { + keyValues[i] = keyValue = key.call(node, node.__data__, i, group) + ""; + if (nodeByKeyValue.has(keyValue)) { + exit[i] = node; + } else { + nodeByKeyValue.set(keyValue, node); + } + } + } + + // Compute the key for each datum. + // If there a node associated with this key, join and add it to update. + // If there is not (or the key is a duplicate), add it to enter. + for (i = 0; i < dataLength; ++i) { + keyValue = key.call(parent, data[i], i, data) + ""; + if (node = nodeByKeyValue.get(keyValue)) { + update[i] = node; + node.__data__ = data[i]; + nodeByKeyValue.delete(keyValue); + } else { + enter[i] = new EnterNode(parent, data[i]); + } + } + + // Add any remaining nodes that were not bound to data to exit. + for (i = 0; i < groupLength; ++i) { + if ((node = group[i]) && (nodeByKeyValue.get(keyValues[i]) === node)) { + exit[i] = node; + } + } +} + +function datum(node) { + return node.__data__; +} + +function selection_data(value, key) { + if (!arguments.length) return Array.from(this, datum); + + var bind = key ? bindKey : bindIndex, + parents = this._parents, + groups = this._groups; + + if (typeof value !== "function") value = constant$a(value); + + for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) { + var parent = parents[j], + group = groups[j], + groupLength = group.length, + data = arraylike(value.call(parent, parent && parent.__data__, j, parents)), + dataLength = data.length, + enterGroup = enter[j] = new Array(dataLength), + updateGroup = update[j] = new Array(dataLength), + exitGroup = exit[j] = new Array(groupLength); + + bind(parent, group, enterGroup, updateGroup, exitGroup, data, key); + + // Now connect the enter nodes to their following update node, such that + // appendChild can insert the materialized enter node before this node, + // rather than at the end of the parent node. + for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) { + if (previous = enterGroup[i0]) { + if (i0 >= i1) i1 = i0 + 1; + while (!(next = updateGroup[i1]) && ++i1 < dataLength); + previous._next = next || null; + } + } + } + + update = new Selection$1(update, parents); + update._enter = enter; + update._exit = exit; + return update; +} + +// Given some data, this returns an array-like view of it: an object that +// exposes a length property and allows numeric indexing. Note that unlike +// selectAll, this isn’t worried about “live” collections because the resulting +// array will only be used briefly while data is being bound. (It is possible to +// cause the data to change while iterating by using a key function, but please +// don’t; we’d rather avoid a gratuitous copy.) +function arraylike(data) { + return typeof data === "object" && "length" in data + ? data // Array, TypedArray, NodeList, array-like + : Array.from(data); // Map, Set, iterable, string, or anything else +} + +function selection_exit() { + return new Selection$1(this._exit || this._groups.map(sparse), this._parents); +} + +function selection_join(onenter, onupdate, onexit) { + var enter = this.enter(), update = this, exit = this.exit(); + if (typeof onenter === "function") { + enter = onenter(enter); + if (enter) enter = enter.selection(); + } else { + enter = enter.append(onenter + ""); + } + if (onupdate != null) { + update = onupdate(update); + if (update) update = update.selection(); + } + if (onexit == null) exit.remove(); else onexit(exit); + return enter && update ? enter.merge(update).order() : update; +} + +function selection_merge(context) { + var selection = context.selection ? context.selection() : context; + + for (var groups0 = this._groups, groups1 = selection._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) { + for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) { + if (node = group0[i] || group1[i]) { + merge[i] = node; + } + } + } + + for (; j < m0; ++j) { + merges[j] = groups0[j]; + } + + return new Selection$1(merges, this._parents); +} + +function selection_order() { + + for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) { + for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) { + if (node = group[i]) { + if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next); + next = node; + } + } + } + + return this; +} + +function selection_sort(compare) { + if (!compare) compare = ascending$2; + + function compareNode(a, b) { + return a && b ? compare(a.__data__, b.__data__) : !a - !b; + } + + for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) { + if (node = group[i]) { + sortgroup[i] = node; + } + } + sortgroup.sort(compareNode); + } + + return new Selection$1(sortgroups, this._parents).order(); +} + +function ascending$2(a, b) { + return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; +} + +function selection_call() { + var callback = arguments[0]; + arguments[0] = this; + callback.apply(null, arguments); + return this; +} + +function selection_nodes() { + return Array.from(this); +} + +function selection_node() { + + for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) { + for (var group = groups[j], i = 0, n = group.length; i < n; ++i) { + var node = group[i]; + if (node) return node; + } + } + + return null; +} + +function selection_size() { + let size = 0; + for (const node of this) ++size; // eslint-disable-line no-unused-vars + return size; +} + +function selection_empty() { + return !this.node(); +} + +function selection_each(callback) { + + for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) { + for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) { + if (node = group[i]) callback.call(node, node.__data__, i, group); + } + } + + return this; +} + +function attrRemove$1(name) { + return function() { + this.removeAttribute(name); + }; +} + +function attrRemoveNS$1(fullname) { + return function() { + this.removeAttributeNS(fullname.space, fullname.local); + }; +} + +function attrConstant$1(name, value) { + return function() { + this.setAttribute(name, value); + }; +} + +function attrConstantNS$1(fullname, value) { + return function() { + this.setAttributeNS(fullname.space, fullname.local, value); + }; +} + +function attrFunction$1(name, value) { + return function() { + var v = value.apply(this, arguments); + if (v == null) this.removeAttribute(name); + else this.setAttribute(name, v); + }; +} + +function attrFunctionNS$1(fullname, value) { + return function() { + var v = value.apply(this, arguments); + if (v == null) this.removeAttributeNS(fullname.space, fullname.local); + else this.setAttributeNS(fullname.space, fullname.local, v); + }; +} + +function selection_attr(name, value) { + var fullname = namespace(name); + + if (arguments.length < 2) { + var node = this.node(); + return fullname.local + ? node.getAttributeNS(fullname.space, fullname.local) + : node.getAttribute(fullname); + } + + return this.each((value == null + ? (fullname.local ? attrRemoveNS$1 : attrRemove$1) : (typeof value === "function" + ? (fullname.local ? attrFunctionNS$1 : attrFunction$1) + : (fullname.local ? attrConstantNS$1 : attrConstant$1)))(fullname, value)); +} + +function defaultView(node) { + return (node.ownerDocument && node.ownerDocument.defaultView) // node is a Node + || (node.document && node) // node is a Window + || node.defaultView; // node is a Document +} + +function styleRemove$1(name) { + return function() { + this.style.removeProperty(name); + }; +} + +function styleConstant$1(name, value, priority) { + return function() { + this.style.setProperty(name, value, priority); + }; +} + +function styleFunction$1(name, value, priority) { + return function() { + var v = value.apply(this, arguments); + if (v == null) this.style.removeProperty(name); + else this.style.setProperty(name, v, priority); + }; +} + +function selection_style(name, value, priority) { + return arguments.length > 1 + ? this.each((value == null + ? styleRemove$1 : typeof value === "function" + ? styleFunction$1 + : styleConstant$1)(name, value, priority == null ? "" : priority)) + : styleValue(this.node(), name); +} + +function styleValue(node, name) { + return node.style.getPropertyValue(name) + || defaultView(node).getComputedStyle(node, null).getPropertyValue(name); +} + +function propertyRemove(name) { + return function() { + delete this[name]; + }; +} + +function propertyConstant(name, value) { + return function() { + this[name] = value; + }; +} + +function propertyFunction(name, value) { + return function() { + var v = value.apply(this, arguments); + if (v == null) delete this[name]; + else this[name] = v; + }; +} + +function selection_property(name, value) { + return arguments.length > 1 + ? this.each((value == null + ? propertyRemove : typeof value === "function" + ? propertyFunction + : propertyConstant)(name, value)) + : this.node()[name]; +} + +function classArray(string) { + return string.trim().split(/^|\s+/); +} + +function classList(node) { + return node.classList || new ClassList(node); +} + +function ClassList(node) { + this._node = node; + this._names = classArray(node.getAttribute("class") || ""); +} + +ClassList.prototype = { + add: function(name) { + var i = this._names.indexOf(name); + if (i < 0) { + this._names.push(name); + this._node.setAttribute("class", this._names.join(" ")); + } + }, + remove: function(name) { + var i = this._names.indexOf(name); + if (i >= 0) { + this._names.splice(i, 1); + this._node.setAttribute("class", this._names.join(" ")); + } + }, + contains: function(name) { + return this._names.indexOf(name) >= 0; + } +}; + +function classedAdd(node, names) { + var list = classList(node), i = -1, n = names.length; + while (++i < n) list.add(names[i]); +} + +function classedRemove(node, names) { + var list = classList(node), i = -1, n = names.length; + while (++i < n) list.remove(names[i]); +} + +function classedTrue(names) { + return function() { + classedAdd(this, names); + }; +} + +function classedFalse(names) { + return function() { + classedRemove(this, names); + }; +} + +function classedFunction(names, value) { + return function() { + (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names); + }; +} + +function selection_classed(name, value) { + var names = classArray(name + ""); + + if (arguments.length < 2) { + var list = classList(this.node()), i = -1, n = names.length; + while (++i < n) if (!list.contains(names[i])) return false; + return true; + } + + return this.each((typeof value === "function" + ? classedFunction : value + ? classedTrue + : classedFalse)(names, value)); +} + +function textRemove() { + this.textContent = ""; +} + +function textConstant$1(value) { + return function() { + this.textContent = value; + }; +} + +function textFunction$1(value) { + return function() { + var v = value.apply(this, arguments); + this.textContent = v == null ? "" : v; + }; +} + +function selection_text(value) { + return arguments.length + ? this.each(value == null + ? textRemove : (typeof value === "function" + ? textFunction$1 + : textConstant$1)(value)) + : this.node().textContent; +} + +function htmlRemove() { + this.innerHTML = ""; +} + +function htmlConstant(value) { + return function() { + this.innerHTML = value; + }; +} + +function htmlFunction(value) { + return function() { + var v = value.apply(this, arguments); + this.innerHTML = v == null ? "" : v; + }; +} + +function selection_html(value) { + return arguments.length + ? this.each(value == null + ? htmlRemove : (typeof value === "function" + ? htmlFunction + : htmlConstant)(value)) + : this.node().innerHTML; +} + +function raise() { + if (this.nextSibling) this.parentNode.appendChild(this); +} + +function selection_raise() { + return this.each(raise); +} + +function lower() { + if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild); +} + +function selection_lower() { + return this.each(lower); +} + +function selection_append(name) { + var create = typeof name === "function" ? name : creator(name); + return this.select(function() { + return this.appendChild(create.apply(this, arguments)); + }); +} + +function constantNull() { + return null; +} + +function selection_insert(name, before) { + var create = typeof name === "function" ? name : creator(name), + select = before == null ? constantNull : typeof before === "function" ? before : selector(before); + return this.select(function() { + return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null); + }); +} + +function remove() { + var parent = this.parentNode; + if (parent) parent.removeChild(this); +} + +function selection_remove() { + return this.each(remove); +} + +function selection_cloneShallow() { + var clone = this.cloneNode(false), parent = this.parentNode; + return parent ? parent.insertBefore(clone, this.nextSibling) : clone; +} + +function selection_cloneDeep() { + var clone = this.cloneNode(true), parent = this.parentNode; + return parent ? parent.insertBefore(clone, this.nextSibling) : clone; +} + +function selection_clone(deep) { + return this.select(deep ? selection_cloneDeep : selection_cloneShallow); +} + +function selection_datum(value) { + return arguments.length + ? this.property("__data__", value) + : this.node().__data__; +} + +function contextListener(listener) { + return function(event) { + listener.call(this, event, this.__data__); + }; +} + +function parseTypenames(typenames) { + return typenames.trim().split(/^|\s+/).map(function(t) { + var name = "", i = t.indexOf("."); + if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i); + return {type: t, name: name}; + }); +} + +function onRemove(typename) { + return function() { + var on = this.__on; + if (!on) return; + for (var j = 0, i = -1, m = on.length, o; j < m; ++j) { + if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) { + this.removeEventListener(o.type, o.listener, o.options); + } else { + on[++i] = o; + } + } + if (++i) on.length = i; + else delete this.__on; + }; +} + +function onAdd(typename, value, options) { + return function() { + var on = this.__on, o, listener = contextListener(value); + if (on) for (var j = 0, m = on.length; j < m; ++j) { + if ((o = on[j]).type === typename.type && o.name === typename.name) { + this.removeEventListener(o.type, o.listener, o.options); + this.addEventListener(o.type, o.listener = listener, o.options = options); + o.value = value; + return; + } + } + this.addEventListener(typename.type, listener, options); + o = {type: typename.type, name: typename.name, value: value, listener: listener, options: options}; + if (!on) this.__on = [o]; + else on.push(o); + }; +} + +function selection_on(typename, value, options) { + var typenames = parseTypenames(typename + ""), i, n = typenames.length, t; + + if (arguments.length < 2) { + var on = this.node().__on; + if (on) for (var j = 0, m = on.length, o; j < m; ++j) { + for (i = 0, o = on[j]; i < n; ++i) { + if ((t = typenames[i]).type === o.type && t.name === o.name) { + return o.value; + } + } + } + return; + } + + on = value ? onAdd : onRemove; + for (i = 0; i < n; ++i) this.each(on(typenames[i], value, options)); + return this; +} + +function dispatchEvent(node, type, params) { + var window = defaultView(node), + event = window.CustomEvent; + + if (typeof event === "function") { + event = new event(type, params); + } else { + event = window.document.createEvent("Event"); + if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail; + else event.initEvent(type, false, false); + } + + node.dispatchEvent(event); +} + +function dispatchConstant(type, params) { + return function() { + return dispatchEvent(this, type, params); + }; +} + +function dispatchFunction(type, params) { + return function() { + return dispatchEvent(this, type, params.apply(this, arguments)); + }; +} + +function selection_dispatch(type, params) { + return this.each((typeof params === "function" + ? dispatchFunction + : dispatchConstant)(type, params)); +} + +function* selection_iterator() { + for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) { + for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) { + if (node = group[i]) yield node; + } + } +} + +var root$1 = [null]; + +function Selection$1(groups, parents) { + this._groups = groups; + this._parents = parents; +} + +function selection() { + return new Selection$1([[document.documentElement]], root$1); +} + +function selection_selection() { + return this; +} + +Selection$1.prototype = selection.prototype = { + constructor: Selection$1, + select: selection_select, + selectAll: selection_selectAll, + selectChild: selection_selectChild, + selectChildren: selection_selectChildren, + filter: selection_filter, + data: selection_data, + enter: selection_enter, + exit: selection_exit, + join: selection_join, + merge: selection_merge, + selection: selection_selection, + order: selection_order, + sort: selection_sort, + call: selection_call, + nodes: selection_nodes, + node: selection_node, + size: selection_size, + empty: selection_empty, + each: selection_each, + attr: selection_attr, + style: selection_style, + property: selection_property, + classed: selection_classed, + text: selection_text, + html: selection_html, + raise: selection_raise, + lower: selection_lower, + append: selection_append, + insert: selection_insert, + remove: selection_remove, + clone: selection_clone, + datum: selection_datum, + on: selection_on, + dispatch: selection_dispatch, + [Symbol.iterator]: selection_iterator +}; + +function select(selector) { + return typeof selector === "string" + ? new Selection$1([[document.querySelector(selector)]], [document.documentElement]) + : new Selection$1([[selector]], root$1); +} + +function create$1(name) { + return select(creator(name).call(document.documentElement)); +} + +var nextId = 0; + +function local$1() { + return new Local; +} + +function Local() { + this._ = "@" + (++nextId).toString(36); +} + +Local.prototype = local$1.prototype = { + constructor: Local, + get: function(node) { + var id = this._; + while (!(id in node)) if (!(node = node.parentNode)) return; + return node[id]; + }, + set: function(node, value) { + return node[this._] = value; + }, + remove: function(node) { + return this._ in node && delete node[this._]; + }, + toString: function() { + return this._; + } +}; + +function sourceEvent(event) { + let sourceEvent; + while (sourceEvent = event.sourceEvent) event = sourceEvent; + return event; +} + +function pointer(event, node) { + event = sourceEvent(event); + if (node === undefined) node = event.currentTarget; + if (node) { + var svg = node.ownerSVGElement || node; + if (svg.createSVGPoint) { + var point = svg.createSVGPoint(); + point.x = event.clientX, point.y = event.clientY; + point = point.matrixTransform(node.getScreenCTM().inverse()); + return [point.x, point.y]; + } + if (node.getBoundingClientRect) { + var rect = node.getBoundingClientRect(); + return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop]; + } + } + return [event.pageX, event.pageY]; +} + +function pointers(events, node) { + if (events.target) { // i.e., instanceof Event, not TouchList or iterable + events = sourceEvent(events); + if (node === undefined) node = events.currentTarget; + events = events.touches || [events]; + } + return Array.from(events, event => pointer(event, node)); +} + +function selectAll(selector) { + return typeof selector === "string" + ? new Selection$1([document.querySelectorAll(selector)], [document.documentElement]) + : new Selection$1([array$4(selector)], root$1); +} + +// These are typically used in conjunction with noevent to ensure that we can +// preventDefault on the event. +const nonpassive = {passive: false}; +const nonpassivecapture = {capture: true, passive: false}; + +function nopropagation$2(event) { + event.stopImmediatePropagation(); +} + +function noevent$2(event) { + event.preventDefault(); + event.stopImmediatePropagation(); +} + +function dragDisable(view) { + var root = view.document.documentElement, + selection = select(view).on("dragstart.drag", noevent$2, nonpassivecapture); + if ("onselectstart" in root) { + selection.on("selectstart.drag", noevent$2, nonpassivecapture); + } else { + root.__noselect = root.style.MozUserSelect; + root.style.MozUserSelect = "none"; + } +} + +function yesdrag(view, noclick) { + var root = view.document.documentElement, + selection = select(view).on("dragstart.drag", null); + if (noclick) { + selection.on("click.drag", noevent$2, nonpassivecapture); + setTimeout(function() { selection.on("click.drag", null); }, 0); + } + if ("onselectstart" in root) { + selection.on("selectstart.drag", null); + } else { + root.style.MozUserSelect = root.__noselect; + delete root.__noselect; + } +} + +var constant$9 = x => () => x; + +function DragEvent(type, { + sourceEvent, + subject, + target, + identifier, + active, + x, y, dx, dy, + dispatch +}) { + Object.defineProperties(this, { + type: {value: type, enumerable: true, configurable: true}, + sourceEvent: {value: sourceEvent, enumerable: true, configurable: true}, + subject: {value: subject, enumerable: true, configurable: true}, + target: {value: target, enumerable: true, configurable: true}, + identifier: {value: identifier, enumerable: true, configurable: true}, + active: {value: active, enumerable: true, configurable: true}, + x: {value: x, enumerable: true, configurable: true}, + y: {value: y, enumerable: true, configurable: true}, + dx: {value: dx, enumerable: true, configurable: true}, + dy: {value: dy, enumerable: true, configurable: true}, + _: {value: dispatch} + }); +} + +DragEvent.prototype.on = function() { + var value = this._.on.apply(this._, arguments); + return value === this._ ? this : value; +}; + +// Ignore right-click, since that should open the context menu. +function defaultFilter$2(event) { + return !event.ctrlKey && !event.button; +} + +function defaultContainer() { + return this.parentNode; +} + +function defaultSubject(event, d) { + return d == null ? {x: event.x, y: event.y} : d; +} + +function defaultTouchable$2() { + return navigator.maxTouchPoints || ("ontouchstart" in this); +} + +function drag() { + var filter = defaultFilter$2, + container = defaultContainer, + subject = defaultSubject, + touchable = defaultTouchable$2, + gestures = {}, + listeners = dispatch("start", "drag", "end"), + active = 0, + mousedownx, + mousedowny, + mousemoving, + touchending, + clickDistance2 = 0; + + function drag(selection) { + selection + .on("mousedown.drag", mousedowned) + .filter(touchable) + .on("touchstart.drag", touchstarted) + .on("touchmove.drag", touchmoved, nonpassive) + .on("touchend.drag touchcancel.drag", touchended) + .style("touch-action", "none") + .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)"); + } + + function mousedowned(event, d) { + if (touchending || !filter.call(this, event, d)) return; + var gesture = beforestart(this, container.call(this, event, d), event, d, "mouse"); + if (!gesture) return; + select(event.view) + .on("mousemove.drag", mousemoved, nonpassivecapture) + .on("mouseup.drag", mouseupped, nonpassivecapture); + dragDisable(event.view); + nopropagation$2(event); + mousemoving = false; + mousedownx = event.clientX; + mousedowny = event.clientY; + gesture("start", event); + } + + function mousemoved(event) { + noevent$2(event); + if (!mousemoving) { + var dx = event.clientX - mousedownx, dy = event.clientY - mousedowny; + mousemoving = dx * dx + dy * dy > clickDistance2; + } + gestures.mouse("drag", event); + } + + function mouseupped(event) { + select(event.view).on("mousemove.drag mouseup.drag", null); + yesdrag(event.view, mousemoving); + noevent$2(event); + gestures.mouse("end", event); + } + + function touchstarted(event, d) { + if (!filter.call(this, event, d)) return; + var touches = event.changedTouches, + c = container.call(this, event, d), + n = touches.length, i, gesture; + + for (i = 0; i < n; ++i) { + if (gesture = beforestart(this, c, event, d, touches[i].identifier, touches[i])) { + nopropagation$2(event); + gesture("start", event, touches[i]); + } + } + } + + function touchmoved(event) { + var touches = event.changedTouches, + n = touches.length, i, gesture; + + for (i = 0; i < n; ++i) { + if (gesture = gestures[touches[i].identifier]) { + noevent$2(event); + gesture("drag", event, touches[i]); + } + } + } + + function touchended(event) { + var touches = event.changedTouches, + n = touches.length, i, gesture; + + if (touchending) clearTimeout(touchending); + touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed! + for (i = 0; i < n; ++i) { + if (gesture = gestures[touches[i].identifier]) { + nopropagation$2(event); + gesture("end", event, touches[i]); + } + } + } + + function beforestart(that, container, event, d, identifier, touch) { + var dispatch = listeners.copy(), + p = pointer(touch || event, container), dx, dy, + s; + + if ((s = subject.call(that, new DragEvent("beforestart", { + sourceEvent: event, + target: drag, + identifier, + active, + x: p[0], + y: p[1], + dx: 0, + dy: 0, + dispatch + }), d)) == null) return; + + dx = s.x - p[0] || 0; + dy = s.y - p[1] || 0; + + return function gesture(type, event, touch) { + var p0 = p, n; + switch (type) { + case "start": gestures[identifier] = gesture, n = active++; break; + case "end": delete gestures[identifier], --active; // falls through + case "drag": p = pointer(touch || event, container), n = active; break; + } + dispatch.call( + type, + that, + new DragEvent(type, { + sourceEvent: event, + subject: s, + target: drag, + identifier, + active: n, + x: p[0] + dx, + y: p[1] + dy, + dx: p[0] - p0[0], + dy: p[1] - p0[1], + dispatch + }), + d + ); + }; + } + + drag.filter = function(_) { + return arguments.length ? (filter = typeof _ === "function" ? _ : constant$9(!!_), drag) : filter; + }; + + drag.container = function(_) { + return arguments.length ? (container = typeof _ === "function" ? _ : constant$9(_), drag) : container; + }; + + drag.subject = function(_) { + return arguments.length ? (subject = typeof _ === "function" ? _ : constant$9(_), drag) : subject; + }; + + drag.touchable = function(_) { + return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$9(!!_), drag) : touchable; + }; + + drag.on = function() { + var value = listeners.on.apply(listeners, arguments); + return value === listeners ? drag : value; + }; + + drag.clickDistance = function(_) { + return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2); + }; + + return drag; +} + +function define(constructor, factory, prototype) { + constructor.prototype = factory.prototype = prototype; + prototype.constructor = constructor; +} + +function extend(parent, definition) { + var prototype = Object.create(parent.prototype); + for (var key in definition) prototype[key] = definition[key]; + return prototype; +} + +function Color() {} + +var darker = 0.7; +var brighter = 1 / darker; + +var reI = "\\s*([+-]?\\d+)\\s*", + reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*", + reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*", + reHex = /^#([0-9a-f]{3,8})$/, + reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$"), + reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$"), + reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$"), + reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$"), + reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$"), + reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$"); + +var named = { + aliceblue: 0xf0f8ff, + antiquewhite: 0xfaebd7, + aqua: 0x00ffff, + aquamarine: 0x7fffd4, + azure: 0xf0ffff, + beige: 0xf5f5dc, + bisque: 0xffe4c4, + black: 0x000000, + blanchedalmond: 0xffebcd, + blue: 0x0000ff, + blueviolet: 0x8a2be2, + brown: 0xa52a2a, + burlywood: 0xdeb887, + cadetblue: 0x5f9ea0, + chartreuse: 0x7fff00, + chocolate: 0xd2691e, + coral: 0xff7f50, + cornflowerblue: 0x6495ed, + cornsilk: 0xfff8dc, + crimson: 0xdc143c, + cyan: 0x00ffff, + darkblue: 0x00008b, + darkcyan: 0x008b8b, + darkgoldenrod: 0xb8860b, + darkgray: 0xa9a9a9, + darkgreen: 0x006400, + darkgrey: 0xa9a9a9, + darkkhaki: 0xbdb76b, + darkmagenta: 0x8b008b, + darkolivegreen: 0x556b2f, + darkorange: 0xff8c00, + darkorchid: 0x9932cc, + darkred: 0x8b0000, + darksalmon: 0xe9967a, + darkseagreen: 0x8fbc8f, + darkslateblue: 0x483d8b, + darkslategray: 0x2f4f4f, + darkslategrey: 0x2f4f4f, + darkturquoise: 0x00ced1, + darkviolet: 0x9400d3, + deeppink: 0xff1493, + deepskyblue: 0x00bfff, + dimgray: 0x696969, + dimgrey: 0x696969, + dodgerblue: 0x1e90ff, + firebrick: 0xb22222, + floralwhite: 0xfffaf0, + forestgreen: 0x228b22, + fuchsia: 0xff00ff, + gainsboro: 0xdcdcdc, + ghostwhite: 0xf8f8ff, + gold: 0xffd700, + goldenrod: 0xdaa520, + gray: 0x808080, + green: 0x008000, + greenyellow: 0xadff2f, + grey: 0x808080, + honeydew: 0xf0fff0, + hotpink: 0xff69b4, + indianred: 0xcd5c5c, + indigo: 0x4b0082, + ivory: 0xfffff0, + khaki: 0xf0e68c, + lavender: 0xe6e6fa, + lavenderblush: 0xfff0f5, + lawngreen: 0x7cfc00, + lemonchiffon: 0xfffacd, + lightblue: 0xadd8e6, + lightcoral: 0xf08080, + lightcyan: 0xe0ffff, + lightgoldenrodyellow: 0xfafad2, + lightgray: 0xd3d3d3, + lightgreen: 0x90ee90, + lightgrey: 0xd3d3d3, + lightpink: 0xffb6c1, + lightsalmon: 0xffa07a, + lightseagreen: 0x20b2aa, + lightskyblue: 0x87cefa, + lightslategray: 0x778899, + lightslategrey: 0x778899, + lightsteelblue: 0xb0c4de, + lightyellow: 0xffffe0, + lime: 0x00ff00, + limegreen: 0x32cd32, + linen: 0xfaf0e6, + magenta: 0xff00ff, + maroon: 0x800000, + mediumaquamarine: 0x66cdaa, + mediumblue: 0x0000cd, + mediumorchid: 0xba55d3, + mediumpurple: 0x9370db, + mediumseagreen: 0x3cb371, + mediumslateblue: 0x7b68ee, + mediumspringgreen: 0x00fa9a, + mediumturquoise: 0x48d1cc, + mediumvioletred: 0xc71585, + midnightblue: 0x191970, + mintcream: 0xf5fffa, + mistyrose: 0xffe4e1, + moccasin: 0xffe4b5, + navajowhite: 0xffdead, + navy: 0x000080, + oldlace: 0xfdf5e6, + olive: 0x808000, + olivedrab: 0x6b8e23, + orange: 0xffa500, + orangered: 0xff4500, + orchid: 0xda70d6, + palegoldenrod: 0xeee8aa, + palegreen: 0x98fb98, + paleturquoise: 0xafeeee, + palevioletred: 0xdb7093, + papayawhip: 0xffefd5, + peachpuff: 0xffdab9, + peru: 0xcd853f, + pink: 0xffc0cb, + plum: 0xdda0dd, + powderblue: 0xb0e0e6, + purple: 0x800080, + rebeccapurple: 0x663399, + red: 0xff0000, + rosybrown: 0xbc8f8f, + royalblue: 0x4169e1, + saddlebrown: 0x8b4513, + salmon: 0xfa8072, + sandybrown: 0xf4a460, + seagreen: 0x2e8b57, + seashell: 0xfff5ee, + sienna: 0xa0522d, + silver: 0xc0c0c0, + skyblue: 0x87ceeb, + slateblue: 0x6a5acd, + slategray: 0x708090, + slategrey: 0x708090, + snow: 0xfffafa, + springgreen: 0x00ff7f, + steelblue: 0x4682b4, + tan: 0xd2b48c, + teal: 0x008080, + thistle: 0xd8bfd8, + tomato: 0xff6347, + turquoise: 0x40e0d0, + violet: 0xee82ee, + wheat: 0xf5deb3, + white: 0xffffff, + whitesmoke: 0xf5f5f5, + yellow: 0xffff00, + yellowgreen: 0x9acd32 +}; + +define(Color, color, { + copy: function(channels) { + return Object.assign(new this.constructor, this, channels); + }, + displayable: function() { + return this.rgb().displayable(); + }, + hex: color_formatHex, // Deprecated! Use color.formatHex. + formatHex: color_formatHex, + formatHsl: color_formatHsl, + formatRgb: color_formatRgb, + toString: color_formatRgb +}); + +function color_formatHex() { + return this.rgb().formatHex(); +} + +function color_formatHsl() { + return hslConvert(this).formatHsl(); +} + +function color_formatRgb() { + return this.rgb().formatRgb(); +} + +function color(format) { + var m, l; + format = (format + "").trim().toLowerCase(); + return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) // #ff0000 + : l === 3 ? new Rgb((m >> 8 & 0xf) | (m >> 4 & 0xf0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1) // #f00 + : l === 8 ? rgba(m >> 24 & 0xff, m >> 16 & 0xff, m >> 8 & 0xff, (m & 0xff) / 0xff) // #ff000000 + : l === 4 ? rgba((m >> 12 & 0xf) | (m >> 8 & 0xf0), (m >> 8 & 0xf) | (m >> 4 & 0xf0), (m >> 4 & 0xf) | (m & 0xf0), (((m & 0xf) << 4) | (m & 0xf)) / 0xff) // #f000 + : null) // invalid hex + : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0) + : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%) + : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1) + : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1) + : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%) + : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1) + : named.hasOwnProperty(format) ? rgbn(named[format]) // eslint-disable-line no-prototype-builtins + : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) + : null; +} + +function rgbn(n) { + return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1); +} + +function rgba(r, g, b, a) { + if (a <= 0) r = g = b = NaN; + return new Rgb(r, g, b, a); +} + +function rgbConvert(o) { + if (!(o instanceof Color)) o = color(o); + if (!o) return new Rgb; + o = o.rgb(); + return new Rgb(o.r, o.g, o.b, o.opacity); +} + +function rgb(r, g, b, opacity) { + return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity); +} + +function Rgb(r, g, b, opacity) { + this.r = +r; + this.g = +g; + this.b = +b; + this.opacity = +opacity; +} + +define(Rgb, rgb, extend(Color, { + brighter: function(k) { + k = k == null ? brighter : Math.pow(brighter, k); + return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity); + }, + darker: function(k) { + k = k == null ? darker : Math.pow(darker, k); + return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity); + }, + rgb: function() { + return this; + }, + displayable: function() { + return (-0.5 <= this.r && this.r < 255.5) + && (-0.5 <= this.g && this.g < 255.5) + && (-0.5 <= this.b && this.b < 255.5) + && (0 <= this.opacity && this.opacity <= 1); + }, + hex: rgb_formatHex, // Deprecated! Use color.formatHex. + formatHex: rgb_formatHex, + formatRgb: rgb_formatRgb, + toString: rgb_formatRgb +})); + +function rgb_formatHex() { + return "#" + hex(this.r) + hex(this.g) + hex(this.b); +} + +function rgb_formatRgb() { + var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a)); + return (a === 1 ? "rgb(" : "rgba(") + + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", " + + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", " + + Math.max(0, Math.min(255, Math.round(this.b) || 0)) + + (a === 1 ? ")" : ", " + a + ")"); +} + +function hex(value) { + value = Math.max(0, Math.min(255, Math.round(value) || 0)); + return (value < 16 ? "0" : "") + value.toString(16); +} + +function hsla(h, s, l, a) { + if (a <= 0) h = s = l = NaN; + else if (l <= 0 || l >= 1) h = s = NaN; + else if (s <= 0) h = NaN; + return new Hsl(h, s, l, a); +} + +function hslConvert(o) { + if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity); + if (!(o instanceof Color)) o = color(o); + if (!o) return new Hsl; + if (o instanceof Hsl) return o; + o = o.rgb(); + var r = o.r / 255, + g = o.g / 255, + b = o.b / 255, + min = Math.min(r, g, b), + max = Math.max(r, g, b), + h = NaN, + s = max - min, + l = (max + min) / 2; + if (s) { + if (r === max) h = (g - b) / s + (g < b) * 6; + else if (g === max) h = (b - r) / s + 2; + else h = (r - g) / s + 4; + s /= l < 0.5 ? max + min : 2 - max - min; + h *= 60; + } else { + s = l > 0 && l < 1 ? 0 : h; + } + return new Hsl(h, s, l, o.opacity); +} + +function hsl$2(h, s, l, opacity) { + return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity); +} + +function Hsl(h, s, l, opacity) { + this.h = +h; + this.s = +s; + this.l = +l; + this.opacity = +opacity; +} + +define(Hsl, hsl$2, extend(Color, { + brighter: function(k) { + k = k == null ? brighter : Math.pow(brighter, k); + return new Hsl(this.h, this.s, this.l * k, this.opacity); + }, + darker: function(k) { + k = k == null ? darker : Math.pow(darker, k); + return new Hsl(this.h, this.s, this.l * k, this.opacity); + }, + rgb: function() { + var h = this.h % 360 + (this.h < 0) * 360, + s = isNaN(h) || isNaN(this.s) ? 0 : this.s, + l = this.l, + m2 = l + (l < 0.5 ? l : 1 - l) * s, + m1 = 2 * l - m2; + return new Rgb( + hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2), + hsl2rgb(h, m1, m2), + hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2), + this.opacity + ); + }, + displayable: function() { + return (0 <= this.s && this.s <= 1 || isNaN(this.s)) + && (0 <= this.l && this.l <= 1) + && (0 <= this.opacity && this.opacity <= 1); + }, + formatHsl: function() { + var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a)); + return (a === 1 ? "hsl(" : "hsla(") + + (this.h || 0) + ", " + + (this.s || 0) * 100 + "%, " + + (this.l || 0) * 100 + "%" + + (a === 1 ? ")" : ", " + a + ")"); + } +})); + +/* From FvD 13.37, CSS Color Module Level 3 */ +function hsl2rgb(h, m1, m2) { + return (h < 60 ? m1 + (m2 - m1) * h / 60 + : h < 180 ? m2 + : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 + : m1) * 255; +} + +const radians$1 = Math.PI / 180; +const degrees$2 = 180 / Math.PI; + +// https://observablehq.com/@mbostock/lab-and-rgb +const K = 18, + Xn = 0.96422, + Yn = 1, + Zn = 0.82521, + t0$1 = 4 / 29, + t1$1 = 6 / 29, + t2 = 3 * t1$1 * t1$1, + t3 = t1$1 * t1$1 * t1$1; + +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); +} + +function gray(l, opacity) { + return new Lab(l, 0, 0, opacity == null ? 1 : opacity); +} + +function lab$1(l, a, b, opacity) { + return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity); +} + +function Lab(l, a, b, opacity) { + this.l = +l; + this.a = +a; + this.b = +b; + this.opacity = +opacity; +} + +define(Lab, lab$1, extend(Color, { + brighter: function(k) { + return new Lab(this.l + K * (k == null ? 1 : k), this.a, this.b, this.opacity); + }, + darker: function(k) { + return new Lab(this.l - K * (k == null ? 1 : k), this.a, this.b, this.opacity); + }, + rgb: function() { + 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$1; +} + +function lab2xyz(t) { + return t > t1$1 ? t * t * t : t2 * (t - t0$1); +} + +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$2; + return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity); +} + +function lch(l, c, h, opacity) { + return arguments.length === 1 ? hclConvert(l) : new Hcl(h, c, l, opacity == null ? 1 : opacity); +} + +function hcl$2(h, c, l, opacity) { + return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity); +} + +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$1; + return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity); +} + +define(Hcl, hcl$2, extend(Color, { + brighter: function(k) { + return new Hcl(this.h, this.c, this.l + K * (k == null ? 1 : k), this.opacity); + }, + darker: function(k) { + return new Hcl(this.h, this.c, this.l - K * (k == null ? 1 : k), this.opacity); + }, + rgb: function() { + return hcl2lab(this).rgb(); + } +})); + +var A = -0.14861, + B$1 = +1.78277, + C = -0.29227, + D$1 = -0.90649, + E = +1.97294, + ED = E * D$1, + EB = E * B$1, + BC_DA = B$1 * C - D$1 * 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$1, + 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$2 - 120 : NaN; + return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity); +} + +function cubehelix$3(h, s, l, opacity) { + return arguments.length === 1 ? cubehelixConvert(h) : new Cubehelix(h, s, l, opacity == null ? 1 : opacity); +} + +function Cubehelix(h, s, l, opacity) { + this.h = +h; + this.s = +s; + this.l = +l; + this.opacity = +opacity; +} + +define(Cubehelix, cubehelix$3, extend(Color, { + brighter: function(k) { + k = k == null ? brighter : Math.pow(brighter, k); + return new Cubehelix(this.h, this.s, this.l * k, this.opacity); + }, + darker: function(k) { + k = k == null ? darker : Math.pow(darker, k); + return new Cubehelix(this.h, this.s, this.l * k, this.opacity); + }, + rgb: function() { + var h = isNaN(this.h) ? 0 : (this.h + 120) * radians$1, + 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$1 * sinh)), + 255 * (l + a * (C * cosh + D$1 * sinh)), + 255 * (l + a * (E * cosh)), + this.opacity + ); + } +})); + +function basis$1(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$2(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$1((t - i / n) * n, v0, v1, v2, v3); + }; +} + +function basisClosed$1(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$1((t - i / n) * n, v0, v1, v2, v3); + }; +} + +var constant$8 = x => () => x; + +function linear$2(a, d) { + return function(t) { + return a + t * d; + }; +} + +function exponential$1(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$2(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant$8(isNaN(a) ? b : a); +} + +function gamma$1(y) { + return (y = +y) === 1 ? nogamma : function(a, b) { + return b - a ? exponential$1(a, b, y) : constant$8(isNaN(a) ? b : a); + }; +} + +function nogamma(a, b) { + var d = b - a; + return d ? linear$2(a, d) : constant$8(isNaN(a) ? b : a); +} + +var interpolateRgb = (function rgbGamma(y) { + var color = gamma$1(y); + + function rgb$1(start, end) { + var r = color((start = rgb(start)).r, (end = 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$1.gamma = rgbGamma; + + return rgb$1; +})(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 = 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$2); +var rgbBasisClosed = rgbSpline(basisClosed$1); + +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$3(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] = interpolate$2(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$1(a, b) { + var d = new Date; + return a = +a, b = +b, function(t) { + return d.setTime(a * (1 - t) + b * t), d; + }; +} + +function interpolateNumber(a, b) { + return a = +a, b = +b, function(t) { + return a * (1 - t) + b * t; + }; +} + +function object$1(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] = interpolate$2(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 interpolateString(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: interpolateNumber(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 interpolate$2(a, b) { + var t = typeof b, c; + return b == null || t === "boolean" ? constant$8(b) + : (t === "number" ? interpolateNumber + : t === "string" ? ((c = color(b)) ? (b = c, interpolateRgb) : interpolateString) + : b instanceof color ? interpolateRgb + : b instanceof Date ? date$1 + : isNumberArray(b) ? numberArray + : Array.isArray(b) ? genericArray + : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object$1 + : interpolateNumber)(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 interpolateRound(a, b) { + return a = +a, b = +b, function(t) { + return Math.round(a * (1 - t) + b * t); + }; +} + +var degrees$1 = 180 / Math.PI; + +var identity$7 = { + 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$1, + skewX: Math.atan(skewX) * degrees$1, + 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$7 : decompose(m.a, m.b, m.c, m.d, m.e, m.f); +} + +function parseSvg(value) { + if (value == null) return identity$7; + if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g"); + svgNode.setAttribute("transform", value); + if (!(value = svgNode.transform.baseVal.consolidate())) return identity$7; + 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: interpolateNumber(xa, xb)}, {i: i - 2, x: interpolateNumber(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: interpolateNumber(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: interpolateNumber(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: interpolateNumber(xa, xb)}, {i: i - 2, x: interpolateNumber(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$1 = 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 interpolateZoom = (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$1) { + 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 = hsl$2(start)).h, (end = hsl$2(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 = lab$1(start)).l, (end = lab$1(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 = hcl$2(start)).h, (end = hcl$2(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$1(hue) { + return (function cubehelixGamma(y) { + y = +y; + + function cubehelix(start, end) { + var h = hue((start = cubehelix$3(start)).h, (end = cubehelix$3(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$2 = cubehelix$1(hue$1); +var cubehelixLong = cubehelix$1(nogamma); + +function piecewise(interpolate, values) { + if (values === undefined) values = interpolate, interpolate = interpolate$2; + 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$1(interpolator, n) { + var samples = new Array(n); + for (var i = 0; i < n; ++i) samples[i] = interpolator(i / (n - 1)); + return samples; +} + +var frame = 0, // is an animation frame pending? + timeout$1 = 0, // is a timeout pending? + interval$1 = 0, // are any timers active? + pokeDelay = 1000, // how frequently we check for clock skew + taskHead, + taskTail, + clockLast = 0, + clockNow = 0, + clockSkew = 0, + clock = typeof performance === "object" && performance.now ? performance : Date, + setFrame = typeof window === "object" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : function(f) { setTimeout(f, 17); }; + +function now() { + return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew); +} + +function clearNow() { + clockNow = 0; +} + +function Timer() { + this._call = + this._time = + this._next = null; +} + +Timer.prototype = timer.prototype = { + constructor: Timer, + restart: function(callback, delay, time) { + if (typeof callback !== "function") throw new TypeError("callback is not a function"); + time = (time == null ? now() : +time) + (delay == null ? 0 : +delay); + if (!this._next && taskTail !== this) { + if (taskTail) taskTail._next = this; + else taskHead = this; + taskTail = this; + } + this._call = callback; + this._time = time; + sleep(); + }, + stop: function() { + if (this._call) { + this._call = null; + this._time = Infinity; + sleep(); + } + } +}; + +function timer(callback, delay, time) { + var t = new Timer; + t.restart(callback, delay, time); + return t; +} + +function timerFlush() { + now(); // Get the current time, if not already set. + ++frame; // Pretend we’ve set an alarm, if we haven’t already. + var t = taskHead, e; + while (t) { + if ((e = clockNow - t._time) >= 0) t._call.call(undefined, e); + t = t._next; + } + --frame; +} + +function wake() { + clockNow = (clockLast = clock.now()) + clockSkew; + frame = timeout$1 = 0; + try { + timerFlush(); + } finally { + frame = 0; + nap(); + clockNow = 0; + } +} + +function poke() { + var now = clock.now(), delay = now - clockLast; + if (delay > pokeDelay) clockSkew -= delay, clockLast = now; +} + +function nap() { + var t0, t1 = taskHead, t2, time = Infinity; + while (t1) { + if (t1._call) { + if (time > t1._time) time = t1._time; + t0 = t1, t1 = t1._next; + } else { + t2 = t1._next, t1._next = null; + t1 = t0 ? t0._next = t2 : taskHead = t2; + } + } + taskTail = t0; + sleep(time); +} + +function sleep(time) { + if (frame) return; // Soonest alarm already set, or will be. + if (timeout$1) timeout$1 = clearTimeout(timeout$1); + var delay = time - clockNow; // Strictly less than if we recomputed clockNow. + if (delay > 24) { + if (time < Infinity) timeout$1 = setTimeout(wake, time - clock.now() - clockSkew); + if (interval$1) interval$1 = clearInterval(interval$1); + } else { + if (!interval$1) clockLast = clock.now(), interval$1 = setInterval(poke, pokeDelay); + frame = 1, setFrame(wake); + } +} + +function timeout(callback, delay, time) { + var t = new Timer; + delay = delay == null ? 0 : +delay; + t.restart(elapsed => { + t.stop(); + callback(elapsed + delay); + }, delay, time); + return t; +} + +function interval(callback, delay, time) { + var t = new Timer, total = delay; + if (delay == null) return t.restart(callback, delay, time), t; + t._restart = t.restart; + t.restart = function(callback, delay, time) { + delay = +delay, time = time == null ? now() : +time; + t._restart(function tick(elapsed) { + elapsed += total; + t._restart(tick, total += delay, time); + callback(elapsed); + }, delay, time); + }; + t.restart(callback, delay, time); + return t; +} + +var emptyOn = dispatch("start", "end", "cancel", "interrupt"); +var emptyTween = []; + +var CREATED = 0; +var SCHEDULED = 1; +var STARTING = 2; +var STARTED = 3; +var RUNNING = 4; +var ENDING = 5; +var ENDED = 6; + +function schedule(node, name, id, index, group, timing) { + var schedules = node.__transition; + if (!schedules) node.__transition = {}; + else if (id in schedules) return; + create(node, id, { + name: name, + index: index, // For context during callback. + group: group, // For context during callback. + on: emptyOn, + tween: emptyTween, + time: timing.time, + delay: timing.delay, + duration: timing.duration, + ease: timing.ease, + timer: null, + state: CREATED + }); +} + +function init(node, id) { + var schedule = get(node, id); + if (schedule.state > CREATED) throw new Error("too late; already scheduled"); + return schedule; +} + +function set(node, id) { + var schedule = get(node, id); + if (schedule.state > STARTED) throw new Error("too late; already running"); + return schedule; +} + +function get(node, id) { + var schedule = node.__transition; + if (!schedule || !(schedule = schedule[id])) throw new Error("transition not found"); + return schedule; +} + +function create(node, id, self) { + var schedules = node.__transition, + tween; + + // Initialize the self timer when the transition is created. + // Note the actual delay is not known until the first callback! + schedules[id] = self; + self.timer = timer(schedule, 0, self.time); + + function schedule(elapsed) { + self.state = SCHEDULED; + self.timer.restart(start, self.delay, self.time); + + // If the elapsed delay is less than our first sleep, start immediately. + if (self.delay <= elapsed) start(elapsed - self.delay); + } + + function start(elapsed) { + var i, j, n, o; + + // If the state is not SCHEDULED, then we previously errored on start. + if (self.state !== SCHEDULED) return stop(); + + for (i in schedules) { + o = schedules[i]; + if (o.name !== self.name) continue; + + // While this element already has a starting transition during this frame, + // defer starting an interrupting transition until that transition has a + // chance to tick (and possibly end); see d3/d3-transition#54! + if (o.state === STARTED) return timeout(start); + + // Interrupt the active transition, if any. + if (o.state === RUNNING) { + o.state = ENDED; + o.timer.stop(); + o.on.call("interrupt", node, node.__data__, o.index, o.group); + delete schedules[i]; + } + + // Cancel any pre-empted transitions. + else if (+i < id) { + o.state = ENDED; + o.timer.stop(); + o.on.call("cancel", node, node.__data__, o.index, o.group); + delete schedules[i]; + } + } + + // Defer the first tick to end of the current frame; see d3/d3#1576. + // Note the transition may be canceled after start and before the first tick! + // Note this must be scheduled before the start event; see d3/d3-transition#16! + // Assuming this is successful, subsequent callbacks go straight to tick. + timeout(function() { + if (self.state === STARTED) { + self.state = RUNNING; + self.timer.restart(tick, self.delay, self.time); + tick(elapsed); + } + }); + + // Dispatch the start event. + // Note this must be done before the tween are initialized. + self.state = STARTING; + self.on.call("start", node, node.__data__, self.index, self.group); + if (self.state !== STARTING) return; // interrupted + self.state = STARTED; + + // Initialize the tween, deleting null tween. + tween = new Array(n = self.tween.length); + for (i = 0, j = -1; i < n; ++i) { + if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) { + tween[++j] = o; + } + } + tween.length = j + 1; + } + + function tick(elapsed) { + var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1), + i = -1, + n = tween.length; + + while (++i < n) { + tween[i].call(node, t); + } + + // Dispatch the end event. + if (self.state === ENDING) { + self.on.call("end", node, node.__data__, self.index, self.group); + stop(); + } + } + + function stop() { + self.state = ENDED; + self.timer.stop(); + delete schedules[id]; + for (var i in schedules) return; // eslint-disable-line no-unused-vars + delete node.__transition; + } +} + +function interrupt(node, name) { + var schedules = node.__transition, + schedule, + active, + empty = true, + i; + + if (!schedules) return; + + name = name == null ? null : name + ""; + + for (i in schedules) { + if ((schedule = schedules[i]).name !== name) { empty = false; continue; } + active = schedule.state > STARTING && schedule.state < ENDING; + schedule.state = ENDED; + schedule.timer.stop(); + schedule.on.call(active ? "interrupt" : "cancel", node, node.__data__, schedule.index, schedule.group); + delete schedules[i]; + } + + if (empty) delete node.__transition; +} + +function selection_interrupt(name) { + return this.each(function() { + interrupt(this, name); + }); +} + +function tweenRemove(id, name) { + var tween0, tween1; + return function() { + var schedule = set(this, id), + tween = schedule.tween; + + // If this node shared tween with the previous node, + // just assign the updated shared tween and we’re done! + // Otherwise, copy-on-write. + if (tween !== tween0) { + tween1 = tween0 = tween; + for (var i = 0, n = tween1.length; i < n; ++i) { + if (tween1[i].name === name) { + tween1 = tween1.slice(); + tween1.splice(i, 1); + break; + } + } + } + + schedule.tween = tween1; + }; +} + +function tweenFunction(id, name, value) { + var tween0, tween1; + if (typeof value !== "function") throw new Error; + return function() { + var schedule = set(this, id), + tween = schedule.tween; + + // If this node shared tween with the previous node, + // just assign the updated shared tween and we’re done! + // Otherwise, copy-on-write. + if (tween !== tween0) { + tween1 = (tween0 = tween).slice(); + for (var t = {name: name, value: value}, i = 0, n = tween1.length; i < n; ++i) { + if (tween1[i].name === name) { + tween1[i] = t; + break; + } + } + if (i === n) tween1.push(t); + } + + schedule.tween = tween1; + }; +} + +function transition_tween(name, value) { + var id = this._id; + + name += ""; + + if (arguments.length < 2) { + var tween = get(this.node(), id).tween; + for (var i = 0, n = tween.length, t; i < n; ++i) { + if ((t = tween[i]).name === name) { + return t.value; + } + } + return null; + } + + return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value)); +} + +function tweenValue(transition, name, value) { + var id = transition._id; + + transition.each(function() { + var schedule = set(this, id); + (schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments); + }); + + return function(node) { + return get(node, id).value[name]; + }; +} + +function interpolate$1(a, b) { + var c; + return (typeof b === "number" ? interpolateNumber + : b instanceof color ? interpolateRgb + : (c = color(b)) ? (b = c, interpolateRgb) + : interpolateString)(a, b); +} + +function attrRemove(name) { + return function() { + this.removeAttribute(name); + }; +} + +function attrRemoveNS(fullname) { + return function() { + this.removeAttributeNS(fullname.space, fullname.local); + }; +} + +function attrConstant(name, interpolate, value1) { + var string00, + string1 = value1 + "", + interpolate0; + return function() { + var string0 = this.getAttribute(name); + return string0 === string1 ? null + : string0 === string00 ? interpolate0 + : interpolate0 = interpolate(string00 = string0, value1); + }; +} + +function attrConstantNS(fullname, interpolate, value1) { + var string00, + string1 = value1 + "", + interpolate0; + return function() { + var string0 = this.getAttributeNS(fullname.space, fullname.local); + return string0 === string1 ? null + : string0 === string00 ? interpolate0 + : interpolate0 = interpolate(string00 = string0, value1); + }; +} + +function attrFunction(name, interpolate, value) { + var string00, + string10, + interpolate0; + return function() { + var string0, value1 = value(this), string1; + if (value1 == null) return void this.removeAttribute(name); + string0 = this.getAttribute(name); + string1 = value1 + ""; + return string0 === string1 ? null + : string0 === string00 && string1 === string10 ? interpolate0 + : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1)); + }; +} + +function attrFunctionNS(fullname, interpolate, value) { + var string00, + string10, + interpolate0; + return function() { + var string0, value1 = value(this), string1; + if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local); + string0 = this.getAttributeNS(fullname.space, fullname.local); + string1 = value1 + ""; + return string0 === string1 ? null + : string0 === string00 && string1 === string10 ? interpolate0 + : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1)); + }; +} + +function transition_attr(name, value) { + var fullname = namespace(name), i = fullname === "transform" ? interpolateTransformSvg : interpolate$1; + return this.attrTween(name, typeof value === "function" + ? (fullname.local ? attrFunctionNS : attrFunction)(fullname, i, tweenValue(this, "attr." + name, value)) + : value == null ? (fullname.local ? attrRemoveNS : attrRemove)(fullname) + : (fullname.local ? attrConstantNS : attrConstant)(fullname, i, value)); +} + +function attrInterpolate(name, i) { + return function(t) { + this.setAttribute(name, i.call(this, t)); + }; +} + +function attrInterpolateNS(fullname, i) { + return function(t) { + this.setAttributeNS(fullname.space, fullname.local, i.call(this, t)); + }; +} + +function attrTweenNS(fullname, value) { + var t0, i0; + function tween() { + var i = value.apply(this, arguments); + if (i !== i0) t0 = (i0 = i) && attrInterpolateNS(fullname, i); + return t0; + } + tween._value = value; + return tween; +} + +function attrTween(name, value) { + var t0, i0; + function tween() { + var i = value.apply(this, arguments); + if (i !== i0) t0 = (i0 = i) && attrInterpolate(name, i); + return t0; + } + tween._value = value; + return tween; +} + +function transition_attrTween(name, value) { + var key = "attr." + name; + if (arguments.length < 2) return (key = this.tween(key)) && key._value; + if (value == null) return this.tween(key, null); + if (typeof value !== "function") throw new Error; + var fullname = namespace(name); + return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value)); +} + +function delayFunction(id, value) { + return function() { + init(this, id).delay = +value.apply(this, arguments); + }; +} + +function delayConstant(id, value) { + return value = +value, function() { + init(this, id).delay = value; + }; +} + +function transition_delay(value) { + var id = this._id; + + return arguments.length + ? this.each((typeof value === "function" + ? delayFunction + : delayConstant)(id, value)) + : get(this.node(), id).delay; +} + +function durationFunction(id, value) { + return function() { + set(this, id).duration = +value.apply(this, arguments); + }; +} + +function durationConstant(id, value) { + return value = +value, function() { + set(this, id).duration = value; + }; +} + +function transition_duration(value) { + var id = this._id; + + return arguments.length + ? this.each((typeof value === "function" + ? durationFunction + : durationConstant)(id, value)) + : get(this.node(), id).duration; +} + +function easeConstant(id, value) { + if (typeof value !== "function") throw new Error; + return function() { + set(this, id).ease = value; + }; +} + +function transition_ease(value) { + var id = this._id; + + return arguments.length + ? this.each(easeConstant(id, value)) + : get(this.node(), id).ease; +} + +function easeVarying(id, value) { + return function() { + var v = value.apply(this, arguments); + if (typeof v !== "function") throw new Error; + set(this, id).ease = v; + }; +} + +function transition_easeVarying(value) { + if (typeof value !== "function") throw new Error; + return this.each(easeVarying(this._id, value)); +} + +function transition_filter(match) { + if (typeof match !== "function") match = matcher(match); + + for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) { + if ((node = group[i]) && match.call(node, node.__data__, i, group)) { + subgroup.push(node); + } + } + } + + return new Transition(subgroups, this._parents, this._name, this._id); +} + +function transition_merge(transition) { + if (transition._id !== this._id) throw new Error; + + for (var groups0 = this._groups, groups1 = transition._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) { + for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) { + if (node = group0[i] || group1[i]) { + merge[i] = node; + } + } + } + + for (; j < m0; ++j) { + merges[j] = groups0[j]; + } + + return new Transition(merges, this._parents, this._name, this._id); +} + +function start(name) { + return (name + "").trim().split(/^|\s+/).every(function(t) { + var i = t.indexOf("."); + if (i >= 0) t = t.slice(0, i); + return !t || t === "start"; + }); +} + +function onFunction(id, name, listener) { + var on0, on1, sit = start(name) ? init : set; + return function() { + var schedule = sit(this, id), + on = schedule.on; + + // If this node shared a dispatch with the previous node, + // just assign the updated shared dispatch and we’re done! + // Otherwise, copy-on-write. + if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener); + + schedule.on = on1; + }; +} + +function transition_on(name, listener) { + var id = this._id; + + return arguments.length < 2 + ? get(this.node(), id).on.on(name) + : this.each(onFunction(id, name, listener)); +} + +function removeFunction(id) { + return function() { + var parent = this.parentNode; + for (var i in this.__transition) if (+i !== id) return; + if (parent) parent.removeChild(this); + }; +} + +function transition_remove() { + return this.on("end.remove", removeFunction(this._id)); +} + +function transition_select(select) { + var name = this._name, + id = this._id; + + if (typeof select !== "function") select = selector(select); + + for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) { + if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) { + if ("__data__" in node) subnode.__data__ = node.__data__; + subgroup[i] = subnode; + schedule(subgroup[i], name, id, i, subgroup, get(node, id)); + } + } + } + + return new Transition(subgroups, this._parents, name, id); +} + +function transition_selectAll(select) { + var name = this._name, + id = this._id; + + if (typeof select !== "function") select = selectorAll(select); + + for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) { + if (node = group[i]) { + for (var children = select.call(node, node.__data__, i, group), child, inherit = get(node, id), k = 0, l = children.length; k < l; ++k) { + if (child = children[k]) { + schedule(child, name, id, k, children, inherit); + } + } + subgroups.push(children); + parents.push(node); + } + } + } + + return new Transition(subgroups, parents, name, id); +} + +var Selection = selection.prototype.constructor; + +function transition_selection() { + return new Selection(this._groups, this._parents); +} + +function styleNull(name, interpolate) { + var string00, + string10, + interpolate0; + return function() { + var string0 = styleValue(this, name), + string1 = (this.style.removeProperty(name), styleValue(this, name)); + return string0 === string1 ? null + : string0 === string00 && string1 === string10 ? interpolate0 + : interpolate0 = interpolate(string00 = string0, string10 = string1); + }; +} + +function styleRemove(name) { + return function() { + this.style.removeProperty(name); + }; +} + +function styleConstant(name, interpolate, value1) { + var string00, + string1 = value1 + "", + interpolate0; + return function() { + var string0 = styleValue(this, name); + return string0 === string1 ? null + : string0 === string00 ? interpolate0 + : interpolate0 = interpolate(string00 = string0, value1); + }; +} + +function styleFunction(name, interpolate, value) { + var string00, + string10, + interpolate0; + return function() { + var string0 = styleValue(this, name), + value1 = value(this), + string1 = value1 + ""; + if (value1 == null) string1 = value1 = (this.style.removeProperty(name), styleValue(this, name)); + return string0 === string1 ? null + : string0 === string00 && string1 === string10 ? interpolate0 + : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1)); + }; +} + +function styleMaybeRemove(id, name) { + var on0, on1, listener0, key = "style." + name, event = "end." + key, remove; + return function() { + var schedule = set(this, id), + on = schedule.on, + listener = schedule.value[key] == null ? remove || (remove = styleRemove(name)) : undefined; + + // If this node shared a dispatch with the previous node, + // just assign the updated shared dispatch and we’re done! + // Otherwise, copy-on-write. + if (on !== on0 || listener0 !== listener) (on1 = (on0 = on).copy()).on(event, listener0 = listener); + + schedule.on = on1; + }; +} + +function transition_style(name, value, priority) { + var i = (name += "") === "transform" ? interpolateTransformCss : interpolate$1; + return value == null ? this + .styleTween(name, styleNull(name, i)) + .on("end.style." + name, styleRemove(name)) + : typeof value === "function" ? this + .styleTween(name, styleFunction(name, i, tweenValue(this, "style." + name, value))) + .each(styleMaybeRemove(this._id, name)) + : this + .styleTween(name, styleConstant(name, i, value), priority) + .on("end.style." + name, null); +} + +function styleInterpolate(name, i, priority) { + return function(t) { + this.style.setProperty(name, i.call(this, t), priority); + }; +} + +function styleTween(name, value, priority) { + var t, i0; + function tween() { + var i = value.apply(this, arguments); + if (i !== i0) t = (i0 = i) && styleInterpolate(name, i, priority); + return t; + } + tween._value = value; + return tween; +} + +function transition_styleTween(name, value, priority) { + var key = "style." + (name += ""); + if (arguments.length < 2) return (key = this.tween(key)) && key._value; + if (value == null) return this.tween(key, null); + if (typeof value !== "function") throw new Error; + return this.tween(key, styleTween(name, value, priority == null ? "" : priority)); +} + +function textConstant(value) { + return function() { + this.textContent = value; + }; +} + +function textFunction(value) { + return function() { + var value1 = value(this); + this.textContent = value1 == null ? "" : value1; + }; +} + +function transition_text(value) { + return this.tween("text", typeof value === "function" + ? textFunction(tweenValue(this, "text", value)) + : textConstant(value == null ? "" : value + "")); +} + +function textInterpolate(i) { + return function(t) { + this.textContent = i.call(this, t); + }; +} + +function textTween(value) { + var t0, i0; + function tween() { + var i = value.apply(this, arguments); + if (i !== i0) t0 = (i0 = i) && textInterpolate(i); + return t0; + } + tween._value = value; + return tween; +} + +function transition_textTween(value) { + var key = "text"; + if (arguments.length < 1) return (key = this.tween(key)) && key._value; + if (value == null) return this.tween(key, null); + if (typeof value !== "function") throw new Error; + return this.tween(key, textTween(value)); +} + +function transition_transition() { + var name = this._name, + id0 = this._id, + id1 = newId(); + + for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) { + if (node = group[i]) { + var inherit = get(node, id0); + schedule(node, name, id1, i, group, { + time: inherit.time + inherit.delay + inherit.duration, + delay: 0, + duration: inherit.duration, + ease: inherit.ease + }); + } + } + } + + return new Transition(groups, this._parents, name, id1); +} + +function transition_end() { + var on0, on1, that = this, id = that._id, size = that.size(); + return new Promise(function(resolve, reject) { + var cancel = {value: reject}, + end = {value: function() { if (--size === 0) resolve(); }}; + + that.each(function() { + var schedule = set(this, id), + on = schedule.on; + + // If this node shared a dispatch with the previous node, + // just assign the updated shared dispatch and we’re done! + // Otherwise, copy-on-write. + if (on !== on0) { + on1 = (on0 = on).copy(); + on1._.cancel.push(cancel); + on1._.interrupt.push(cancel); + on1._.end.push(end); + } + + schedule.on = on1; + }); + + // The selection was empty, resolve end immediately + if (size === 0) resolve(); + }); +} + +var id = 0; + +function Transition(groups, parents, name, id) { + this._groups = groups; + this._parents = parents; + this._name = name; + this._id = id; +} + +function transition(name) { + return selection().transition(name); +} + +function newId() { + return ++id; +} + +var selection_prototype = selection.prototype; + +Transition.prototype = transition.prototype = { + constructor: Transition, + select: transition_select, + selectAll: transition_selectAll, + selectChild: selection_prototype.selectChild, + selectChildren: selection_prototype.selectChildren, + filter: transition_filter, + merge: transition_merge, + selection: transition_selection, + transition: transition_transition, + call: selection_prototype.call, + nodes: selection_prototype.nodes, + node: selection_prototype.node, + size: selection_prototype.size, + empty: selection_prototype.empty, + each: selection_prototype.each, + on: transition_on, + attr: transition_attr, + attrTween: transition_attrTween, + style: transition_style, + styleTween: transition_styleTween, + text: transition_text, + textTween: transition_textTween, + remove: transition_remove, + tween: transition_tween, + delay: transition_delay, + duration: transition_duration, + ease: transition_ease, + easeVarying: transition_easeVarying, + end: transition_end, + [Symbol.iterator]: selection_prototype[Symbol.iterator] +}; + +const linear$1 = 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$1 = 3; + +var polyIn = (function custom(e) { + e = +e; + + function polyIn(t) { + return Math.pow(t, e); + } + + polyIn.exponent = custom; + + return polyIn; +})(exponent$1); + +var polyOut = (function custom(e) { + e = +e; + + function polyOut(t) { + return 1 - Math.pow(1 - t, e); + } + + polyOut.exponent = custom; + + return polyOut; +})(exponent$1); + +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$1); + +var pi$4 = Math.PI, + halfPi$3 = pi$4 / 2; + +function sinIn(t) { + return (+t === 1) ? 1 : 1 - Math.cos(t * halfPi$3); +} + +function sinOut(t) { + return Math.sin(t * halfPi$3); +} + +function sinInOut(t) { + return (1 - Math.cos(pi$4 * 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$5 = 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$5); + + function elasticIn(t) { + return a * tpmt(-(--t)) * Math.sin((s - t) / p); + } + + elasticIn.amplitude = function(a) { return custom(a, p * tau$5); }; + 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$5); + + function elasticOut(t) { + return 1 - a * tpmt(t = +t) * Math.sin((t + s) / p); + } + + elasticOut.amplitude = function(a) { return custom(a, p * tau$5); }; + 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$5); + + 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$5); }; + elasticInOut.period = function(p) { return custom(a, p); }; + + return elasticInOut; +})(amplitude, period); + +var defaultTiming = { + time: null, // Set on use. + delay: 0, + duration: 250, + ease: cubicInOut +}; + +function inherit(node, id) { + var timing; + while (!(timing = node.__transition) || !(timing = timing[id])) { + if (!(node = node.parentNode)) { + throw new Error(`transition ${id} not found`); + } + } + return timing; +} + +function selection_transition(name) { + var id, + timing; + + if (name instanceof Transition) { + id = name._id, name = name._name; + } else { + id = newId(), (timing = defaultTiming).time = now(), name = name == null ? null : name + ""; + } + + for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) { + if (node = group[i]) { + schedule(node, name, id, i, group, timing || inherit(node, id)); + } + } + } + + return new Transition(groups, this._parents, name, id); +} + +selection.prototype.interrupt = selection_interrupt; +selection.prototype.transition = selection_transition; + +var root = [null]; + +function active(node, name) { + var schedules = node.__transition, + schedule, + i; + + if (schedules) { + name = name == null ? null : name + ""; + for (i in schedules) { + if ((schedule = schedules[i]).state > SCHEDULED && schedule.name === name) { + return new Transition([[node]], root, name, +i); + } + } + } + + return null; +} + +var constant$7 = x => () => x; + +function BrushEvent(type, { + sourceEvent, + target, + selection, + mode, + dispatch +}) { + Object.defineProperties(this, { + type: {value: type, enumerable: true, configurable: true}, + sourceEvent: {value: sourceEvent, enumerable: true, configurable: true}, + target: {value: target, enumerable: true, configurable: true}, + selection: {value: selection, enumerable: true, configurable: true}, + mode: {value: mode, enumerable: true, configurable: true}, + _: {value: dispatch} + }); +} + +function nopropagation$1(event) { + event.stopImmediatePropagation(); +} + +function noevent$1(event) { + event.preventDefault(); + event.stopImmediatePropagation(); +} + +var MODE_DRAG = {name: "drag"}, + MODE_SPACE = {name: "space"}, + MODE_HANDLE = {name: "handle"}, + MODE_CENTER = {name: "center"}; + +const {abs: abs$3, max: max$2, min: min$1} = Math; + +function number1(e) { + return [+e[0], +e[1]]; +} + +function number2(e) { + return [number1(e[0]), number1(e[1])]; +} + +var X = { + name: "x", + handles: ["w", "e"].map(type), + input: function(x, e) { return x == null ? null : [[+x[0], e[0][1]], [+x[1], e[1][1]]]; }, + output: function(xy) { return xy && [xy[0][0], xy[1][0]]; } +}; + +var Y = { + name: "y", + handles: ["n", "s"].map(type), + input: function(y, e) { return y == null ? null : [[e[0][0], +y[0]], [e[1][0], +y[1]]]; }, + output: function(xy) { return xy && [xy[0][1], xy[1][1]]; } +}; + +var XY = { + name: "xy", + handles: ["n", "w", "e", "s", "nw", "ne", "sw", "se"].map(type), + input: function(xy) { return xy == null ? null : number2(xy); }, + output: function(xy) { return xy; } +}; + +var cursors = { + overlay: "crosshair", + selection: "move", + n: "ns-resize", + e: "ew-resize", + s: "ns-resize", + w: "ew-resize", + nw: "nwse-resize", + ne: "nesw-resize", + se: "nwse-resize", + sw: "nesw-resize" +}; + +var flipX = { + e: "w", + w: "e", + nw: "ne", + ne: "nw", + se: "sw", + sw: "se" +}; + +var flipY = { + n: "s", + s: "n", + nw: "sw", + ne: "se", + se: "ne", + sw: "nw" +}; + +var signsX = { + overlay: +1, + selection: +1, + n: null, + e: +1, + s: null, + w: -1, + nw: -1, + ne: +1, + se: +1, + sw: -1 +}; + +var signsY = { + overlay: +1, + selection: +1, + n: -1, + e: null, + s: +1, + w: null, + nw: -1, + ne: -1, + se: +1, + sw: +1 +}; + +function type(t) { + return {type: t}; +} + +// Ignore right-click, since that should open the context menu. +function defaultFilter$1(event) { + return !event.ctrlKey && !event.button; +} + +function defaultExtent$1() { + var svg = this.ownerSVGElement || this; + if (svg.hasAttribute("viewBox")) { + svg = svg.viewBox.baseVal; + return [[svg.x, svg.y], [svg.x + svg.width, svg.y + svg.height]]; + } + return [[0, 0], [svg.width.baseVal.value, svg.height.baseVal.value]]; +} + +function defaultTouchable$1() { + return navigator.maxTouchPoints || ("ontouchstart" in this); +} + +// Like d3.local, but with the name “__brush” rather than auto-generated. +function local(node) { + while (!node.__brush) if (!(node = node.parentNode)) return; + return node.__brush; +} + +function empty(extent) { + return extent[0][0] === extent[1][0] + || extent[0][1] === extent[1][1]; +} + +function brushSelection(node) { + var state = node.__brush; + return state ? state.dim.output(state.selection) : null; +} + +function brushX() { + return brush$1(X); +} + +function brushY() { + return brush$1(Y); +} + +function brush() { + return brush$1(XY); +} + +function brush$1(dim) { + var extent = defaultExtent$1, + filter = defaultFilter$1, + touchable = defaultTouchable$1, + keys = true, + listeners = dispatch("start", "brush", "end"), + handleSize = 6, + touchending; + + function brush(group) { + var overlay = group + .property("__brush", initialize) + .selectAll(".overlay") + .data([type("overlay")]); + + overlay.enter().append("rect") + .attr("class", "overlay") + .attr("pointer-events", "all") + .attr("cursor", cursors.overlay) + .merge(overlay) + .each(function() { + var extent = local(this).extent; + select(this) + .attr("x", extent[0][0]) + .attr("y", extent[0][1]) + .attr("width", extent[1][0] - extent[0][0]) + .attr("height", extent[1][1] - extent[0][1]); + }); + + group.selectAll(".selection") + .data([type("selection")]) + .enter().append("rect") + .attr("class", "selection") + .attr("cursor", cursors.selection) + .attr("fill", "#777") + .attr("fill-opacity", 0.3) + .attr("stroke", "#fff") + .attr("shape-rendering", "crispEdges"); + + var handle = group.selectAll(".handle") + .data(dim.handles, function(d) { return d.type; }); + + handle.exit().remove(); + + handle.enter().append("rect") + .attr("class", function(d) { return "handle handle--" + d.type; }) + .attr("cursor", function(d) { return cursors[d.type]; }); + + group + .each(redraw) + .attr("fill", "none") + .attr("pointer-events", "all") + .on("mousedown.brush", started) + .filter(touchable) + .on("touchstart.brush", started) + .on("touchmove.brush", touchmoved) + .on("touchend.brush touchcancel.brush", touchended) + .style("touch-action", "none") + .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)"); + } + + brush.move = function(group, selection, event) { + if (group.tween) { + group + .on("start.brush", function(event) { emitter(this, arguments).beforestart().start(event); }) + .on("interrupt.brush end.brush", function(event) { emitter(this, arguments).end(event); }) + .tween("brush", function() { + var that = this, + state = that.__brush, + emit = emitter(that, arguments), + selection0 = state.selection, + selection1 = dim.input(typeof selection === "function" ? selection.apply(this, arguments) : selection, state.extent), + i = interpolate$2(selection0, selection1); + + function tween(t) { + state.selection = t === 1 && selection1 === null ? null : i(t); + redraw.call(that); + emit.brush(); + } + + return selection0 !== null && selection1 !== null ? tween : tween(1); + }); + } else { + group + .each(function() { + var that = this, + args = arguments, + state = that.__brush, + selection1 = dim.input(typeof selection === "function" ? selection.apply(that, args) : selection, state.extent), + emit = emitter(that, args).beforestart(); + + interrupt(that); + state.selection = selection1 === null ? null : selection1; + redraw.call(that); + emit.start(event).brush(event).end(event); + }); + } + }; + + brush.clear = function(group, event) { + brush.move(group, null, event); + }; + + function redraw() { + var group = select(this), + selection = local(this).selection; + + if (selection) { + group.selectAll(".selection") + .style("display", null) + .attr("x", selection[0][0]) + .attr("y", selection[0][1]) + .attr("width", selection[1][0] - selection[0][0]) + .attr("height", selection[1][1] - selection[0][1]); + + group.selectAll(".handle") + .style("display", null) + .attr("x", function(d) { return d.type[d.type.length - 1] === "e" ? selection[1][0] - handleSize / 2 : selection[0][0] - handleSize / 2; }) + .attr("y", function(d) { return d.type[0] === "s" ? selection[1][1] - handleSize / 2 : selection[0][1] - handleSize / 2; }) + .attr("width", function(d) { return d.type === "n" || d.type === "s" ? selection[1][0] - selection[0][0] + handleSize : handleSize; }) + .attr("height", function(d) { return d.type === "e" || d.type === "w" ? selection[1][1] - selection[0][1] + handleSize : handleSize; }); + } + + else { + group.selectAll(".selection,.handle") + .style("display", "none") + .attr("x", null) + .attr("y", null) + .attr("width", null) + .attr("height", null); + } + } + + function emitter(that, args, clean) { + var emit = that.__brush.emitter; + return emit && (!clean || !emit.clean) ? emit : new Emitter(that, args, clean); + } + + function Emitter(that, args, clean) { + this.that = that; + this.args = args; + this.state = that.__brush; + this.active = 0; + this.clean = clean; + } + + Emitter.prototype = { + beforestart: function() { + if (++this.active === 1) this.state.emitter = this, this.starting = true; + return this; + }, + start: function(event, mode) { + if (this.starting) this.starting = false, this.emit("start", event, mode); + else this.emit("brush", event); + return this; + }, + brush: function(event, mode) { + this.emit("brush", event, mode); + return this; + }, + end: function(event, mode) { + if (--this.active === 0) delete this.state.emitter, this.emit("end", event, mode); + return this; + }, + emit: function(type, event, mode) { + var d = select(this.that).datum(); + listeners.call( + type, + this.that, + new BrushEvent(type, { + sourceEvent: event, + target: brush, + selection: dim.output(this.state.selection), + mode, + dispatch: listeners + }), + d + ); + } + }; + + function started(event) { + if (touchending && !event.touches) return; + if (!filter.apply(this, arguments)) return; + + var that = this, + type = event.target.__data__.type, + mode = (keys && event.metaKey ? type = "overlay" : type) === "selection" ? MODE_DRAG : (keys && event.altKey ? MODE_CENTER : MODE_HANDLE), + signX = dim === Y ? null : signsX[type], + signY = dim === X ? null : signsY[type], + state = local(that), + extent = state.extent, + selection = state.selection, + W = extent[0][0], w0, w1, + N = extent[0][1], n0, n1, + E = extent[1][0], e0, e1, + S = extent[1][1], s0, s1, + dx = 0, + dy = 0, + moving, + shifting = signX && signY && keys && event.shiftKey, + lockX, + lockY, + points = Array.from(event.touches || [event], t => { + const i = t.identifier; + t = pointer(t, that); + t.point0 = t.slice(); + t.identifier = i; + return t; + }); + + interrupt(that); + var emit = emitter(that, arguments, true).beforestart(); + + if (type === "overlay") { + if (selection) moving = true; + const pts = [points[0], points[1] || points[0]]; + state.selection = selection = [[ + w0 = dim === Y ? W : min$1(pts[0][0], pts[1][0]), + n0 = dim === X ? N : min$1(pts[0][1], pts[1][1]) + ], [ + e0 = dim === Y ? E : max$2(pts[0][0], pts[1][0]), + s0 = dim === X ? S : max$2(pts[0][1], pts[1][1]) + ]]; + if (points.length > 1) move(event); + } else { + w0 = selection[0][0]; + n0 = selection[0][1]; + e0 = selection[1][0]; + s0 = selection[1][1]; + } + + w1 = w0; + n1 = n0; + e1 = e0; + s1 = s0; + + var group = select(that) + .attr("pointer-events", "none"); + + var overlay = group.selectAll(".overlay") + .attr("cursor", cursors[type]); + + if (event.touches) { + emit.moved = moved; + emit.ended = ended; + } else { + var view = select(event.view) + .on("mousemove.brush", moved, true) + .on("mouseup.brush", ended, true); + if (keys) view + .on("keydown.brush", keydowned, true) + .on("keyup.brush", keyupped, true); + + dragDisable(event.view); + } + + redraw.call(that); + emit.start(event, mode.name); + + function moved(event) { + for (const p of event.changedTouches || [event]) { + for (const d of points) + if (d.identifier === p.identifier) d.cur = pointer(p, that); + } + if (shifting && !lockX && !lockY && points.length === 1) { + const point = points[0]; + if (abs$3(point.cur[0] - point[0]) > abs$3(point.cur[1] - point[1])) + lockY = true; + else + lockX = true; + } + for (const point of points) + if (point.cur) point[0] = point.cur[0], point[1] = point.cur[1]; + moving = true; + noevent$1(event); + move(event); + } + + function move(event) { + const point = points[0], point0 = point.point0; + var t; + + dx = point[0] - point0[0]; + dy = point[1] - point0[1]; + + switch (mode) { + case MODE_SPACE: + case MODE_DRAG: { + if (signX) dx = max$2(W - w0, min$1(E - e0, dx)), w1 = w0 + dx, e1 = e0 + dx; + if (signY) dy = max$2(N - n0, min$1(S - s0, dy)), n1 = n0 + dy, s1 = s0 + dy; + break; + } + case MODE_HANDLE: { + if (points[1]) { + if (signX) w1 = max$2(W, min$1(E, points[0][0])), e1 = max$2(W, min$1(E, points[1][0])), signX = 1; + if (signY) n1 = max$2(N, min$1(S, points[0][1])), s1 = max$2(N, min$1(S, points[1][1])), signY = 1; + } else { + if (signX < 0) dx = max$2(W - w0, min$1(E - w0, dx)), w1 = w0 + dx, e1 = e0; + else if (signX > 0) dx = max$2(W - e0, min$1(E - e0, dx)), w1 = w0, e1 = e0 + dx; + if (signY < 0) dy = max$2(N - n0, min$1(S - n0, dy)), n1 = n0 + dy, s1 = s0; + else if (signY > 0) dy = max$2(N - s0, min$1(S - s0, dy)), n1 = n0, s1 = s0 + dy; + } + break; + } + case MODE_CENTER: { + if (signX) w1 = max$2(W, min$1(E, w0 - dx * signX)), e1 = max$2(W, min$1(E, e0 + dx * signX)); + if (signY) n1 = max$2(N, min$1(S, n0 - dy * signY)), s1 = max$2(N, min$1(S, s0 + dy * signY)); + break; + } + } + + if (e1 < w1) { + signX *= -1; + t = w0, w0 = e0, e0 = t; + t = w1, w1 = e1, e1 = t; + if (type in flipX) overlay.attr("cursor", cursors[type = flipX[type]]); + } + + if (s1 < n1) { + signY *= -1; + t = n0, n0 = s0, s0 = t; + t = n1, n1 = s1, s1 = t; + if (type in flipY) overlay.attr("cursor", cursors[type = flipY[type]]); + } + + if (state.selection) selection = state.selection; // May be set by brush.move! + if (lockX) w1 = selection[0][0], e1 = selection[1][0]; + if (lockY) n1 = selection[0][1], s1 = selection[1][1]; + + if (selection[0][0] !== w1 + || selection[0][1] !== n1 + || selection[1][0] !== e1 + || selection[1][1] !== s1) { + state.selection = [[w1, n1], [e1, s1]]; + redraw.call(that); + emit.brush(event, mode.name); + } + } + + function ended(event) { + nopropagation$1(event); + if (event.touches) { + if (event.touches.length) return; + if (touchending) clearTimeout(touchending); + touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed! + } else { + yesdrag(event.view, moving); + view.on("keydown.brush keyup.brush mousemove.brush mouseup.brush", null); + } + group.attr("pointer-events", "all"); + overlay.attr("cursor", cursors.overlay); + if (state.selection) selection = state.selection; // May be set by brush.move (on start)! + if (empty(selection)) state.selection = null, redraw.call(that); + emit.end(event, mode.name); + } + + function keydowned(event) { + switch (event.keyCode) { + case 16: { // SHIFT + shifting = signX && signY; + break; + } + case 18: { // ALT + if (mode === MODE_HANDLE) { + if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX; + if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY; + mode = MODE_CENTER; + move(event); + } + break; + } + case 32: { // SPACE; takes priority over ALT + if (mode === MODE_HANDLE || mode === MODE_CENTER) { + if (signX < 0) e0 = e1 - dx; else if (signX > 0) w0 = w1 - dx; + if (signY < 0) s0 = s1 - dy; else if (signY > 0) n0 = n1 - dy; + mode = MODE_SPACE; + overlay.attr("cursor", cursors.selection); + move(event); + } + break; + } + default: return; + } + noevent$1(event); + } + + function keyupped(event) { + switch (event.keyCode) { + case 16: { // SHIFT + if (shifting) { + lockX = lockY = shifting = false; + move(event); + } + break; + } + case 18: { // ALT + if (mode === MODE_CENTER) { + if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1; + if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1; + mode = MODE_HANDLE; + move(event); + } + break; + } + case 32: { // SPACE + if (mode === MODE_SPACE) { + if (event.altKey) { + if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX; + if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY; + mode = MODE_CENTER; + } else { + if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1; + if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1; + mode = MODE_HANDLE; + } + overlay.attr("cursor", cursors[type]); + move(event); + } + break; + } + default: return; + } + noevent$1(event); + } + } + + function touchmoved(event) { + emitter(this, arguments).moved(event); + } + + function touchended(event) { + emitter(this, arguments).ended(event); + } + + function initialize() { + var state = this.__brush || {selection: null}; + state.extent = number2(extent.apply(this, arguments)); + state.dim = dim; + return state; + } + + brush.extent = function(_) { + return arguments.length ? (extent = typeof _ === "function" ? _ : constant$7(number2(_)), brush) : extent; + }; + + brush.filter = function(_) { + return arguments.length ? (filter = typeof _ === "function" ? _ : constant$7(!!_), brush) : filter; + }; + + brush.touchable = function(_) { + return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$7(!!_), brush) : touchable; + }; + + brush.handleSize = function(_) { + return arguments.length ? (handleSize = +_, brush) : handleSize; + }; + + brush.keyModifiers = function(_) { + return arguments.length ? (keys = !!_, brush) : keys; + }; + + brush.on = function() { + var value = listeners.on.apply(listeners, arguments); + return value === listeners ? brush : value; + }; + + return brush; +} + +var abs$2 = Math.abs; +var cos$2 = Math.cos; +var sin$2 = Math.sin; +var pi$3 = Math.PI; +var halfPi$2 = pi$3 / 2; +var tau$4 = pi$3 * 2; +var max$1 = Math.max; +var epsilon$5 = 1e-12; + +function range$1(i, j) { + return Array.from({length: j - i}, (_, k) => i + k); +} + +function compareValue(compare) { + return function(a, b) { + return compare( + a.source.value + a.target.value, + b.source.value + b.target.value + ); + }; +} + +function chord() { + return chord$1(false, false); +} + +function chordTranspose() { + return chord$1(false, true); +} + +function chordDirected() { + return chord$1(true, false); +} + +function chord$1(directed, transpose) { + var padAngle = 0, + sortGroups = null, + sortSubgroups = null, + sortChords = null; + + function chord(matrix) { + var n = matrix.length, + groupSums = new Array(n), + groupIndex = range$1(0, n), + chords = new Array(n * n), + groups = new Array(n), + k = 0, dx; + + matrix = Float64Array.from({length: n * n}, transpose + ? (_, i) => matrix[i % n][i / n | 0] + : (_, i) => matrix[i / n | 0][i % n]); + + // Compute the scaling factor from value to angle in [0, 2pi]. + for (let i = 0; i < n; ++i) { + let x = 0; + for (let j = 0; j < n; ++j) x += matrix[i * n + j] + directed * matrix[j * n + i]; + k += groupSums[i] = x; + } + k = max$1(0, tau$4 - padAngle * n) / k; + dx = k ? padAngle : tau$4 / n; + + // Compute the angles for each group and constituent chord. + { + let x = 0; + if (sortGroups) groupIndex.sort((a, b) => sortGroups(groupSums[a], groupSums[b])); + for (const i of groupIndex) { + const x0 = x; + if (directed) { + const subgroupIndex = range$1(~n + 1, n).filter(j => j < 0 ? matrix[~j * n + i] : matrix[i * n + j]); + if (sortSubgroups) subgroupIndex.sort((a, b) => sortSubgroups(a < 0 ? -matrix[~a * n + i] : matrix[i * n + a], b < 0 ? -matrix[~b * n + i] : matrix[i * n + b])); + for (const j of subgroupIndex) { + if (j < 0) { + const chord = chords[~j * n + i] || (chords[~j * n + i] = {source: null, target: null}); + chord.target = {index: i, startAngle: x, endAngle: x += matrix[~j * n + i] * k, value: matrix[~j * n + i]}; + } else { + const chord = chords[i * n + j] || (chords[i * n + j] = {source: null, target: null}); + chord.source = {index: i, startAngle: x, endAngle: x += matrix[i * n + j] * k, value: matrix[i * n + j]}; + } + } + groups[i] = {index: i, startAngle: x0, endAngle: x, value: groupSums[i]}; + } else { + const subgroupIndex = range$1(0, n).filter(j => matrix[i * n + j] || matrix[j * n + i]); + if (sortSubgroups) subgroupIndex.sort((a, b) => sortSubgroups(matrix[i * n + a], matrix[i * n + b])); + for (const j of subgroupIndex) { + let chord; + if (i < j) { + chord = chords[i * n + j] || (chords[i * n + j] = {source: null, target: null}); + chord.source = {index: i, startAngle: x, endAngle: x += matrix[i * n + j] * k, value: matrix[i * n + j]}; + } else { + chord = chords[j * n + i] || (chords[j * n + i] = {source: null, target: null}); + chord.target = {index: i, startAngle: x, endAngle: x += matrix[i * n + j] * k, value: matrix[i * n + j]}; + if (i === j) chord.source = chord.target; + } + if (chord.source && chord.target && chord.source.value < chord.target.value) { + const source = chord.source; + chord.source = chord.target; + chord.target = source; + } + } + groups[i] = {index: i, startAngle: x0, endAngle: x, value: groupSums[i]}; + } + x += dx; + } + } + + // Remove empty chords. + chords = Object.values(chords); + chords.groups = groups; + return sortChords ? chords.sort(sortChords) : chords; + } + + chord.padAngle = function(_) { + return arguments.length ? (padAngle = max$1(0, _), chord) : padAngle; + }; + + chord.sortGroups = function(_) { + return arguments.length ? (sortGroups = _, chord) : sortGroups; + }; + + chord.sortSubgroups = function(_) { + return arguments.length ? (sortSubgroups = _, chord) : sortSubgroups; + }; + + chord.sortChords = function(_) { + return arguments.length ? (_ == null ? sortChords = null : (sortChords = compareValue(_))._ = _, chord) : sortChords && sortChords._; + }; + + return chord; +} + +const pi$2 = Math.PI, + tau$3 = 2 * pi$2, + epsilon$4 = 1e-6, + tauEpsilon = tau$3 - epsilon$4; + +function Path$1() { + this._x0 = this._y0 = // start of current subpath + this._x1 = this._y1 = null; // end of current subpath + this._ = ""; +} + +function path() { + return new Path$1; +} + +Path$1.prototype = path.prototype = { + constructor: Path$1, + moveTo: function(x, y) { + this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y); + }, + closePath: function() { + if (this._x1 !== null) { + this._x1 = this._x0, this._y1 = this._y0; + this._ += "Z"; + } + }, + lineTo: function(x, y) { + this._ += "L" + (this._x1 = +x) + "," + (this._y1 = +y); + }, + quadraticCurveTo: function(x1, y1, x, y) { + this._ += "Q" + (+x1) + "," + (+y1) + "," + (this._x1 = +x) + "," + (this._y1 = +y); + }, + bezierCurveTo: function(x1, y1, x2, y2, x, y) { + this._ += "C" + (+x1) + "," + (+y1) + "," + (+x2) + "," + (+y2) + "," + (this._x1 = +x) + "," + (this._y1 = +y); + }, + arcTo: function(x1, y1, x2, y2, r) { + x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r; + var x0 = this._x1, + y0 = this._y1, + x21 = x2 - x1, + y21 = y2 - y1, + x01 = x0 - x1, + y01 = y0 - y1, + l01_2 = x01 * x01 + y01 * y01; + + // Is the radius negative? Error. + if (r < 0) throw new Error("negative radius: " + r); + + // Is this path empty? Move to (x1,y1). + if (this._x1 === null) { + this._ += "M" + (this._x1 = x1) + "," + (this._y1 = y1); + } + + // Or, is (x1,y1) coincident with (x0,y0)? Do nothing. + else if (!(l01_2 > epsilon$4)); + + // Or, are (x0,y0), (x1,y1) and (x2,y2) collinear? + // Equivalently, is (x1,y1) coincident with (x2,y2)? + // Or, is the radius zero? Line to (x1,y1). + else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon$4) || !r) { + this._ += "L" + (this._x1 = x1) + "," + (this._y1 = y1); + } + + // Otherwise, draw an arc! + else { + var x20 = x2 - x0, + y20 = y2 - y0, + l21_2 = x21 * x21 + y21 * y21, + l20_2 = x20 * x20 + y20 * y20, + l21 = Math.sqrt(l21_2), + l01 = Math.sqrt(l01_2), + l = r * Math.tan((pi$2 - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2), + t01 = l / l01, + t21 = l / l21; + + // If the start tangent is not coincident with (x0,y0), line to. + if (Math.abs(t01 - 1) > epsilon$4) { + this._ += "L" + (x1 + t01 * x01) + "," + (y1 + t01 * y01); + } + + this._ += "A" + r + "," + r + ",0,0," + (+(y01 * x20 > x01 * y20)) + "," + (this._x1 = x1 + t21 * x21) + "," + (this._y1 = y1 + t21 * y21); + } + }, + arc: function(x, y, r, a0, a1, ccw) { + x = +x, y = +y, r = +r, ccw = !!ccw; + var dx = r * Math.cos(a0), + dy = r * Math.sin(a0), + x0 = x + dx, + y0 = y + dy, + cw = 1 ^ ccw, + da = ccw ? a0 - a1 : a1 - a0; + + // Is the radius negative? Error. + if (r < 0) throw new Error("negative radius: " + r); + + // Is this path empty? Move to (x0,y0). + if (this._x1 === null) { + this._ += "M" + x0 + "," + y0; + } + + // Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0). + else if (Math.abs(this._x1 - x0) > epsilon$4 || Math.abs(this._y1 - y0) > epsilon$4) { + this._ += "L" + x0 + "," + y0; + } + + // Is this arc empty? We’re done. + if (!r) return; + + // Does the angle go the wrong way? Flip the direction. + if (da < 0) da = da % tau$3 + tau$3; + + // Is this a complete circle? Draw two arcs to complete the circle. + if (da > tauEpsilon) { + this._ += "A" + r + "," + r + ",0,1," + cw + "," + (x - dx) + "," + (y - dy) + "A" + r + "," + r + ",0,1," + cw + "," + (this._x1 = x0) + "," + (this._y1 = y0); + } + + // Is this arc non-empty? Draw an arc! + else if (da > epsilon$4) { + this._ += "A" + r + "," + r + ",0," + (+(da >= pi$2)) + "," + cw + "," + (this._x1 = x + r * Math.cos(a1)) + "," + (this._y1 = y + r * Math.sin(a1)); + } + }, + rect: function(x, y, w, h) { + this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y) + "h" + (+w) + "v" + (+h) + "h" + (-w) + "Z"; + }, + toString: function() { + return this._; + } +}; + +var slice$2 = Array.prototype.slice; + +function constant$6(x) { + return function() { + return x; + }; +} + +function defaultSource$1(d) { + return d.source; +} + +function defaultTarget(d) { + return d.target; +} + +function defaultRadius$1(d) { + return d.radius; +} + +function defaultStartAngle(d) { + return d.startAngle; +} + +function defaultEndAngle(d) { + return d.endAngle; +} + +function defaultPadAngle() { + return 0; +} + +function defaultArrowheadRadius() { + return 10; +} + +function ribbon(headRadius) { + var source = defaultSource$1, + target = defaultTarget, + sourceRadius = defaultRadius$1, + targetRadius = defaultRadius$1, + startAngle = defaultStartAngle, + endAngle = defaultEndAngle, + padAngle = defaultPadAngle, + context = null; + + function ribbon() { + var buffer, + s = source.apply(this, arguments), + t = target.apply(this, arguments), + ap = padAngle.apply(this, arguments) / 2, + argv = slice$2.call(arguments), + sr = +sourceRadius.apply(this, (argv[0] = s, argv)), + sa0 = startAngle.apply(this, argv) - halfPi$2, + sa1 = endAngle.apply(this, argv) - halfPi$2, + tr = +targetRadius.apply(this, (argv[0] = t, argv)), + ta0 = startAngle.apply(this, argv) - halfPi$2, + ta1 = endAngle.apply(this, argv) - halfPi$2; + + if (!context) context = buffer = path(); + + if (ap > epsilon$5) { + if (abs$2(sa1 - sa0) > ap * 2 + epsilon$5) sa1 > sa0 ? (sa0 += ap, sa1 -= ap) : (sa0 -= ap, sa1 += ap); + else sa0 = sa1 = (sa0 + sa1) / 2; + if (abs$2(ta1 - ta0) > ap * 2 + epsilon$5) ta1 > ta0 ? (ta0 += ap, ta1 -= ap) : (ta0 -= ap, ta1 += ap); + else ta0 = ta1 = (ta0 + ta1) / 2; + } + + context.moveTo(sr * cos$2(sa0), sr * sin$2(sa0)); + context.arc(0, 0, sr, sa0, sa1); + if (sa0 !== ta0 || sa1 !== ta1) { + if (headRadius) { + var hr = +headRadius.apply(this, arguments), tr2 = tr - hr, ta2 = (ta0 + ta1) / 2; + context.quadraticCurveTo(0, 0, tr2 * cos$2(ta0), tr2 * sin$2(ta0)); + context.lineTo(tr * cos$2(ta2), tr * sin$2(ta2)); + context.lineTo(tr2 * cos$2(ta1), tr2 * sin$2(ta1)); + } else { + context.quadraticCurveTo(0, 0, tr * cos$2(ta0), tr * sin$2(ta0)); + context.arc(0, 0, tr, ta0, ta1); + } + } + context.quadraticCurveTo(0, 0, sr * cos$2(sa0), sr * sin$2(sa0)); + context.closePath(); + + if (buffer) return context = null, buffer + "" || null; + } + + if (headRadius) ribbon.headRadius = function(_) { + return arguments.length ? (headRadius = typeof _ === "function" ? _ : constant$6(+_), ribbon) : headRadius; + }; + + ribbon.radius = function(_) { + return arguments.length ? (sourceRadius = targetRadius = typeof _ === "function" ? _ : constant$6(+_), ribbon) : sourceRadius; + }; + + ribbon.sourceRadius = function(_) { + return arguments.length ? (sourceRadius = typeof _ === "function" ? _ : constant$6(+_), ribbon) : sourceRadius; + }; + + ribbon.targetRadius = function(_) { + return arguments.length ? (targetRadius = typeof _ === "function" ? _ : constant$6(+_), ribbon) : targetRadius; + }; + + ribbon.startAngle = function(_) { + return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$6(+_), ribbon) : startAngle; + }; + + ribbon.endAngle = function(_) { + return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$6(+_), ribbon) : endAngle; + }; + + ribbon.padAngle = function(_) { + return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$6(+_), ribbon) : padAngle; + }; + + ribbon.source = function(_) { + return arguments.length ? (source = _, ribbon) : source; + }; + + ribbon.target = function(_) { + return arguments.length ? (target = _, ribbon) : target; + }; + + ribbon.context = function(_) { + return arguments.length ? ((context = _ == null ? null : _), ribbon) : context; + }; + + return ribbon; +} + +function ribbon$1() { + return ribbon(); +} + +function ribbonArrow() { + return ribbon(defaultArrowheadRadius); +} + +var array$2 = Array.prototype; + +var slice$1 = array$2.slice; + +function ascending$1(a, b) { + return a - b; +} + +function area$3(ring) { + var i = 0, n = ring.length, area = ring[n - 1][1] * ring[0][0] - ring[n - 1][0] * ring[0][1]; + while (++i < n) area += ring[i - 1][1] * ring[i][0] - ring[i - 1][0] * ring[i][1]; + return area; +} + +var constant$5 = x => () => x; + +function contains$2(ring, hole) { + var i = -1, n = hole.length, c; + while (++i < n) if (c = ringContains(ring, hole[i])) return c; + return 0; +} + +function ringContains(ring, point) { + var x = point[0], y = point[1], contains = -1; + for (var i = 0, n = ring.length, j = n - 1; i < n; j = i++) { + var pi = ring[i], xi = pi[0], yi = pi[1], pj = ring[j], xj = pj[0], yj = pj[1]; + if (segmentContains(pi, pj, point)) return 0; + if (((yi > y) !== (yj > y)) && ((x < (xj - xi) * (y - yi) / (yj - yi) + xi))) contains = -contains; + } + return contains; +} + +function segmentContains(a, b, c) { + var i; return collinear$1(a, b, c) && within(a[i = +(a[0] === b[0])], c[i], b[i]); +} + +function collinear$1(a, b, c) { + return (b[0] - a[0]) * (c[1] - a[1]) === (c[0] - a[0]) * (b[1] - a[1]); +} + +function within(p, q, r) { + return p <= q && q <= r || r <= q && q <= p; +} + +function noop$2() {} + +var cases = [ + [], + [[[1.0, 1.5], [0.5, 1.0]]], + [[[1.5, 1.0], [1.0, 1.5]]], + [[[1.5, 1.0], [0.5, 1.0]]], + [[[1.0, 0.5], [1.5, 1.0]]], + [[[1.0, 1.5], [0.5, 1.0]], [[1.0, 0.5], [1.5, 1.0]]], + [[[1.0, 0.5], [1.0, 1.5]]], + [[[1.0, 0.5], [0.5, 1.0]]], + [[[0.5, 1.0], [1.0, 0.5]]], + [[[1.0, 1.5], [1.0, 0.5]]], + [[[0.5, 1.0], [1.0, 0.5]], [[1.5, 1.0], [1.0, 1.5]]], + [[[1.5, 1.0], [1.0, 0.5]]], + [[[0.5, 1.0], [1.5, 1.0]]], + [[[1.0, 1.5], [1.5, 1.0]]], + [[[0.5, 1.0], [1.0, 1.5]]], + [] +]; + +function contours() { + var dx = 1, + dy = 1, + threshold = thresholdSturges, + smooth = smoothLinear; + + function contours(values) { + var tz = threshold(values); + + // Convert number of thresholds into uniform thresholds. + if (!Array.isArray(tz)) { + const e = extent$1(values), ts = tickStep(e[0], e[1], tz); + tz = ticks(Math.floor(e[0] / ts) * ts, Math.floor(e[1] / ts - 1) * ts, tz); + } else { + tz = tz.slice().sort(ascending$1); + } + + return tz.map(value => contour(values, value)); + } + + // Accumulate, smooth contour rings, assign holes to exterior rings. + // Based on https://github.com/mbostock/shapefile/blob/v0.6.2/shp/polygon.js + function contour(values, value) { + var polygons = [], + holes = []; + + isorings(values, value, function(ring) { + smooth(ring, values, value); + if (area$3(ring) > 0) polygons.push([ring]); + else holes.push(ring); + }); + + holes.forEach(function(hole) { + for (var i = 0, n = polygons.length, polygon; i < n; ++i) { + if (contains$2((polygon = polygons[i])[0], hole) !== -1) { + polygon.push(hole); + return; + } + } + }); + + return { + type: "MultiPolygon", + value: value, + coordinates: polygons + }; + } + + // Marching squares with isolines stitched into rings. + // Based on https://github.com/topojson/topojson-client/blob/v3.0.0/src/stitch.js + function isorings(values, value, callback) { + var fragmentByStart = new Array, + fragmentByEnd = new Array, + x, y, t0, t1, t2, t3; + + // Special case for the first row (y = -1, t2 = t3 = 0). + x = y = -1; + t1 = values[0] >= value; + cases[t1 << 1].forEach(stitch); + while (++x < dx - 1) { + t0 = t1, t1 = values[x + 1] >= value; + cases[t0 | t1 << 1].forEach(stitch); + } + cases[t1 << 0].forEach(stitch); + + // General case for the intermediate rows. + while (++y < dy - 1) { + x = -1; + t1 = values[y * dx + dx] >= value; + t2 = values[y * dx] >= value; + cases[t1 << 1 | t2 << 2].forEach(stitch); + while (++x < dx - 1) { + t0 = t1, t1 = values[y * dx + dx + x + 1] >= value; + t3 = t2, t2 = values[y * dx + x + 1] >= value; + cases[t0 | t1 << 1 | t2 << 2 | t3 << 3].forEach(stitch); + } + cases[t1 | t2 << 3].forEach(stitch); + } + + // Special case for the last row (y = dy - 1, t0 = t1 = 0). + x = -1; + t2 = values[y * dx] >= value; + cases[t2 << 2].forEach(stitch); + while (++x < dx - 1) { + t3 = t2, t2 = values[y * dx + x + 1] >= value; + cases[t2 << 2 | t3 << 3].forEach(stitch); + } + cases[t2 << 3].forEach(stitch); + + function stitch(line) { + var start = [line[0][0] + x, line[0][1] + y], + end = [line[1][0] + x, line[1][1] + y], + startIndex = index(start), + endIndex = index(end), + f, g; + if (f = fragmentByEnd[startIndex]) { + if (g = fragmentByStart[endIndex]) { + delete fragmentByEnd[f.end]; + delete fragmentByStart[g.start]; + if (f === g) { + f.ring.push(end); + callback(f.ring); + } else { + fragmentByStart[f.start] = fragmentByEnd[g.end] = {start: f.start, end: g.end, ring: f.ring.concat(g.ring)}; + } + } else { + delete fragmentByEnd[f.end]; + f.ring.push(end); + fragmentByEnd[f.end = endIndex] = f; + } + } else if (f = fragmentByStart[endIndex]) { + if (g = fragmentByEnd[startIndex]) { + delete fragmentByStart[f.start]; + delete fragmentByEnd[g.end]; + if (f === g) { + f.ring.push(end); + callback(f.ring); + } else { + fragmentByStart[g.start] = fragmentByEnd[f.end] = {start: g.start, end: f.end, ring: g.ring.concat(f.ring)}; + } + } else { + delete fragmentByStart[f.start]; + f.ring.unshift(start); + fragmentByStart[f.start = startIndex] = f; + } + } else { + fragmentByStart[startIndex] = fragmentByEnd[endIndex] = {start: startIndex, end: endIndex, ring: [start, end]}; + } + } + } + + function index(point) { + return point[0] * 2 + point[1] * (dx + 1) * 4; + } + + function smoothLinear(ring, values, value) { + ring.forEach(function(point) { + var x = point[0], + y = point[1], + xt = x | 0, + yt = y | 0, + v0, + v1 = values[yt * dx + xt]; + if (x > 0 && x < dx && xt === x) { + v0 = values[yt * dx + xt - 1]; + point[0] = x + (value - v0) / (v1 - v0) - 0.5; + } + if (y > 0 && y < dy && yt === y) { + v0 = values[(yt - 1) * dx + xt]; + point[1] = y + (value - v0) / (v1 - v0) - 0.5; + } + }); + } + + contours.contour = contour; + + contours.size = function(_) { + if (!arguments.length) return [dx, dy]; + var _0 = Math.floor(_[0]), _1 = Math.floor(_[1]); + if (!(_0 >= 0 && _1 >= 0)) throw new Error("invalid size"); + return dx = _0, dy = _1, contours; + }; + + contours.thresholds = function(_) { + return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant$5(slice$1.call(_)) : constant$5(_), contours) : threshold; + }; + + contours.smooth = function(_) { + return arguments.length ? (smooth = _ ? smoothLinear : noop$2, contours) : smooth === smoothLinear; + }; + + return contours; +} + +// TODO Optimize edge cases. +// TODO Optimize index calculation. +// TODO Optimize arguments. +function blurX(source, target, r) { + var n = source.width, + m = source.height, + w = (r << 1) + 1; + for (var j = 0; j < m; ++j) { + for (var i = 0, sr = 0; i < n + r; ++i) { + if (i < n) { + sr += source.data[i + j * n]; + } + if (i >= r) { + if (i >= w) { + sr -= source.data[i - w + j * n]; + } + target.data[i - r + j * n] = sr / Math.min(i + 1, n - 1 + w - i, w); + } + } + } +} + +// TODO Optimize edge cases. +// TODO Optimize index calculation. +// TODO Optimize arguments. +function blurY(source, target, r) { + var n = source.width, + m = source.height, + w = (r << 1) + 1; + for (var i = 0; i < n; ++i) { + for (var j = 0, sr = 0; j < m + r; ++j) { + if (j < m) { + sr += source.data[i + j * n]; + } + if (j >= r) { + if (j >= w) { + sr -= source.data[i + (j - w) * n]; + } + target.data[i + (j - r) * n] = sr / Math.min(j + 1, m - 1 + w - j, w); + } + } + } +} + +function defaultX$1(d) { + return d[0]; +} + +function defaultY$1(d) { + return d[1]; +} + +function defaultWeight() { + return 1; +} + +function density() { + var x = defaultX$1, + y = defaultY$1, + weight = defaultWeight, + dx = 960, + dy = 500, + r = 20, // blur radius + k = 2, // log2(grid cell size) + o = r * 3, // grid offset, to pad for blur + n = (dx + o * 2) >> k, // grid width + m = (dy + o * 2) >> k, // grid height + threshold = constant$5(20); + + function density(data) { + var values0 = new Float32Array(n * m), + values1 = new Float32Array(n * m), + pow2k = Math.pow(2, -k); + + data.forEach(function(d, i, data) { + var xi = (x(d, i, data) + o) * pow2k, + yi = (y(d, i, data) + o) * pow2k, + wi = +weight(d, i, data); + if (xi >= 0 && xi < n && yi >= 0 && yi < m) { + var x0 = Math.floor(xi), + y0 = Math.floor(yi), + xt = xi - x0 - 0.5, + yt = yi - y0 - 0.5; + values0[x0 + y0 * n] += (1 - xt) * (1 - yt) * wi; + values0[x0 + 1 + y0 * n] += xt * (1 - yt) * wi; + values0[x0 + 1 + (y0 + 1) * n] += xt * yt * wi; + values0[x0 + (y0 + 1) * n] += (1 - xt) * yt * wi; + } + }); + + // TODO Optimize. + blurX({width: n, height: m, data: values0}, {width: n, height: m, data: values1}, r >> k); + blurY({width: n, height: m, data: values1}, {width: n, height: m, data: values0}, r >> k); + blurX({width: n, height: m, data: values0}, {width: n, height: m, data: values1}, r >> k); + blurY({width: n, height: m, data: values1}, {width: n, height: m, data: values0}, r >> k); + blurX({width: n, height: m, data: values0}, {width: n, height: m, data: values1}, r >> k); + blurY({width: n, height: m, data: values1}, {width: n, height: m, data: values0}, r >> k); + + var tz = threshold(values0); + + // Convert number of thresholds into uniform thresholds. + if (!Array.isArray(tz)) { + var stop = max$3(values0); + tz = tickStep(0, stop, tz); + tz = range$2(0, Math.floor(stop / tz) * tz, tz); + tz.shift(); + } + + return contours() + .thresholds(tz) + .size([n, m]) + (values0) + .map(transform); + } + + function transform(geometry) { + geometry.value *= Math.pow(2, -2 * k); // Density in points per square pixel. + geometry.coordinates.forEach(transformPolygon); + return geometry; + } + + function transformPolygon(coordinates) { + coordinates.forEach(transformRing); + } + + function transformRing(coordinates) { + coordinates.forEach(transformPoint); + } + + // TODO Optimize. + function transformPoint(coordinates) { + coordinates[0] = coordinates[0] * Math.pow(2, k) - o; + coordinates[1] = coordinates[1] * Math.pow(2, k) - o; + } + + function resize() { + o = r * 3; + n = (dx + o * 2) >> k; + m = (dy + o * 2) >> k; + return density; + } + + density.x = function(_) { + return arguments.length ? (x = typeof _ === "function" ? _ : constant$5(+_), density) : x; + }; + + density.y = function(_) { + return arguments.length ? (y = typeof _ === "function" ? _ : constant$5(+_), density) : y; + }; + + density.weight = function(_) { + return arguments.length ? (weight = typeof _ === "function" ? _ : constant$5(+_), density) : weight; + }; + + density.size = function(_) { + if (!arguments.length) return [dx, dy]; + var _0 = +_[0], _1 = +_[1]; + if (!(_0 >= 0 && _1 >= 0)) throw new Error("invalid size"); + return dx = _0, dy = _1, resize(); + }; + + density.cellSize = function(_) { + if (!arguments.length) return 1 << k; + if (!((_ = +_) >= 1)) throw new Error("invalid cell size"); + return k = Math.floor(Math.log(_) / Math.LN2), resize(); + }; + + density.thresholds = function(_) { + return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant$5(slice$1.call(_)) : constant$5(_), density) : threshold; + }; + + density.bandwidth = function(_) { + if (!arguments.length) return Math.sqrt(r * (r + 1)); + if (!((_ = +_) >= 0)) throw new Error("invalid bandwidth"); + return r = Math.round((Math.sqrt(4 * _ * _ + 1) - 1) / 2), resize(); + }; + + return density; +} + +const epsilon$3 = 1.1102230246251565e-16; +const splitter = 134217729; +const resulterrbound = (3 + 8 * epsilon$3) * epsilon$3; + +// fast_expansion_sum_zeroelim routine from oritinal code +function sum$1(elen, e, flen, f, h) { + let Q, Qnew, hh, bvirt; + let enow = e[0]; + let fnow = f[0]; + let eindex = 0; + let findex = 0; + if ((fnow > enow) === (fnow > -enow)) { + Q = enow; + enow = e[++eindex]; + } else { + Q = fnow; + fnow = f[++findex]; + } + let hindex = 0; + if (eindex < elen && findex < flen) { + if ((fnow > enow) === (fnow > -enow)) { + Qnew = enow + Q; + hh = Q - (Qnew - enow); + enow = e[++eindex]; + } else { + Qnew = fnow + Q; + hh = Q - (Qnew - fnow); + fnow = f[++findex]; + } + Q = Qnew; + if (hh !== 0) { + h[hindex++] = hh; + } + while (eindex < elen && findex < flen) { + if ((fnow > enow) === (fnow > -enow)) { + Qnew = Q + enow; + bvirt = Qnew - Q; + hh = Q - (Qnew - bvirt) + (enow - bvirt); + enow = e[++eindex]; + } else { + Qnew = Q + fnow; + bvirt = Qnew - Q; + hh = Q - (Qnew - bvirt) + (fnow - bvirt); + fnow = f[++findex]; + } + Q = Qnew; + if (hh !== 0) { + h[hindex++] = hh; + } + } + } + while (eindex < elen) { + Qnew = Q + enow; + bvirt = Qnew - Q; + hh = Q - (Qnew - bvirt) + (enow - bvirt); + enow = e[++eindex]; + Q = Qnew; + if (hh !== 0) { + h[hindex++] = hh; + } + } + while (findex < flen) { + Qnew = Q + fnow; + bvirt = Qnew - Q; + hh = Q - (Qnew - bvirt) + (fnow - bvirt); + fnow = f[++findex]; + Q = Qnew; + if (hh !== 0) { + h[hindex++] = hh; + } + } + if (Q !== 0 || hindex === 0) { + h[hindex++] = Q; + } + return hindex; +} + +function estimate(elen, e) { + let Q = e[0]; + for (let i = 1; i < elen; i++) Q += e[i]; + return Q; +} + +function vec(n) { + return new Float64Array(n); +} + +const ccwerrboundA = (3 + 16 * epsilon$3) * epsilon$3; +const ccwerrboundB = (2 + 12 * epsilon$3) * epsilon$3; +const ccwerrboundC = (9 + 64 * epsilon$3) * epsilon$3 * epsilon$3; + +const B = vec(4); +const C1 = vec(8); +const C2 = vec(12); +const D = vec(16); +const u = vec(4); + +function orient2dadapt(ax, ay, bx, by, cx, cy, detsum) { + let acxtail, acytail, bcxtail, bcytail; + let bvirt, c, ahi, alo, bhi, blo, _i, _j, _0, s1, s0, t1, t0, u3; + + const acx = ax - cx; + const bcx = bx - cx; + const acy = ay - cy; + const bcy = by - cy; + + s1 = acx * bcy; + c = splitter * acx; + ahi = c - (c - acx); + alo = acx - ahi; + c = splitter * bcy; + bhi = c - (c - bcy); + blo = bcy - bhi; + s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo); + t1 = acy * bcx; + c = splitter * acy; + ahi = c - (c - acy); + alo = acy - ahi; + c = splitter * bcx; + bhi = c - (c - bcx); + blo = bcx - bhi; + t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo); + _i = s0 - t0; + bvirt = s0 - _i; + B[0] = s0 - (_i + bvirt) + (bvirt - t0); + _j = s1 + _i; + bvirt = _j - s1; + _0 = s1 - (_j - bvirt) + (_i - bvirt); + _i = _0 - t1; + bvirt = _0 - _i; + B[1] = _0 - (_i + bvirt) + (bvirt - t1); + u3 = _j + _i; + bvirt = u3 - _j; + B[2] = _j - (u3 - bvirt) + (_i - bvirt); + B[3] = u3; + + let det = estimate(4, B); + let errbound = ccwerrboundB * detsum; + if (det >= errbound || -det >= errbound) { + return det; + } + + bvirt = ax - acx; + acxtail = ax - (acx + bvirt) + (bvirt - cx); + bvirt = bx - bcx; + bcxtail = bx - (bcx + bvirt) + (bvirt - cx); + bvirt = ay - acy; + acytail = ay - (acy + bvirt) + (bvirt - cy); + bvirt = by - bcy; + bcytail = by - (bcy + bvirt) + (bvirt - cy); + + if (acxtail === 0 && acytail === 0 && bcxtail === 0 && bcytail === 0) { + return det; + } + + errbound = ccwerrboundC * detsum + resulterrbound * Math.abs(det); + det += (acx * bcytail + bcy * acxtail) - (acy * bcxtail + bcx * acytail); + if (det >= errbound || -det >= errbound) return det; + + s1 = acxtail * bcy; + c = splitter * acxtail; + ahi = c - (c - acxtail); + alo = acxtail - ahi; + c = splitter * bcy; + bhi = c - (c - bcy); + blo = bcy - bhi; + s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo); + t1 = acytail * bcx; + c = splitter * acytail; + ahi = c - (c - acytail); + alo = acytail - ahi; + c = splitter * bcx; + bhi = c - (c - bcx); + blo = bcx - bhi; + t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo); + _i = s0 - t0; + bvirt = s0 - _i; + u[0] = s0 - (_i + bvirt) + (bvirt - t0); + _j = s1 + _i; + bvirt = _j - s1; + _0 = s1 - (_j - bvirt) + (_i - bvirt); + _i = _0 - t1; + bvirt = _0 - _i; + u[1] = _0 - (_i + bvirt) + (bvirt - t1); + u3 = _j + _i; + bvirt = u3 - _j; + u[2] = _j - (u3 - bvirt) + (_i - bvirt); + u[3] = u3; + const C1len = sum$1(4, B, 4, u, C1); + + s1 = acx * bcytail; + c = splitter * acx; + ahi = c - (c - acx); + alo = acx - ahi; + c = splitter * bcytail; + bhi = c - (c - bcytail); + blo = bcytail - bhi; + s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo); + t1 = acy * bcxtail; + c = splitter * acy; + ahi = c - (c - acy); + alo = acy - ahi; + c = splitter * bcxtail; + bhi = c - (c - bcxtail); + blo = bcxtail - bhi; + t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo); + _i = s0 - t0; + bvirt = s0 - _i; + u[0] = s0 - (_i + bvirt) + (bvirt - t0); + _j = s1 + _i; + bvirt = _j - s1; + _0 = s1 - (_j - bvirt) + (_i - bvirt); + _i = _0 - t1; + bvirt = _0 - _i; + u[1] = _0 - (_i + bvirt) + (bvirt - t1); + u3 = _j + _i; + bvirt = u3 - _j; + u[2] = _j - (u3 - bvirt) + (_i - bvirt); + u[3] = u3; + const C2len = sum$1(C1len, C1, 4, u, C2); + + s1 = acxtail * bcytail; + c = splitter * acxtail; + ahi = c - (c - acxtail); + alo = acxtail - ahi; + c = splitter * bcytail; + bhi = c - (c - bcytail); + blo = bcytail - bhi; + s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo); + t1 = acytail * bcxtail; + c = splitter * acytail; + ahi = c - (c - acytail); + alo = acytail - ahi; + c = splitter * bcxtail; + bhi = c - (c - bcxtail); + blo = bcxtail - bhi; + t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo); + _i = s0 - t0; + bvirt = s0 - _i; + u[0] = s0 - (_i + bvirt) + (bvirt - t0); + _j = s1 + _i; + bvirt = _j - s1; + _0 = s1 - (_j - bvirt) + (_i - bvirt); + _i = _0 - t1; + bvirt = _0 - _i; + u[1] = _0 - (_i + bvirt) + (bvirt - t1); + u3 = _j + _i; + bvirt = u3 - _j; + u[2] = _j - (u3 - bvirt) + (_i - bvirt); + u[3] = u3; + const Dlen = sum$1(C2len, C2, 4, u, D); + + return D[Dlen - 1]; +} + +function orient2d(ax, ay, bx, by, cx, cy) { + const detleft = (ay - cy) * (bx - cx); + const detright = (ax - cx) * (by - cy); + const det = detleft - detright; + + if (detleft === 0 || detright === 0 || (detleft > 0) !== (detright > 0)) return det; + + const detsum = Math.abs(detleft + detright); + if (Math.abs(det) >= ccwerrboundA * detsum) return det; + + return -orient2dadapt(ax, ay, bx, by, cx, cy, detsum); +} + +const EPSILON = Math.pow(2, -52); +const EDGE_STACK = new Uint32Array(512); + +class Delaunator { + + static from(points, getX = defaultGetX, getY = defaultGetY) { + const n = points.length; + const coords = new Float64Array(n * 2); + + for (let i = 0; i < n; i++) { + const p = points[i]; + coords[2 * i] = getX(p); + coords[2 * i + 1] = getY(p); + } + + return new Delaunator(coords); + } + + constructor(coords) { + const n = coords.length >> 1; + if (n > 0 && typeof coords[0] !== 'number') throw new Error('Expected coords to contain numbers.'); + + this.coords = coords; + + // arrays that will store the triangulation graph + const maxTriangles = Math.max(2 * n - 5, 0); + this._triangles = new Uint32Array(maxTriangles * 3); + this._halfedges = new Int32Array(maxTriangles * 3); + + // temporary arrays for tracking the edges of the advancing convex hull + this._hashSize = Math.ceil(Math.sqrt(n)); + this._hullPrev = new Uint32Array(n); // edge to prev edge + this._hullNext = new Uint32Array(n); // edge to next edge + this._hullTri = new Uint32Array(n); // edge to adjacent triangle + this._hullHash = new Int32Array(this._hashSize).fill(-1); // angular edge hash + + // temporary arrays for sorting points + this._ids = new Uint32Array(n); + this._dists = new Float64Array(n); + + this.update(); + } + + update() { + const {coords, _hullPrev: hullPrev, _hullNext: hullNext, _hullTri: hullTri, _hullHash: hullHash} = this; + const n = coords.length >> 1; + + // populate an array of point indices; calculate input data bbox + let minX = Infinity; + let minY = Infinity; + let maxX = -Infinity; + let maxY = -Infinity; + + for (let i = 0; i < n; i++) { + const x = coords[2 * i]; + const y = coords[2 * i + 1]; + if (x < minX) minX = x; + if (y < minY) minY = y; + if (x > maxX) maxX = x; + if (y > maxY) maxY = y; + this._ids[i] = i; + } + const cx = (minX + maxX) / 2; + const cy = (minY + maxY) / 2; + + let minDist = Infinity; + let i0, i1, i2; + + // pick a seed point close to the center + for (let i = 0; i < n; i++) { + const d = dist(cx, cy, coords[2 * i], coords[2 * i + 1]); + if (d < minDist) { + i0 = i; + minDist = d; + } + } + const i0x = coords[2 * i0]; + const i0y = coords[2 * i0 + 1]; + + minDist = Infinity; + + // find the point closest to the seed + for (let i = 0; i < n; i++) { + if (i === i0) continue; + const d = dist(i0x, i0y, coords[2 * i], coords[2 * i + 1]); + if (d < minDist && d > 0) { + i1 = i; + minDist = d; + } + } + let i1x = coords[2 * i1]; + let i1y = coords[2 * i1 + 1]; + + let minRadius = Infinity; + + // find the third point which forms the smallest circumcircle with the first two + for (let i = 0; i < n; i++) { + if (i === i0 || i === i1) continue; + const r = circumradius(i0x, i0y, i1x, i1y, coords[2 * i], coords[2 * i + 1]); + if (r < minRadius) { + i2 = i; + minRadius = r; + } + } + let i2x = coords[2 * i2]; + let i2y = coords[2 * i2 + 1]; + + if (minRadius === Infinity) { + // order collinear points by dx (or dy if all x are identical) + // and return the list as a hull + for (let i = 0; i < n; i++) { + this._dists[i] = (coords[2 * i] - coords[0]) || (coords[2 * i + 1] - coords[1]); + } + quicksort(this._ids, this._dists, 0, n - 1); + const hull = new Uint32Array(n); + let j = 0; + for (let i = 0, d0 = -Infinity; i < n; i++) { + const id = this._ids[i]; + if (this._dists[id] > d0) { + hull[j++] = id; + d0 = this._dists[id]; + } + } + this.hull = hull.subarray(0, j); + this.triangles = new Uint32Array(0); + this.halfedges = new Uint32Array(0); + return; + } + + // swap the order of the seed points for counter-clockwise orientation + if (orient2d(i0x, i0y, i1x, i1y, i2x, i2y) < 0) { + const i = i1; + const x = i1x; + const y = i1y; + i1 = i2; + i1x = i2x; + i1y = i2y; + i2 = i; + i2x = x; + i2y = y; + } + + const center = circumcenter(i0x, i0y, i1x, i1y, i2x, i2y); + this._cx = center.x; + this._cy = center.y; + + for (let i = 0; i < n; i++) { + this._dists[i] = dist(coords[2 * i], coords[2 * i + 1], center.x, center.y); + } + + // sort the points by distance from the seed triangle circumcenter + quicksort(this._ids, this._dists, 0, n - 1); + + // set up the seed triangle as the starting hull + this._hullStart = i0; + let hullSize = 3; + + hullNext[i0] = hullPrev[i2] = i1; + hullNext[i1] = hullPrev[i0] = i2; + hullNext[i2] = hullPrev[i1] = i0; + + hullTri[i0] = 0; + hullTri[i1] = 1; + hullTri[i2] = 2; + + hullHash.fill(-1); + hullHash[this._hashKey(i0x, i0y)] = i0; + hullHash[this._hashKey(i1x, i1y)] = i1; + hullHash[this._hashKey(i2x, i2y)] = i2; + + this.trianglesLen = 0; + this._addTriangle(i0, i1, i2, -1, -1, -1); + + for (let k = 0, xp, yp; k < this._ids.length; k++) { + const i = this._ids[k]; + const x = coords[2 * i]; + const y = coords[2 * i + 1]; + + // skip near-duplicate points + if (k > 0 && Math.abs(x - xp) <= EPSILON && Math.abs(y - yp) <= EPSILON) continue; + xp = x; + yp = y; + + // skip seed triangle points + if (i === i0 || i === i1 || i === i2) continue; + + // find a visible edge on the convex hull using edge hash + let start = 0; + for (let j = 0, key = this._hashKey(x, y); j < this._hashSize; j++) { + start = hullHash[(key + j) % this._hashSize]; + if (start !== -1 && start !== hullNext[start]) break; + } + + start = hullPrev[start]; + let e = start, q; + while (q = hullNext[e], orient2d(x, y, coords[2 * e], coords[2 * e + 1], coords[2 * q], coords[2 * q + 1]) >= 0) { + e = q; + if (e === start) { + e = -1; + break; + } + } + if (e === -1) continue; // likely a near-duplicate point; skip it + + // add the first triangle from the point + let t = this._addTriangle(e, i, hullNext[e], -1, -1, hullTri[e]); + + // recursively flip triangles from the point until they satisfy the Delaunay condition + hullTri[i] = this._legalize(t + 2); + hullTri[e] = t; // keep track of boundary triangles on the hull + hullSize++; + + // walk forward through the hull, adding more triangles and flipping recursively + let n = hullNext[e]; + while (q = hullNext[n], orient2d(x, y, coords[2 * n], coords[2 * n + 1], coords[2 * q], coords[2 * q + 1]) < 0) { + t = this._addTriangle(n, i, q, hullTri[i], -1, hullTri[n]); + hullTri[i] = this._legalize(t + 2); + hullNext[n] = n; // mark as removed + hullSize--; + n = q; + } + + // walk backward from the other side, adding more triangles and flipping + if (e === start) { + while (q = hullPrev[e], orient2d(x, y, coords[2 * q], coords[2 * q + 1], coords[2 * e], coords[2 * e + 1]) < 0) { + t = this._addTriangle(q, i, e, -1, hullTri[e], hullTri[q]); + this._legalize(t + 2); + hullTri[q] = t; + hullNext[e] = e; // mark as removed + hullSize--; + e = q; + } + } + + // update the hull indices + this._hullStart = hullPrev[i] = e; + hullNext[e] = hullPrev[n] = i; + hullNext[i] = n; + + // save the two new edges in the hash table + hullHash[this._hashKey(x, y)] = i; + hullHash[this._hashKey(coords[2 * e], coords[2 * e + 1])] = e; + } + + this.hull = new Uint32Array(hullSize); + for (let i = 0, e = this._hullStart; i < hullSize; i++) { + this.hull[i] = e; + e = hullNext[e]; + } + + // trim typed triangle mesh arrays + this.triangles = this._triangles.subarray(0, this.trianglesLen); + this.halfedges = this._halfedges.subarray(0, this.trianglesLen); + } + + _hashKey(x, y) { + return Math.floor(pseudoAngle(x - this._cx, y - this._cy) * this._hashSize) % this._hashSize; + } + + _legalize(a) { + const {_triangles: triangles, _halfedges: halfedges, coords} = this; + + let i = 0; + let ar = 0; + + // recursion eliminated with a fixed-size stack + while (true) { + const b = halfedges[a]; + + /* if the pair of triangles doesn't satisfy the Delaunay condition + * (p1 is inside the circumcircle of [p0, pl, pr]), flip them, + * then do the same check/flip recursively for the new pair of triangles + * + * pl pl + * /||\ / \ + * al/ || \bl al/ \a + * / || \ / \ + * / a||b \ flip /___ar___\ + * p0\ || /p1 => p0\---bl---/p1 + * \ || / \ / + * ar\ || /br b\ /br + * \||/ \ / + * pr pr + */ + const a0 = a - a % 3; + ar = a0 + (a + 2) % 3; + + if (b === -1) { // convex hull edge + if (i === 0) break; + a = EDGE_STACK[--i]; + continue; + } + + const b0 = b - b % 3; + const al = a0 + (a + 1) % 3; + const bl = b0 + (b + 2) % 3; + + const p0 = triangles[ar]; + const pr = triangles[a]; + const pl = triangles[al]; + const p1 = triangles[bl]; + + const illegal = inCircle( + coords[2 * p0], coords[2 * p0 + 1], + coords[2 * pr], coords[2 * pr + 1], + coords[2 * pl], coords[2 * pl + 1], + coords[2 * p1], coords[2 * p1 + 1]); + + if (illegal) { + triangles[a] = p1; + triangles[b] = p0; + + const hbl = halfedges[bl]; + + // edge swapped on the other side of the hull (rare); fix the halfedge reference + if (hbl === -1) { + let e = this._hullStart; + do { + if (this._hullTri[e] === bl) { + this._hullTri[e] = a; + break; + } + e = this._hullPrev[e]; + } while (e !== this._hullStart); + } + this._link(a, hbl); + this._link(b, halfedges[ar]); + this._link(ar, bl); + + const br = b0 + (b + 1) % 3; + + // don't worry about hitting the cap: it can only happen on extremely degenerate input + if (i < EDGE_STACK.length) { + EDGE_STACK[i++] = br; + } + } else { + if (i === 0) break; + a = EDGE_STACK[--i]; + } + } + + return ar; + } + + _link(a, b) { + this._halfedges[a] = b; + if (b !== -1) this._halfedges[b] = a; + } + + // add a new triangle given vertex indices and adjacent half-edge ids + _addTriangle(i0, i1, i2, a, b, c) { + const t = this.trianglesLen; + + this._triangles[t] = i0; + this._triangles[t + 1] = i1; + this._triangles[t + 2] = i2; + + this._link(t, a); + this._link(t + 1, b); + this._link(t + 2, c); + + this.trianglesLen += 3; + + return t; + } +} + +// monotonically increases with real angle, but doesn't need expensive trigonometry +function pseudoAngle(dx, dy) { + const p = dx / (Math.abs(dx) + Math.abs(dy)); + return (dy > 0 ? 3 - p : 1 + p) / 4; // [0..1] +} + +function dist(ax, ay, bx, by) { + const dx = ax - bx; + const dy = ay - by; + return dx * dx + dy * dy; +} + +function inCircle(ax, ay, bx, by, cx, cy, px, py) { + const dx = ax - px; + const dy = ay - py; + const ex = bx - px; + const ey = by - py; + const fx = cx - px; + const fy = cy - py; + + const ap = dx * dx + dy * dy; + const bp = ex * ex + ey * ey; + const cp = fx * fx + fy * fy; + + return dx * (ey * cp - bp * fy) - + dy * (ex * cp - bp * fx) + + ap * (ex * fy - ey * fx) < 0; +} + +function circumradius(ax, ay, bx, by, cx, cy) { + const dx = bx - ax; + const dy = by - ay; + const ex = cx - ax; + const ey = cy - ay; + + const bl = dx * dx + dy * dy; + const cl = ex * ex + ey * ey; + const d = 0.5 / (dx * ey - dy * ex); + + const x = (ey * bl - dy * cl) * d; + const y = (dx * cl - ex * bl) * d; + + return x * x + y * y; +} + +function circumcenter(ax, ay, bx, by, cx, cy) { + const dx = bx - ax; + const dy = by - ay; + const ex = cx - ax; + const ey = cy - ay; + + const bl = dx * dx + dy * dy; + const cl = ex * ex + ey * ey; + const d = 0.5 / (dx * ey - dy * ex); + + const x = ax + (ey * bl - dy * cl) * d; + const y = ay + (dx * cl - ex * bl) * d; + + return {x, y}; +} + +function quicksort(ids, dists, left, right) { + if (right - left <= 20) { + for (let i = left + 1; i <= right; i++) { + const temp = ids[i]; + const tempDist = dists[temp]; + let j = i - 1; + while (j >= left && dists[ids[j]] > tempDist) ids[j + 1] = ids[j--]; + ids[j + 1] = temp; + } + } else { + const median = (left + right) >> 1; + let i = left + 1; + let j = right; + swap(ids, median, i); + if (dists[ids[left]] > dists[ids[right]]) swap(ids, left, right); + if (dists[ids[i]] > dists[ids[right]]) swap(ids, i, right); + if (dists[ids[left]] > dists[ids[i]]) swap(ids, left, i); + + const temp = ids[i]; + const tempDist = dists[temp]; + while (true) { + do i++; while (dists[ids[i]] < tempDist); + do j--; while (dists[ids[j]] > tempDist); + if (j < i) break; + swap(ids, i, j); + } + ids[left + 1] = ids[j]; + ids[j] = temp; + + if (right - i + 1 >= j - left) { + quicksort(ids, dists, i, right); + quicksort(ids, dists, left, j - 1); + } else { + quicksort(ids, dists, left, j - 1); + quicksort(ids, dists, i, right); + } + } +} + +function swap(arr, i, j) { + const tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; +} + +function defaultGetX(p) { + return p[0]; +} +function defaultGetY(p) { + return p[1]; +} + +const epsilon$2 = 1e-6; + +class Path { + constructor() { + this._x0 = this._y0 = // start of current subpath + this._x1 = this._y1 = null; // end of current subpath + this._ = ""; + } + moveTo(x, y) { + this._ += `M${this._x0 = this._x1 = +x},${this._y0 = this._y1 = +y}`; + } + closePath() { + if (this._x1 !== null) { + this._x1 = this._x0, this._y1 = this._y0; + this._ += "Z"; + } + } + lineTo(x, y) { + this._ += `L${this._x1 = +x},${this._y1 = +y}`; + } + arc(x, y, r) { + x = +x, y = +y, r = +r; + const x0 = x + r; + const y0 = y; + if (r < 0) throw new Error("negative radius"); + if (this._x1 === null) this._ += `M${x0},${y0}`; + else if (Math.abs(this._x1 - x0) > epsilon$2 || Math.abs(this._y1 - y0) > epsilon$2) this._ += "L" + x0 + "," + y0; + if (!r) return; + this._ += `A${r},${r},0,1,1,${x - r},${y}A${r},${r},0,1,1,${this._x1 = x0},${this._y1 = y0}`; + } + rect(x, y, w, h) { + this._ += `M${this._x0 = this._x1 = +x},${this._y0 = this._y1 = +y}h${+w}v${+h}h${-w}Z`; + } + value() { + return this._ || null; + } +} + +class Polygon { + constructor() { + this._ = []; + } + moveTo(x, y) { + this._.push([x, y]); + } + closePath() { + this._.push(this._[0].slice()); + } + lineTo(x, y) { + this._.push([x, y]); + } + value() { + return this._.length ? this._ : null; + } +} + +class Voronoi { + constructor(delaunay, [xmin, ymin, xmax, ymax] = [0, 0, 960, 500]) { + if (!((xmax = +xmax) >= (xmin = +xmin)) || !((ymax = +ymax) >= (ymin = +ymin))) throw new Error("invalid bounds"); + this.delaunay = delaunay; + this._circumcenters = new Float64Array(delaunay.points.length * 2); + this.vectors = new Float64Array(delaunay.points.length * 2); + this.xmax = xmax, this.xmin = xmin; + this.ymax = ymax, this.ymin = ymin; + this._init(); + } + update() { + this.delaunay.update(); + this._init(); + return this; + } + _init() { + const {delaunay: {points, hull, triangles}, vectors} = this; + + // Compute circumcenters. + const circumcenters = this.circumcenters = this._circumcenters.subarray(0, triangles.length / 3 * 2); + for (let i = 0, j = 0, n = triangles.length, x, y; i < n; i += 3, j += 2) { + const t1 = triangles[i] * 2; + const t2 = triangles[i + 1] * 2; + const t3 = triangles[i + 2] * 2; + const x1 = points[t1]; + const y1 = points[t1 + 1]; + const x2 = points[t2]; + const y2 = points[t2 + 1]; + const x3 = points[t3]; + const y3 = points[t3 + 1]; + + const dx = x2 - x1; + const dy = y2 - y1; + const ex = x3 - x1; + const ey = y3 - y1; + const ab = (dx * ey - dy * ex) * 2; + + if (Math.abs(ab) < 1e-9) { + // degenerate case (collinear diagram) + // almost equal points (degenerate triangle) + // the circumcenter is at the infinity, in a + // direction that is: + // 1. orthogonal to the halfedge. + let a = 1e9; + // 2. points away from the center; since the list of triangles starts + // in the center, the first point of the first triangle + // will be our reference + const r = triangles[0] * 2; + a *= Math.sign((points[r] - x1) * ey - (points[r + 1] - y1) * ex); + x = (x1 + x3) / 2 - a * ey; + y = (y1 + y3) / 2 + a * ex; + } else { + const d = 1 / ab; + const bl = dx * dx + dy * dy; + const cl = ex * ex + ey * ey; + x = x1 + (ey * bl - dy * cl) * d; + y = y1 + (dx * cl - ex * bl) * d; + } + circumcenters[j] = x; + circumcenters[j + 1] = y; + } + + // Compute exterior cell rays. + let h = hull[hull.length - 1]; + let p0, p1 = h * 4; + let x0, x1 = points[2 * h]; + let y0, y1 = points[2 * h + 1]; + vectors.fill(0); + for (let i = 0; i < hull.length; ++i) { + h = hull[i]; + p0 = p1, x0 = x1, y0 = y1; + p1 = h * 4, x1 = points[2 * h], y1 = points[2 * h + 1]; + vectors[p0 + 2] = vectors[p1] = y0 - y1; + vectors[p0 + 3] = vectors[p1 + 1] = x1 - x0; + } + } + render(context) { + const buffer = context == null ? context = new Path : undefined; + const {delaunay: {halfedges, inedges, hull}, circumcenters, vectors} = this; + if (hull.length <= 1) return null; + for (let i = 0, n = halfedges.length; i < n; ++i) { + const j = halfedges[i]; + if (j < i) continue; + const ti = Math.floor(i / 3) * 2; + const tj = Math.floor(j / 3) * 2; + const xi = circumcenters[ti]; + const yi = circumcenters[ti + 1]; + const xj = circumcenters[tj]; + const yj = circumcenters[tj + 1]; + this._renderSegment(xi, yi, xj, yj, context); + } + let h0, h1 = hull[hull.length - 1]; + for (let i = 0; i < hull.length; ++i) { + h0 = h1, h1 = hull[i]; + const t = Math.floor(inedges[h1] / 3) * 2; + const x = circumcenters[t]; + const y = circumcenters[t + 1]; + const v = h0 * 4; + const p = this._project(x, y, vectors[v + 2], vectors[v + 3]); + if (p) this._renderSegment(x, y, p[0], p[1], context); + } + return buffer && buffer.value(); + } + renderBounds(context) { + const buffer = context == null ? context = new Path : undefined; + context.rect(this.xmin, this.ymin, this.xmax - this.xmin, this.ymax - this.ymin); + return buffer && buffer.value(); + } + renderCell(i, context) { + const buffer = context == null ? context = new Path : undefined; + const points = this._clip(i); + if (points === null || !points.length) return; + context.moveTo(points[0], points[1]); + let n = points.length; + while (points[0] === points[n-2] && points[1] === points[n-1] && n > 1) n -= 2; + for (let i = 2; i < n; i += 2) { + if (points[i] !== points[i-2] || points[i+1] !== points[i-1]) + context.lineTo(points[i], points[i + 1]); + } + context.closePath(); + return buffer && buffer.value(); + } + *cellPolygons() { + const {delaunay: {points}} = this; + for (let i = 0, n = points.length / 2; i < n; ++i) { + const cell = this.cellPolygon(i); + if (cell) cell.index = i, yield cell; + } + } + cellPolygon(i) { + const polygon = new Polygon; + this.renderCell(i, polygon); + return polygon.value(); + } + _renderSegment(x0, y0, x1, y1, context) { + let S; + const c0 = this._regioncode(x0, y0); + const c1 = this._regioncode(x1, y1); + if (c0 === 0 && c1 === 0) { + context.moveTo(x0, y0); + context.lineTo(x1, y1); + } else if (S = this._clipSegment(x0, y0, x1, y1, c0, c1)) { + context.moveTo(S[0], S[1]); + context.lineTo(S[2], S[3]); + } + } + contains(i, x, y) { + if ((x = +x, x !== x) || (y = +y, y !== y)) return false; + return this.delaunay._step(i, x, y) === i; + } + *neighbors(i) { + const ci = this._clip(i); + if (ci) for (const j of this.delaunay.neighbors(i)) { + const cj = this._clip(j); + // find the common edge + if (cj) loop: for (let ai = 0, li = ci.length; ai < li; ai += 2) { + for (let aj = 0, lj = cj.length; aj < lj; aj += 2) { + if (ci[ai] == cj[aj] + && ci[ai + 1] == cj[aj + 1] + && ci[(ai + 2) % li] == cj[(aj + lj - 2) % lj] + && ci[(ai + 3) % li] == cj[(aj + lj - 1) % lj] + ) { + yield j; + break loop; + } + } + } + } + } + _cell(i) { + const {circumcenters, delaunay: {inedges, halfedges, triangles}} = this; + const e0 = inedges[i]; + if (e0 === -1) return null; // coincident point + const points = []; + let e = e0; + do { + const t = Math.floor(e / 3); + points.push(circumcenters[t * 2], circumcenters[t * 2 + 1]); + e = e % 3 === 2 ? e - 2 : e + 1; + if (triangles[e] !== i) break; // bad triangulation + e = halfedges[e]; + } while (e !== e0 && e !== -1); + return points; + } + _clip(i) { + // degenerate case (1 valid point: return the box) + if (i === 0 && this.delaunay.hull.length === 1) { + return [this.xmax, this.ymin, this.xmax, this.ymax, this.xmin, this.ymax, this.xmin, this.ymin]; + } + const points = this._cell(i); + if (points === null) return null; + const {vectors: V} = this; + const v = i * 4; + return V[v] || V[v + 1] + ? this._clipInfinite(i, points, V[v], V[v + 1], V[v + 2], V[v + 3]) + : this._clipFinite(i, points); + } + _clipFinite(i, points) { + const n = points.length; + let P = null; + let x0, y0, x1 = points[n - 2], y1 = points[n - 1]; + let c0, c1 = this._regioncode(x1, y1); + let e0, e1 = 0; + for (let j = 0; j < n; j += 2) { + x0 = x1, y0 = y1, x1 = points[j], y1 = points[j + 1]; + c0 = c1, c1 = this._regioncode(x1, y1); + if (c0 === 0 && c1 === 0) { + e0 = e1, e1 = 0; + if (P) P.push(x1, y1); + else P = [x1, y1]; + } else { + let S, sx0, sy0, sx1, sy1; + if (c0 === 0) { + if ((S = this._clipSegment(x0, y0, x1, y1, c0, c1)) === null) continue; + [sx0, sy0, sx1, sy1] = S; + } else { + if ((S = this._clipSegment(x1, y1, x0, y0, c1, c0)) === null) continue; + [sx1, sy1, sx0, sy0] = S; + e0 = e1, e1 = this._edgecode(sx0, sy0); + if (e0 && e1) this._edge(i, e0, e1, P, P.length); + if (P) P.push(sx0, sy0); + else P = [sx0, sy0]; + } + e0 = e1, e1 = this._edgecode(sx1, sy1); + if (e0 && e1) this._edge(i, e0, e1, P, P.length); + if (P) P.push(sx1, sy1); + else P = [sx1, sy1]; + } + } + if (P) { + e0 = e1, e1 = this._edgecode(P[0], P[1]); + if (e0 && e1) this._edge(i, e0, e1, P, P.length); + } else if (this.contains(i, (this.xmin + this.xmax) / 2, (this.ymin + this.ymax) / 2)) { + return [this.xmax, this.ymin, this.xmax, this.ymax, this.xmin, this.ymax, this.xmin, this.ymin]; + } + return P; + } + _clipSegment(x0, y0, x1, y1, c0, c1) { + while (true) { + if (c0 === 0 && c1 === 0) return [x0, y0, x1, y1]; + if (c0 & c1) return null; + let x, y, c = c0 || c1; + if (c & 0b1000) x = x0 + (x1 - x0) * (this.ymax - y0) / (y1 - y0), y = this.ymax; + else if (c & 0b0100) x = x0 + (x1 - x0) * (this.ymin - y0) / (y1 - y0), y = this.ymin; + else if (c & 0b0010) y = y0 + (y1 - y0) * (this.xmax - x0) / (x1 - x0), x = this.xmax; + else y = y0 + (y1 - y0) * (this.xmin - x0) / (x1 - x0), x = this.xmin; + if (c0) x0 = x, y0 = y, c0 = this._regioncode(x0, y0); + else x1 = x, y1 = y, c1 = this._regioncode(x1, y1); + } + } + _clipInfinite(i, points, vx0, vy0, vxn, vyn) { + let P = Array.from(points), p; + if (p = this._project(P[0], P[1], vx0, vy0)) P.unshift(p[0], p[1]); + if (p = this._project(P[P.length - 2], P[P.length - 1], vxn, vyn)) P.push(p[0], p[1]); + if (P = this._clipFinite(i, P)) { + for (let j = 0, n = P.length, c0, c1 = this._edgecode(P[n - 2], P[n - 1]); j < n; j += 2) { + c0 = c1, c1 = this._edgecode(P[j], P[j + 1]); + if (c0 && c1) j = this._edge(i, c0, c1, P, j), n = P.length; + } + } else if (this.contains(i, (this.xmin + this.xmax) / 2, (this.ymin + this.ymax) / 2)) { + P = [this.xmin, this.ymin, this.xmax, this.ymin, this.xmax, this.ymax, this.xmin, this.ymax]; + } + return P; + } + _edge(i, e0, e1, P, j) { + while (e0 !== e1) { + let x, y; + switch (e0) { + case 0b0101: e0 = 0b0100; continue; // top-left + case 0b0100: e0 = 0b0110, x = this.xmax, y = this.ymin; break; // top + case 0b0110: e0 = 0b0010; continue; // top-right + case 0b0010: e0 = 0b1010, x = this.xmax, y = this.ymax; break; // right + case 0b1010: e0 = 0b1000; continue; // bottom-right + case 0b1000: e0 = 0b1001, x = this.xmin, y = this.ymax; break; // bottom + case 0b1001: e0 = 0b0001; continue; // bottom-left + case 0b0001: e0 = 0b0101, x = this.xmin, y = this.ymin; break; // left + } + // Note: this implicitly checks for out of bounds: if P[j] or P[j+1] are + // undefined, the conditional statement will be executed. + if ((P[j] !== x || P[j + 1] !== y) && this.contains(i, x, y)) { + P.splice(j, 0, x, y), j += 2; + } + } + if (P.length > 4) { + for (let i = 0; i < P.length; i+= 2) { + const j = (i + 2) % P.length, k = (i + 4) % P.length; + if (P[i] === P[j] && P[j] === P[k] + || P[i + 1] === P[j + 1] && P[j + 1] === P[k + 1]) + P.splice(j, 2), i -= 2; + } + } + return j; + } + _project(x0, y0, vx, vy) { + let t = Infinity, c, x, y; + if (vy < 0) { // top + if (y0 <= this.ymin) return null; + if ((c = (this.ymin - y0) / vy) < t) y = this.ymin, x = x0 + (t = c) * vx; + } else if (vy > 0) { // bottom + if (y0 >= this.ymax) return null; + if ((c = (this.ymax - y0) / vy) < t) y = this.ymax, x = x0 + (t = c) * vx; + } + if (vx > 0) { // right + if (x0 >= this.xmax) return null; + if ((c = (this.xmax - x0) / vx) < t) x = this.xmax, y = y0 + (t = c) * vy; + } else if (vx < 0) { // left + if (x0 <= this.xmin) return null; + if ((c = (this.xmin - x0) / vx) < t) x = this.xmin, y = y0 + (t = c) * vy; + } + return [x, y]; + } + _edgecode(x, y) { + return (x === this.xmin ? 0b0001 + : x === this.xmax ? 0b0010 : 0b0000) + | (y === this.ymin ? 0b0100 + : y === this.ymax ? 0b1000 : 0b0000); + } + _regioncode(x, y) { + return (x < this.xmin ? 0b0001 + : x > this.xmax ? 0b0010 : 0b0000) + | (y < this.ymin ? 0b0100 + : y > this.ymax ? 0b1000 : 0b0000); + } +} + +const tau$2 = 2 * Math.PI, pow$2 = Math.pow; + +function pointX(p) { + return p[0]; +} + +function pointY(p) { + return p[1]; +} + +// A triangulation is collinear if all its triangles have a non-null area +function collinear(d) { + const {triangles, coords} = d; + for (let i = 0; i < triangles.length; i += 3) { + const a = 2 * triangles[i], + b = 2 * triangles[i + 1], + c = 2 * triangles[i + 2], + cross = (coords[c] - coords[a]) * (coords[b + 1] - coords[a + 1]) + - (coords[b] - coords[a]) * (coords[c + 1] - coords[a + 1]); + if (cross > 1e-10) return false; + } + return true; +} + +function jitter(x, y, r) { + return [x + Math.sin(x + y) * r, y + Math.cos(x - y) * r]; +} + +class Delaunay { + static from(points, fx = pointX, fy = pointY, that) { + return new Delaunay("length" in points + ? flatArray(points, fx, fy, that) + : Float64Array.from(flatIterable(points, fx, fy, that))); + } + constructor(points) { + this._delaunator = new Delaunator(points); + this.inedges = new Int32Array(points.length / 2); + this._hullIndex = new Int32Array(points.length / 2); + this.points = this._delaunator.coords; + this._init(); + } + update() { + this._delaunator.update(); + this._init(); + return this; + } + _init() { + const d = this._delaunator, points = this.points; + + // check for collinear + if (d.hull && d.hull.length > 2 && collinear(d)) { + this.collinear = Int32Array.from({length: points.length/2}, (_,i) => i) + .sort((i, j) => points[2 * i] - points[2 * j] || points[2 * i + 1] - points[2 * j + 1]); // for exact neighbors + const e = this.collinear[0], f = this.collinear[this.collinear.length - 1], + bounds = [ points[2 * e], points[2 * e + 1], points[2 * f], points[2 * f + 1] ], + r = 1e-8 * Math.hypot(bounds[3] - bounds[1], bounds[2] - bounds[0]); + for (let i = 0, n = points.length / 2; i < n; ++i) { + const p = jitter(points[2 * i], points[2 * i + 1], r); + points[2 * i] = p[0]; + points[2 * i + 1] = p[1]; + } + this._delaunator = new Delaunator(points); + } else { + delete this.collinear; + } + + const halfedges = this.halfedges = this._delaunator.halfedges; + const hull = this.hull = this._delaunator.hull; + const triangles = this.triangles = this._delaunator.triangles; + const inedges = this.inedges.fill(-1); + const hullIndex = this._hullIndex.fill(-1); + + // Compute an index from each point to an (arbitrary) incoming halfedge + // Used to give the first neighbor of each point; for this reason, + // on the hull we give priority to exterior halfedges + for (let e = 0, n = halfedges.length; e < n; ++e) { + const p = triangles[e % 3 === 2 ? e - 2 : e + 1]; + if (halfedges[e] === -1 || inedges[p] === -1) inedges[p] = e; + } + for (let i = 0, n = hull.length; i < n; ++i) { + hullIndex[hull[i]] = i; + } + + // degenerate case: 1 or 2 (distinct) points + if (hull.length <= 2 && hull.length > 0) { + this.triangles = new Int32Array(3).fill(-1); + this.halfedges = new Int32Array(3).fill(-1); + this.triangles[0] = hull[0]; + inedges[hull[0]] = 1; + if (hull.length === 2) { + inedges[hull[1]] = 0; + this.triangles[1] = hull[1]; + this.triangles[2] = hull[1]; + } + } + } + voronoi(bounds) { + return new Voronoi(this, bounds); + } + *neighbors(i) { + const {inedges, hull, _hullIndex, halfedges, triangles, collinear} = this; + + // degenerate case with several collinear points + if (collinear) { + const l = collinear.indexOf(i); + if (l > 0) yield collinear[l - 1]; + if (l < collinear.length - 1) yield collinear[l + 1]; + return; + } + + const e0 = inedges[i]; + if (e0 === -1) return; // coincident point + let e = e0, p0 = -1; + do { + yield p0 = triangles[e]; + e = e % 3 === 2 ? e - 2 : e + 1; + if (triangles[e] !== i) return; // bad triangulation + e = halfedges[e]; + if (e === -1) { + const p = hull[(_hullIndex[i] + 1) % hull.length]; + if (p !== p0) yield p; + return; + } + } while (e !== e0); + } + find(x, y, i = 0) { + if ((x = +x, x !== x) || (y = +y, y !== y)) return -1; + const i0 = i; + let c; + while ((c = this._step(i, x, y)) >= 0 && c !== i && c !== i0) i = c; + return c; + } + _step(i, x, y) { + const {inedges, hull, _hullIndex, halfedges, triangles, points} = this; + if (inedges[i] === -1 || !points.length) return (i + 1) % (points.length >> 1); + let c = i; + let dc = pow$2(x - points[i * 2], 2) + pow$2(y - points[i * 2 + 1], 2); + const e0 = inedges[i]; + let e = e0; + do { + let t = triangles[e]; + const dt = pow$2(x - points[t * 2], 2) + pow$2(y - points[t * 2 + 1], 2); + if (dt < dc) dc = dt, c = t; + e = e % 3 === 2 ? e - 2 : e + 1; + if (triangles[e] !== i) break; // bad triangulation + e = halfedges[e]; + if (e === -1) { + e = hull[(_hullIndex[i] + 1) % hull.length]; + if (e !== t) { + if (pow$2(x - points[e * 2], 2) + pow$2(y - points[e * 2 + 1], 2) < dc) return e; + } + break; + } + } while (e !== e0); + return c; + } + render(context) { + const buffer = context == null ? context = new Path : undefined; + const {points, halfedges, triangles} = this; + for (let i = 0, n = halfedges.length; i < n; ++i) { + const j = halfedges[i]; + if (j < i) continue; + const ti = triangles[i] * 2; + const tj = triangles[j] * 2; + context.moveTo(points[ti], points[ti + 1]); + context.lineTo(points[tj], points[tj + 1]); + } + this.renderHull(context); + return buffer && buffer.value(); + } + renderPoints(context, r) { + if (r === undefined && (!context || typeof context.moveTo !== "function")) r = context, context = null; + r = r == undefined ? 2 : +r; + const buffer = context == null ? context = new Path : undefined; + const {points} = this; + for (let i = 0, n = points.length; i < n; i += 2) { + const x = points[i], y = points[i + 1]; + context.moveTo(x + r, y); + context.arc(x, y, r, 0, tau$2); + } + return buffer && buffer.value(); + } + renderHull(context) { + const buffer = context == null ? context = new Path : undefined; + const {hull, points} = this; + const h = hull[0] * 2, n = hull.length; + context.moveTo(points[h], points[h + 1]); + for (let i = 1; i < n; ++i) { + const h = 2 * hull[i]; + context.lineTo(points[h], points[h + 1]); + } + context.closePath(); + return buffer && buffer.value(); + } + hullPolygon() { + const polygon = new Polygon; + this.renderHull(polygon); + return polygon.value(); + } + renderTriangle(i, context) { + const buffer = context == null ? context = new Path : undefined; + const {points, triangles} = this; + const t0 = triangles[i *= 3] * 2; + const t1 = triangles[i + 1] * 2; + const t2 = triangles[i + 2] * 2; + context.moveTo(points[t0], points[t0 + 1]); + context.lineTo(points[t1], points[t1 + 1]); + context.lineTo(points[t2], points[t2 + 1]); + context.closePath(); + return buffer && buffer.value(); + } + *trianglePolygons() { + const {triangles} = this; + for (let i = 0, n = triangles.length / 3; i < n; ++i) { + yield this.trianglePolygon(i); + } + } + trianglePolygon(i) { + const polygon = new Polygon; + this.renderTriangle(i, polygon); + return polygon.value(); + } +} + +function flatArray(points, fx, fy, that) { + const n = points.length; + const array = new Float64Array(n * 2); + for (let i = 0; i < n; ++i) { + const p = points[i]; + array[i * 2] = fx.call(that, p, i, points); + array[i * 2 + 1] = fy.call(that, p, i, points); + } + return array; +} + +function* flatIterable(points, fx, fy, that) { + let i = 0; + for (const p of points) { + yield fx.call(that, p, i, points); + yield fy.call(that, p, i, points); + ++i; + } +} + +var EOL = {}, + EOF = {}, + QUOTE = 34, + NEWLINE = 10, + RETURN = 13; + +function objectConverter(columns) { + return new Function("d", "return {" + columns.map(function(name, i) { + return JSON.stringify(name) + ": d[" + i + "] || \"\""; + }).join(",") + "}"); +} + +function customConverter(columns, f) { + var object = objectConverter(columns); + return function(row, i) { + return f(object(row), i, columns); + }; +} + +// Compute unique columns in order of discovery. +function inferColumns(rows) { + var columnSet = Object.create(null), + columns = []; + + rows.forEach(function(row) { + for (var column in row) { + if (!(column in columnSet)) { + columns.push(columnSet[column] = column); + } + } + }); + + return columns; +} + +function pad$1(value, width) { + var s = value + "", length = s.length; + return length < width ? new Array(width - length + 1).join(0) + s : s; +} + +function formatYear$1(year) { + return year < 0 ? "-" + pad$1(-year, 6) + : year > 9999 ? "+" + pad$1(year, 6) + : pad$1(year, 4); +} + +function formatDate(date) { + var hours = date.getUTCHours(), + minutes = date.getUTCMinutes(), + seconds = date.getUTCSeconds(), + milliseconds = date.getUTCMilliseconds(); + return isNaN(date) ? "Invalid Date" + : formatYear$1(date.getUTCFullYear()) + "-" + pad$1(date.getUTCMonth() + 1, 2) + "-" + pad$1(date.getUTCDate(), 2) + + (milliseconds ? "T" + pad$1(hours, 2) + ":" + pad$1(minutes, 2) + ":" + pad$1(seconds, 2) + "." + pad$1(milliseconds, 3) + "Z" + : seconds ? "T" + pad$1(hours, 2) + ":" + pad$1(minutes, 2) + ":" + pad$1(seconds, 2) + "Z" + : minutes || hours ? "T" + pad$1(hours, 2) + ":" + pad$1(minutes, 2) + "Z" + : ""); +} + +function dsvFormat(delimiter) { + var reFormat = new RegExp("[\"" + delimiter + "\n\r]"), + DELIMITER = delimiter.charCodeAt(0); + + function parse(text, f) { + var convert, columns, rows = parseRows(text, function(row, i) { + if (convert) return convert(row, i - 1); + columns = row, convert = f ? customConverter(row, f) : objectConverter(row); + }); + rows.columns = columns || []; + return rows; + } + + function parseRows(text, f) { + var rows = [], // output rows + N = text.length, + I = 0, // current character index + n = 0, // current line number + t, // current token + eof = N <= 0, // current token followed by EOF? + eol = false; // current token followed by EOL? + + // Strip the trailing newline. + if (text.charCodeAt(N - 1) === NEWLINE) --N; + if (text.charCodeAt(N - 1) === RETURN) --N; + + function token() { + if (eof) return EOF; + if (eol) return eol = false, EOL; + + // Unescape quotes. + var i, j = I, c; + if (text.charCodeAt(j) === QUOTE) { + while (I++ < N && text.charCodeAt(I) !== QUOTE || text.charCodeAt(++I) === QUOTE); + if ((i = I) >= N) eof = true; + else if ((c = text.charCodeAt(I++)) === NEWLINE) eol = true; + else if (c === RETURN) { eol = true; if (text.charCodeAt(I) === NEWLINE) ++I; } + return text.slice(j + 1, i - 1).replace(/""/g, "\""); + } + + // Find next delimiter or newline. + while (I < N) { + if ((c = text.charCodeAt(i = I++)) === NEWLINE) eol = true; + else if (c === RETURN) { eol = true; if (text.charCodeAt(I) === NEWLINE) ++I; } + else if (c !== DELIMITER) continue; + return text.slice(j, i); + } + + // Return last token before EOF. + return eof = true, text.slice(j, N); + } + + while ((t = token()) !== EOF) { + var row = []; + while (t !== EOL && t !== EOF) row.push(t), t = token(); + if (f && (row = f(row, n++)) == null) continue; + rows.push(row); + } + + return rows; + } + + function preformatBody(rows, columns) { + return rows.map(function(row) { + return columns.map(function(column) { + return formatValue(row[column]); + }).join(delimiter); + }); + } + + function format(rows, columns) { + if (columns == null) columns = inferColumns(rows); + return [columns.map(formatValue).join(delimiter)].concat(preformatBody(rows, columns)).join("\n"); + } + + function formatBody(rows, columns) { + if (columns == null) columns = inferColumns(rows); + return preformatBody(rows, columns).join("\n"); + } + + function formatRows(rows) { + return rows.map(formatRow).join("\n"); + } + + function formatRow(row) { + return row.map(formatValue).join(delimiter); + } + + function formatValue(value) { + return value == null ? "" + : value instanceof Date ? formatDate(value) + : reFormat.test(value += "") ? "\"" + value.replace(/"/g, "\"\"") + "\"" + : value; + } + + return { + parse: parse, + parseRows: parseRows, + format: format, + formatBody: formatBody, + formatRows: formatRows, + formatRow: formatRow, + formatValue: formatValue + }; +} + +var csv$1 = dsvFormat(","); + +var csvParse = csv$1.parse; +var csvParseRows = csv$1.parseRows; +var csvFormat = csv$1.format; +var csvFormatBody = csv$1.formatBody; +var csvFormatRows = csv$1.formatRows; +var csvFormatRow = csv$1.formatRow; +var csvFormatValue = csv$1.formatValue; + +var tsv$1 = dsvFormat("\t"); + +var tsvParse = tsv$1.parse; +var tsvParseRows = tsv$1.parseRows; +var tsvFormat = tsv$1.format; +var tsvFormatBody = tsv$1.formatBody; +var tsvFormatRows = tsv$1.formatRows; +var tsvFormatRow = tsv$1.formatRow; +var tsvFormatValue = tsv$1.formatValue; + +function autoType(object) { + for (var key in object) { + var value = object[key].trim(), number, m; + if (!value) value = null; + else if (value === "true") value = true; + else if (value === "false") value = false; + else if (value === "NaN") value = NaN; + else if (!isNaN(number = +value)) value = number; + else if (m = value.match(/^([-+]\d{2})?\d{4}(-\d{2}(-\d{2})?)?(T\d{2}:\d{2}(:\d{2}(\.\d{3})?)?(Z|[-+]\d{2}:\d{2})?)?$/)) { + if (fixtz && !!m[4] && !m[7]) value = value.replace(/-/g, "/").replace(/T/, " "); + value = new Date(value); + } + else continue; + object[key] = value; + } + return object; +} + +// https://github.com/d3/d3-dsv/issues/45 +const fixtz = new Date("2019-01-01T00:00").getHours() || new Date("2019-07-01T00:00").getHours(); + +function responseBlob(response) { + if (!response.ok) throw new Error(response.status + " " + response.statusText); + return response.blob(); +} + +function blob(input, init) { + return fetch(input, init).then(responseBlob); +} + +function responseArrayBuffer(response) { + if (!response.ok) throw new Error(response.status + " " + response.statusText); + return response.arrayBuffer(); +} + +function buffer(input, init) { + return fetch(input, init).then(responseArrayBuffer); +} + +function responseText(response) { + if (!response.ok) throw new Error(response.status + " " + response.statusText); + return response.text(); +} + +function text(input, init) { + return fetch(input, init).then(responseText); +} + +function dsvParse(parse) { + return function(input, init, row) { + if (arguments.length === 2 && typeof init === "function") row = init, init = undefined; + return text(input, init).then(function(response) { + return parse(response, row); + }); + }; +} + +function dsv(delimiter, input, init, row) { + if (arguments.length === 3 && typeof init === "function") row = init, init = undefined; + var format = dsvFormat(delimiter); + return text(input, init).then(function(response) { + return format.parse(response, row); + }); +} + +var csv = dsvParse(csvParse); +var tsv = dsvParse(tsvParse); + +function image(input, init) { + return new Promise(function(resolve, reject) { + var image = new Image; + for (var key in init) image[key] = init[key]; + image.onerror = reject; + image.onload = function() { resolve(image); }; + image.src = input; + }); +} + +function responseJson(response) { + if (!response.ok) throw new Error(response.status + " " + response.statusText); + if (response.status === 204 || response.status === 205) return; + return response.json(); +} + +function json(input, init) { + return fetch(input, init).then(responseJson); +} + +function parser(type) { + return (input, init) => text(input, init) + .then(text => (new DOMParser).parseFromString(text, type)); +} + +var xml = parser("application/xml"); + +var html = parser("text/html"); + +var svg = parser("image/svg+xml"); + +function center(x, y) { + var nodes, strength = 1; + + if (x == null) x = 0; + if (y == null) y = 0; + + function force() { + var i, + n = nodes.length, + node, + sx = 0, + sy = 0; + + for (i = 0; i < n; ++i) { + node = nodes[i], sx += node.x, sy += node.y; + } + + for (sx = (sx / n - x) * strength, sy = (sy / n - y) * strength, i = 0; i < n; ++i) { + node = nodes[i], node.x -= sx, node.y -= sy; + } + } + + force.initialize = function(_) { + nodes = _; + }; + + force.x = function(_) { + return arguments.length ? (x = +_, force) : x; + }; + + force.y = function(_) { + return arguments.length ? (y = +_, force) : y; + }; + + force.strength = function(_) { + return arguments.length ? (strength = +_, force) : strength; + }; + + return force; +} + +function tree_add(d) { + const x = +this._x.call(null, d), + y = +this._y.call(null, d); + return add(this.cover(x, y), x, y, d); +} + +function add(tree, x, y, d) { + if (isNaN(x) || isNaN(y)) return tree; // ignore invalid points + + var parent, + node = tree._root, + leaf = {data: d}, + x0 = tree._x0, + y0 = tree._y0, + x1 = tree._x1, + y1 = tree._y1, + xm, + ym, + xp, + yp, + right, + bottom, + i, + j; + + // If the tree is empty, initialize the root as a leaf. + if (!node) return tree._root = leaf, tree; + + // Find the existing leaf for the new point, or add it. + while (node.length) { + if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm; + if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym; + if (parent = node, !(node = node[i = bottom << 1 | right])) return parent[i] = leaf, tree; + } + + // Is the new point is exactly coincident with the existing point? + xp = +tree._x.call(null, node.data); + yp = +tree._y.call(null, node.data); + if (x === xp && y === yp) return leaf.next = node, parent ? parent[i] = leaf : tree._root = leaf, tree; + + // Otherwise, split the leaf node until the old and new point are separated. + do { + parent = parent ? parent[i] = new Array(4) : tree._root = new Array(4); + if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm; + if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym; + } while ((i = bottom << 1 | right) === (j = (yp >= ym) << 1 | (xp >= xm))); + return parent[j] = node, parent[i] = leaf, tree; +} + +function addAll(data) { + var d, i, n = data.length, + x, + y, + xz = new Array(n), + yz = new Array(n), + x0 = Infinity, + y0 = Infinity, + x1 = -Infinity, + y1 = -Infinity; + + // Compute the points and their extent. + for (i = 0; i < n; ++i) { + if (isNaN(x = +this._x.call(null, d = data[i])) || isNaN(y = +this._y.call(null, d))) continue; + xz[i] = x; + yz[i] = y; + if (x < x0) x0 = x; + if (x > x1) x1 = x; + if (y < y0) y0 = y; + if (y > y1) y1 = y; + } + + // If there were no (valid) points, abort. + if (x0 > x1 || y0 > y1) return this; + + // Expand the tree to cover the new points. + this.cover(x0, y0).cover(x1, y1); + + // Add the new points. + for (i = 0; i < n; ++i) { + add(this, xz[i], yz[i], data[i]); + } + + return this; +} + +function tree_cover(x, y) { + if (isNaN(x = +x) || isNaN(y = +y)) return this; // ignore invalid points + + var x0 = this._x0, + y0 = this._y0, + x1 = this._x1, + y1 = this._y1; + + // If the quadtree has no extent, initialize them. + // Integer extent are necessary so that if we later double the extent, + // the existing quadrant boundaries don’t change due to floating point error! + if (isNaN(x0)) { + x1 = (x0 = Math.floor(x)) + 1; + y1 = (y0 = Math.floor(y)) + 1; + } + + // Otherwise, double repeatedly to cover. + else { + var z = x1 - x0 || 1, + node = this._root, + parent, + i; + + while (x0 > x || x >= x1 || y0 > y || y >= y1) { + i = (y < y0) << 1 | (x < x0); + parent = new Array(4), parent[i] = node, node = parent, z *= 2; + switch (i) { + case 0: x1 = x0 + z, y1 = y0 + z; break; + case 1: x0 = x1 - z, y1 = y0 + z; break; + case 2: x1 = x0 + z, y0 = y1 - z; break; + case 3: x0 = x1 - z, y0 = y1 - z; break; + } + } + + if (this._root && this._root.length) this._root = node; + } + + this._x0 = x0; + this._y0 = y0; + this._x1 = x1; + this._y1 = y1; + return this; +} + +function tree_data() { + var data = []; + this.visit(function(node) { + if (!node.length) do data.push(node.data); while (node = node.next) + }); + return data; +} + +function tree_extent(_) { + return arguments.length + ? this.cover(+_[0][0], +_[0][1]).cover(+_[1][0], +_[1][1]) + : isNaN(this._x0) ? undefined : [[this._x0, this._y0], [this._x1, this._y1]]; +} + +function Quad(node, x0, y0, x1, y1) { + this.node = node; + this.x0 = x0; + this.y0 = y0; + this.x1 = x1; + this.y1 = y1; +} + +function tree_find(x, y, radius) { + var data, + x0 = this._x0, + y0 = this._y0, + x1, + y1, + x2, + y2, + x3 = this._x1, + y3 = this._y1, + quads = [], + node = this._root, + q, + i; + + if (node) quads.push(new Quad(node, x0, y0, x3, y3)); + if (radius == null) radius = Infinity; + else { + x0 = x - radius, y0 = y - radius; + x3 = x + radius, y3 = y + radius; + radius *= radius; + } + + while (q = quads.pop()) { + + // Stop searching if this quadrant can’t contain a closer node. + if (!(node = q.node) + || (x1 = q.x0) > x3 + || (y1 = q.y0) > y3 + || (x2 = q.x1) < x0 + || (y2 = q.y1) < y0) continue; + + // Bisect the current quadrant. + if (node.length) { + var xm = (x1 + x2) / 2, + ym = (y1 + y2) / 2; + + quads.push( + new Quad(node[3], xm, ym, x2, y2), + new Quad(node[2], x1, ym, xm, y2), + new Quad(node[1], xm, y1, x2, ym), + new Quad(node[0], x1, y1, xm, ym) + ); + + // Visit the closest quadrant first. + if (i = (y >= ym) << 1 | (x >= xm)) { + q = quads[quads.length - 1]; + quads[quads.length - 1] = quads[quads.length - 1 - i]; + quads[quads.length - 1 - i] = q; + } + } + + // Visit this point. (Visiting coincident points isn’t necessary!) + else { + var dx = x - +this._x.call(null, node.data), + dy = y - +this._y.call(null, node.data), + d2 = dx * dx + dy * dy; + if (d2 < radius) { + var d = Math.sqrt(radius = d2); + x0 = x - d, y0 = y - d; + x3 = x + d, y3 = y + d; + data = node.data; + } + } + } + + return data; +} + +function tree_remove(d) { + if (isNaN(x = +this._x.call(null, d)) || isNaN(y = +this._y.call(null, d))) return this; // ignore invalid points + + var parent, + node = this._root, + retainer, + previous, + next, + x0 = this._x0, + y0 = this._y0, + x1 = this._x1, + y1 = this._y1, + x, + y, + xm, + ym, + right, + bottom, + i, + j; + + // If the tree is empty, initialize the root as a leaf. + if (!node) return this; + + // Find the leaf node for the point. + // While descending, also retain the deepest parent with a non-removed sibling. + if (node.length) while (true) { + if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm; + if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym; + if (!(parent = node, node = node[i = bottom << 1 | right])) return this; + if (!node.length) break; + if (parent[(i + 1) & 3] || parent[(i + 2) & 3] || parent[(i + 3) & 3]) retainer = parent, j = i; + } + + // Find the point to remove. + while (node.data !== d) if (!(previous = node, node = node.next)) return this; + if (next = node.next) delete node.next; + + // If there are multiple coincident points, remove just the point. + if (previous) return (next ? previous.next = next : delete previous.next), this; + + // If this is the root point, remove it. + if (!parent) return this._root = next, this; + + // Remove this leaf. + next ? parent[i] = next : delete parent[i]; + + // If the parent now contains exactly one leaf, collapse superfluous parents. + if ((node = parent[0] || parent[1] || parent[2] || parent[3]) + && node === (parent[3] || parent[2] || parent[1] || parent[0]) + && !node.length) { + if (retainer) retainer[j] = node; + else this._root = node; + } + + return this; +} + +function removeAll(data) { + for (var i = 0, n = data.length; i < n; ++i) this.remove(data[i]); + return this; +} + +function tree_root() { + return this._root; +} + +function tree_size() { + var size = 0; + this.visit(function(node) { + if (!node.length) do ++size; while (node = node.next) + }); + return size; +} + +function tree_visit(callback) { + var quads = [], q, node = this._root, child, x0, y0, x1, y1; + if (node) quads.push(new Quad(node, this._x0, this._y0, this._x1, this._y1)); + while (q = quads.pop()) { + if (!callback(node = q.node, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1) && node.length) { + var xm = (x0 + x1) / 2, ym = (y0 + y1) / 2; + if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1)); + if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1)); + if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym)); + if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym)); + } + } + return this; +} + +function tree_visitAfter(callback) { + var quads = [], next = [], q; + if (this._root) quads.push(new Quad(this._root, this._x0, this._y0, this._x1, this._y1)); + while (q = quads.pop()) { + var node = q.node; + if (node.length) { + var child, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1, xm = (x0 + x1) / 2, ym = (y0 + y1) / 2; + if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym)); + if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym)); + if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1)); + if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1)); + } + next.push(q); + } + while (q = next.pop()) { + callback(q.node, q.x0, q.y0, q.x1, q.y1); + } + return this; +} + +function defaultX(d) { + return d[0]; +} + +function tree_x(_) { + return arguments.length ? (this._x = _, this) : this._x; +} + +function defaultY(d) { + return d[1]; +} + +function tree_y(_) { + return arguments.length ? (this._y = _, this) : this._y; +} + +function quadtree(nodes, x, y) { + var tree = new Quadtree(x == null ? defaultX : x, y == null ? defaultY : y, NaN, NaN, NaN, NaN); + return nodes == null ? tree : tree.addAll(nodes); +} + +function Quadtree(x, y, x0, y0, x1, y1) { + this._x = x; + this._y = y; + this._x0 = x0; + this._y0 = y0; + this._x1 = x1; + this._y1 = y1; + this._root = undefined; +} + +function leaf_copy(leaf) { + var copy = {data: leaf.data}, next = copy; + while (leaf = leaf.next) next = next.next = {data: leaf.data}; + return copy; +} + +var treeProto = quadtree.prototype = Quadtree.prototype; + +treeProto.copy = function() { + var copy = new Quadtree(this._x, this._y, this._x0, this._y0, this._x1, this._y1), + node = this._root, + nodes, + child; + + if (!node) return copy; + + if (!node.length) return copy._root = leaf_copy(node), copy; + + nodes = [{source: node, target: copy._root = new Array(4)}]; + while (node = nodes.pop()) { + for (var i = 0; i < 4; ++i) { + if (child = node.source[i]) { + if (child.length) nodes.push({source: child, target: node.target[i] = new Array(4)}); + else node.target[i] = leaf_copy(child); + } + } + } + + return copy; +}; + +treeProto.add = tree_add; +treeProto.addAll = addAll; +treeProto.cover = tree_cover; +treeProto.data = tree_data; +treeProto.extent = tree_extent; +treeProto.find = tree_find; +treeProto.remove = tree_remove; +treeProto.removeAll = removeAll; +treeProto.root = tree_root; +treeProto.size = tree_size; +treeProto.visit = tree_visit; +treeProto.visitAfter = tree_visitAfter; +treeProto.x = tree_x; +treeProto.y = tree_y; + +function constant$4(x) { + return function() { + return x; + }; +} + +function jiggle(random) { + return (random() - 0.5) * 1e-6; +} + +function x$3(d) { + return d.x + d.vx; +} + +function y$3(d) { + return d.y + d.vy; +} + +function collide(radius) { + var nodes, + radii, + random, + strength = 1, + iterations = 1; + + if (typeof radius !== "function") radius = constant$4(radius == null ? 1 : +radius); + + function force() { + var i, n = nodes.length, + tree, + node, + xi, + yi, + ri, + ri2; + + for (var k = 0; k < iterations; ++k) { + tree = quadtree(nodes, x$3, y$3).visitAfter(prepare); + for (i = 0; i < n; ++i) { + node = nodes[i]; + ri = radii[node.index], ri2 = ri * ri; + xi = node.x + node.vx; + yi = node.y + node.vy; + tree.visit(apply); + } + } + + function apply(quad, x0, y0, x1, y1) { + var data = quad.data, rj = quad.r, r = ri + rj; + if (data) { + if (data.index > node.index) { + var x = xi - data.x - data.vx, + y = yi - data.y - data.vy, + l = x * x + y * y; + if (l < r * r) { + if (x === 0) x = jiggle(random), l += x * x; + if (y === 0) y = jiggle(random), l += y * y; + l = (r - (l = Math.sqrt(l))) / l * strength; + node.vx += (x *= l) * (r = (rj *= rj) / (ri2 + rj)); + node.vy += (y *= l) * r; + data.vx -= x * (r = 1 - r); + data.vy -= y * r; + } + } + return; + } + return x0 > xi + r || x1 < xi - r || y0 > yi + r || y1 < yi - r; + } + } + + function prepare(quad) { + if (quad.data) return quad.r = radii[quad.data.index]; + for (var i = quad.r = 0; i < 4; ++i) { + if (quad[i] && quad[i].r > quad.r) { + quad.r = quad[i].r; + } + } + } + + function initialize() { + if (!nodes) return; + var i, n = nodes.length, node; + radii = new Array(n); + for (i = 0; i < n; ++i) node = nodes[i], radii[node.index] = +radius(node, i, nodes); + } + + force.initialize = function(_nodes, _random) { + nodes = _nodes; + random = _random; + initialize(); + }; + + force.iterations = function(_) { + return arguments.length ? (iterations = +_, force) : iterations; + }; + + force.strength = function(_) { + return arguments.length ? (strength = +_, force) : strength; + }; + + force.radius = function(_) { + return arguments.length ? (radius = typeof _ === "function" ? _ : constant$4(+_), initialize(), force) : radius; + }; + + return force; +} + +function index$3(d) { + return d.index; +} + +function find(nodeById, nodeId) { + var node = nodeById.get(nodeId); + if (!node) throw new Error("node not found: " + nodeId); + return node; +} + +function link$2(links) { + var id = index$3, + strength = defaultStrength, + strengths, + distance = constant$4(30), + distances, + nodes, + count, + bias, + random, + iterations = 1; + + if (links == null) links = []; + + function defaultStrength(link) { + return 1 / Math.min(count[link.source.index], count[link.target.index]); + } + + function force(alpha) { + for (var k = 0, n = links.length; k < iterations; ++k) { + for (var i = 0, link, source, target, x, y, l, b; i < n; ++i) { + link = links[i], source = link.source, target = link.target; + x = target.x + target.vx - source.x - source.vx || jiggle(random); + y = target.y + target.vy - source.y - source.vy || jiggle(random); + l = Math.sqrt(x * x + y * y); + l = (l - distances[i]) / l * alpha * strengths[i]; + x *= l, y *= l; + target.vx -= x * (b = bias[i]); + target.vy -= y * b; + source.vx += x * (b = 1 - b); + source.vy += y * b; + } + } + } + + function initialize() { + if (!nodes) return; + + var i, + n = nodes.length, + m = links.length, + nodeById = new Map(nodes.map((d, i) => [id(d, i, nodes), d])), + link; + + for (i = 0, count = new Array(n); i < m; ++i) { + link = links[i], link.index = i; + if (typeof link.source !== "object") link.source = find(nodeById, link.source); + if (typeof link.target !== "object") link.target = find(nodeById, link.target); + count[link.source.index] = (count[link.source.index] || 0) + 1; + count[link.target.index] = (count[link.target.index] || 0) + 1; + } + + for (i = 0, bias = new Array(m); i < m; ++i) { + link = links[i], bias[i] = count[link.source.index] / (count[link.source.index] + count[link.target.index]); + } + + strengths = new Array(m), initializeStrength(); + distances = new Array(m), initializeDistance(); + } + + function initializeStrength() { + if (!nodes) return; + + for (var i = 0, n = links.length; i < n; ++i) { + strengths[i] = +strength(links[i], i, links); + } + } + + function initializeDistance() { + if (!nodes) return; + + for (var i = 0, n = links.length; i < n; ++i) { + distances[i] = +distance(links[i], i, links); + } + } + + force.initialize = function(_nodes, _random) { + nodes = _nodes; + random = _random; + initialize(); + }; + + force.links = function(_) { + return arguments.length ? (links = _, initialize(), force) : links; + }; + + force.id = function(_) { + return arguments.length ? (id = _, force) : id; + }; + + force.iterations = function(_) { + return arguments.length ? (iterations = +_, force) : iterations; + }; + + force.strength = function(_) { + return arguments.length ? (strength = typeof _ === "function" ? _ : constant$4(+_), initializeStrength(), force) : strength; + }; + + force.distance = function(_) { + return arguments.length ? (distance = typeof _ === "function" ? _ : constant$4(+_), initializeDistance(), force) : distance; + }; + + return force; +} + +// https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use +const a$1 = 1664525; +const c$3 = 1013904223; +const m = 4294967296; // 2^32 + +function lcg$1() { + let s = 1; + return () => (s = (a$1 * s + c$3) % m) / m; +} + +function x$2(d) { + return d.x; +} + +function y$2(d) { + return d.y; +} + +var initialRadius = 10, + initialAngle = Math.PI * (3 - Math.sqrt(5)); + +function simulation(nodes) { + var simulation, + alpha = 1, + alphaMin = 0.001, + alphaDecay = 1 - Math.pow(alphaMin, 1 / 300), + alphaTarget = 0, + velocityDecay = 0.6, + forces = new Map(), + stepper = timer(step), + event = dispatch("tick", "end"), + random = lcg$1(); + + if (nodes == null) nodes = []; + + function step() { + tick(); + event.call("tick", simulation); + if (alpha < alphaMin) { + stepper.stop(); + event.call("end", simulation); + } + } + + function tick(iterations) { + var i, n = nodes.length, node; + + if (iterations === undefined) iterations = 1; + + for (var k = 0; k < iterations; ++k) { + alpha += (alphaTarget - alpha) * alphaDecay; + + forces.forEach(function(force) { + force(alpha); + }); + + for (i = 0; i < n; ++i) { + node = nodes[i]; + if (node.fx == null) node.x += node.vx *= velocityDecay; + else node.x = node.fx, node.vx = 0; + if (node.fy == null) node.y += node.vy *= velocityDecay; + else node.y = node.fy, node.vy = 0; + } + } + + return simulation; + } + + function initializeNodes() { + for (var i = 0, n = nodes.length, node; i < n; ++i) { + node = nodes[i], node.index = i; + if (node.fx != null) node.x = node.fx; + if (node.fy != null) node.y = node.fy; + if (isNaN(node.x) || isNaN(node.y)) { + var radius = initialRadius * Math.sqrt(0.5 + i), angle = i * initialAngle; + node.x = radius * Math.cos(angle); + node.y = radius * Math.sin(angle); + } + if (isNaN(node.vx) || isNaN(node.vy)) { + node.vx = node.vy = 0; + } + } + } + + function initializeForce(force) { + if (force.initialize) force.initialize(nodes, random); + return force; + } + + initializeNodes(); + + return simulation = { + tick: tick, + + restart: function() { + return stepper.restart(step), simulation; + }, + + stop: function() { + return stepper.stop(), simulation; + }, + + nodes: function(_) { + return arguments.length ? (nodes = _, initializeNodes(), forces.forEach(initializeForce), simulation) : nodes; + }, + + alpha: function(_) { + return arguments.length ? (alpha = +_, simulation) : alpha; + }, + + alphaMin: function(_) { + return arguments.length ? (alphaMin = +_, simulation) : alphaMin; + }, + + alphaDecay: function(_) { + return arguments.length ? (alphaDecay = +_, simulation) : +alphaDecay; + }, + + alphaTarget: function(_) { + return arguments.length ? (alphaTarget = +_, simulation) : alphaTarget; + }, + + velocityDecay: function(_) { + return arguments.length ? (velocityDecay = 1 - _, simulation) : 1 - velocityDecay; + }, + + randomSource: function(_) { + return arguments.length ? (random = _, forces.forEach(initializeForce), simulation) : random; + }, + + force: function(name, _) { + return arguments.length > 1 ? ((_ == null ? forces.delete(name) : forces.set(name, initializeForce(_))), simulation) : forces.get(name); + }, + + find: function(x, y, radius) { + var i = 0, + n = nodes.length, + dx, + dy, + d2, + node, + closest; + + if (radius == null) radius = Infinity; + else radius *= radius; + + for (i = 0; i < n; ++i) { + node = nodes[i]; + dx = x - node.x; + dy = y - node.y; + d2 = dx * dx + dy * dy; + if (d2 < radius) closest = node, radius = d2; + } + + return closest; + }, + + on: function(name, _) { + return arguments.length > 1 ? (event.on(name, _), simulation) : event.on(name); + } + }; +} + +function manyBody() { + var nodes, + node, + random, + alpha, + strength = constant$4(-30), + strengths, + distanceMin2 = 1, + distanceMax2 = Infinity, + theta2 = 0.81; + + function force(_) { + var i, n = nodes.length, tree = quadtree(nodes, x$2, y$2).visitAfter(accumulate); + for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply); + } + + function initialize() { + if (!nodes) return; + var i, n = nodes.length, node; + strengths = new Array(n); + for (i = 0; i < n; ++i) node = nodes[i], strengths[node.index] = +strength(node, i, nodes); + } + + function accumulate(quad) { + var strength = 0, q, c, weight = 0, x, y, i; + + // For internal nodes, accumulate forces from child quadrants. + if (quad.length) { + for (x = y = i = 0; i < 4; ++i) { + if ((q = quad[i]) && (c = Math.abs(q.value))) { + strength += q.value, weight += c, x += c * q.x, y += c * q.y; + } + } + quad.x = x / weight; + quad.y = y / weight; + } + + // For leaf nodes, accumulate forces from coincident quadrants. + else { + q = quad; + q.x = q.data.x; + q.y = q.data.y; + do strength += strengths[q.data.index]; + while (q = q.next); + } + + quad.value = strength; + } + + function apply(quad, x1, _, x2) { + if (!quad.value) return true; + + var x = quad.x - node.x, + y = quad.y - node.y, + w = x2 - x1, + l = x * x + y * y; + + // Apply the Barnes-Hut approximation if possible. + // Limit forces for very close nodes; randomize direction if coincident. + if (w * w / theta2 < l) { + if (l < distanceMax2) { + if (x === 0) x = jiggle(random), l += x * x; + if (y === 0) y = jiggle(random), l += y * y; + if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l); + node.vx += x * quad.value * alpha / l; + node.vy += y * quad.value * alpha / l; + } + return true; + } + + // Otherwise, process points directly. + else if (quad.length || l >= distanceMax2) return; + + // Limit forces for very close nodes; randomize direction if coincident. + if (quad.data !== node || quad.next) { + if (x === 0) x = jiggle(random), l += x * x; + if (y === 0) y = jiggle(random), l += y * y; + if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l); + } + + do if (quad.data !== node) { + w = strengths[quad.data.index] * alpha / l; + node.vx += x * w; + node.vy += y * w; + } while (quad = quad.next); + } + + force.initialize = function(_nodes, _random) { + nodes = _nodes; + random = _random; + initialize(); + }; + + force.strength = function(_) { + return arguments.length ? (strength = typeof _ === "function" ? _ : constant$4(+_), initialize(), force) : strength; + }; + + force.distanceMin = function(_) { + return arguments.length ? (distanceMin2 = _ * _, force) : Math.sqrt(distanceMin2); + }; + + force.distanceMax = function(_) { + return arguments.length ? (distanceMax2 = _ * _, force) : Math.sqrt(distanceMax2); + }; + + force.theta = function(_) { + return arguments.length ? (theta2 = _ * _, force) : Math.sqrt(theta2); + }; + + return force; +} + +function radial$1(radius, x, y) { + var nodes, + strength = constant$4(0.1), + strengths, + radiuses; + + if (typeof radius !== "function") radius = constant$4(+radius); + if (x == null) x = 0; + if (y == null) y = 0; + + function force(alpha) { + for (var i = 0, n = nodes.length; i < n; ++i) { + var node = nodes[i], + dx = node.x - x || 1e-6, + dy = node.y - y || 1e-6, + r = Math.sqrt(dx * dx + dy * dy), + k = (radiuses[i] - r) * strengths[i] * alpha / r; + node.vx += dx * k; + node.vy += dy * k; + } + } + + function initialize() { + if (!nodes) return; + var i, n = nodes.length; + strengths = new Array(n); + radiuses = new Array(n); + for (i = 0; i < n; ++i) { + radiuses[i] = +radius(nodes[i], i, nodes); + strengths[i] = isNaN(radiuses[i]) ? 0 : +strength(nodes[i], i, nodes); + } + } + + force.initialize = function(_) { + nodes = _, initialize(); + }; + + force.strength = function(_) { + return arguments.length ? (strength = typeof _ === "function" ? _ : constant$4(+_), initialize(), force) : strength; + }; + + force.radius = function(_) { + return arguments.length ? (radius = typeof _ === "function" ? _ : constant$4(+_), initialize(), force) : radius; + }; + + force.x = function(_) { + return arguments.length ? (x = +_, force) : x; + }; + + force.y = function(_) { + return arguments.length ? (y = +_, force) : y; + }; + + return force; +} + +function x$1(x) { + var strength = constant$4(0.1), + nodes, + strengths, + xz; + + if (typeof x !== "function") x = constant$4(x == null ? 0 : +x); + + function force(alpha) { + for (var i = 0, n = nodes.length, node; i < n; ++i) { + node = nodes[i], node.vx += (xz[i] - node.x) * strengths[i] * alpha; + } + } + + function initialize() { + if (!nodes) return; + var i, n = nodes.length; + strengths = new Array(n); + xz = new Array(n); + for (i = 0; i < n; ++i) { + strengths[i] = isNaN(xz[i] = +x(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes); + } + } + + force.initialize = function(_) { + nodes = _; + initialize(); + }; + + force.strength = function(_) { + return arguments.length ? (strength = typeof _ === "function" ? _ : constant$4(+_), initialize(), force) : strength; + }; + + force.x = function(_) { + return arguments.length ? (x = typeof _ === "function" ? _ : constant$4(+_), initialize(), force) : x; + }; + + return force; +} + +function y$1(y) { + var strength = constant$4(0.1), + nodes, + strengths, + yz; + + if (typeof y !== "function") y = constant$4(y == null ? 0 : +y); + + function force(alpha) { + for (var i = 0, n = nodes.length, node; i < n; ++i) { + node = nodes[i], node.vy += (yz[i] - node.y) * strengths[i] * alpha; + } + } + + function initialize() { + if (!nodes) return; + var i, n = nodes.length; + strengths = new Array(n); + yz = new Array(n); + for (i = 0; i < n; ++i) { + strengths[i] = isNaN(yz[i] = +y(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes); + } + } + + force.initialize = function(_) { + nodes = _; + initialize(); + }; + + force.strength = function(_) { + return arguments.length ? (strength = typeof _ === "function" ? _ : constant$4(+_), initialize(), force) : strength; + }; + + force.y = function(_) { + return arguments.length ? (y = typeof _ === "function" ? _ : constant$4(+_), initialize(), force) : y; + }; + + return force; +} + +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 ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity + var i, 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 x + ""; + 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$6(x) { + return x; +} + +var map = Array.prototype.map, + prefixes = ["y","z","a","f","p","n","\xB5","m","","k","M","G","T","P","E","Z","Y"]; + +function formatLocale$1(locale) { + var group = locale.grouping === undefined || locale.thousands === undefined ? identity$6 : 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$6 : formatNumerals(map.call(locale.numerals, String)), + percent = locale.percent === undefined ? "%" : locale.percent + "", + minus = locale.minus === undefined ? "\u2212" : locale.minus + "", + nan = locale.nan === undefined ? "NaN" : locale.nan + ""; + + function newFormat(specifier) { + 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 = symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "", + suffix = symbol === "$" ? currencySuffix : /[%p]/.test(type) ? percent : ""; + + // 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" ? 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 f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)), + e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3, + k = Math.pow(10, -e), + prefix = prefixes[8 + e / 3]; + return function(value) { + return f(k * value) + prefix; + }; + } + + return { + format: newFormat, + formatPrefix: formatPrefix + }; +} + +var locale$1; +exports.format = void 0; +exports.formatPrefix = void 0; + +defaultLocale$1({ + thousands: ",", + grouping: [3], + currency: ["$", ""] +}); + +function defaultLocale$1(definition) { + locale$1 = formatLocale$1(definition); + exports.format = locale$1.format; + exports.formatPrefix = locale$1.formatPrefix; + return locale$1; +} + +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; +} + +var epsilon$1 = 1e-6; +var epsilon2 = 1e-12; +var pi$1 = Math.PI; +var halfPi$1 = pi$1 / 2; +var quarterPi = pi$1 / 4; +var tau$1 = pi$1 * 2; + +var degrees = 180 / pi$1; +var radians = pi$1 / 180; + +var abs$1 = Math.abs; +var atan = Math.atan; +var atan2$1 = Math.atan2; +var cos$1 = Math.cos; +var ceil = Math.ceil; +var exp = Math.exp; +var hypot = Math.hypot; +var log$1 = Math.log; +var pow$1 = Math.pow; +var sin$1 = Math.sin; +var sign$1 = Math.sign || function(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; }; +var sqrt$2 = Math.sqrt; +var tan = Math.tan; + +function acos$1(x) { + return x > 1 ? 0 : x < -1 ? pi$1 : Math.acos(x); +} + +function asin$1(x) { + return x > 1 ? halfPi$1 : x < -1 ? -halfPi$1 : Math.asin(x); +} + +function haversin(x) { + return (x = sin$1(x / 2)) * x; +} + +function noop$1() {} + +function streamGeometry(geometry, stream) { + if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) { + streamGeometryType[geometry.type](geometry, stream); + } +} + +var streamObjectType = { + Feature: function(object, stream) { + streamGeometry(object.geometry, stream); + }, + FeatureCollection: function(object, stream) { + var features = object.features, i = -1, n = features.length; + while (++i < n) streamGeometry(features[i].geometry, stream); + } +}; + +var streamGeometryType = { + Sphere: function(object, stream) { + stream.sphere(); + }, + Point: function(object, stream) { + object = object.coordinates; + stream.point(object[0], object[1], object[2]); + }, + MultiPoint: function(object, stream) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) object = coordinates[i], stream.point(object[0], object[1], object[2]); + }, + LineString: function(object, stream) { + streamLine(object.coordinates, stream, 0); + }, + MultiLineString: function(object, stream) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) streamLine(coordinates[i], stream, 0); + }, + Polygon: function(object, stream) { + streamPolygon(object.coordinates, stream); + }, + MultiPolygon: function(object, stream) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) streamPolygon(coordinates[i], stream); + }, + GeometryCollection: function(object, stream) { + var geometries = object.geometries, i = -1, n = geometries.length; + while (++i < n) streamGeometry(geometries[i], stream); + } +}; + +function streamLine(coordinates, stream, closed) { + var i = -1, n = coordinates.length - closed, coordinate; + stream.lineStart(); + while (++i < n) coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]); + stream.lineEnd(); +} + +function streamPolygon(coordinates, stream) { + var i = -1, n = coordinates.length; + stream.polygonStart(); + while (++i < n) streamLine(coordinates[i], stream, 1); + stream.polygonEnd(); +} + +function geoStream(object, stream) { + if (object && streamObjectType.hasOwnProperty(object.type)) { + streamObjectType[object.type](object, stream); + } else { + streamGeometry(object, stream); + } +} + +var areaRingSum$1 = new Adder(); + +// hello? + +var areaSum$1 = new Adder(), + lambda00$2, + phi00$2, + lambda0$2, + cosPhi0$1, + sinPhi0$1; + +var areaStream$1 = { + point: noop$1, + lineStart: noop$1, + lineEnd: noop$1, + polygonStart: function() { + areaRingSum$1 = new Adder(); + areaStream$1.lineStart = areaRingStart$1; + areaStream$1.lineEnd = areaRingEnd$1; + }, + polygonEnd: function() { + var areaRing = +areaRingSum$1; + areaSum$1.add(areaRing < 0 ? tau$1 + areaRing : areaRing); + this.lineStart = this.lineEnd = this.point = noop$1; + }, + sphere: function() { + areaSum$1.add(tau$1); + } +}; + +function areaRingStart$1() { + areaStream$1.point = areaPointFirst$1; +} + +function areaRingEnd$1() { + areaPoint$1(lambda00$2, phi00$2); +} + +function areaPointFirst$1(lambda, phi) { + areaStream$1.point = areaPoint$1; + lambda00$2 = lambda, phi00$2 = phi; + lambda *= radians, phi *= radians; + lambda0$2 = lambda, cosPhi0$1 = cos$1(phi = phi / 2 + quarterPi), sinPhi0$1 = sin$1(phi); +} + +function areaPoint$1(lambda, phi) { + lambda *= radians, phi *= radians; + phi = phi / 2 + quarterPi; // half the angular distance from south pole + + // Spherical excess E for a spherical triangle with vertices: south pole, + // previous point, current point. Uses a formula derived from Cagnoli’s + // theorem. See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2). + var dLambda = lambda - lambda0$2, + sdLambda = dLambda >= 0 ? 1 : -1, + adLambda = sdLambda * dLambda, + cosPhi = cos$1(phi), + sinPhi = sin$1(phi), + k = sinPhi0$1 * sinPhi, + u = cosPhi0$1 * cosPhi + k * cos$1(adLambda), + v = k * sdLambda * sin$1(adLambda); + areaRingSum$1.add(atan2$1(v, u)); + + // Advance the previous points. + lambda0$2 = lambda, cosPhi0$1 = cosPhi, sinPhi0$1 = sinPhi; +} + +function area$2(object) { + areaSum$1 = new Adder(); + geoStream(object, areaStream$1); + return areaSum$1 * 2; +} + +function spherical(cartesian) { + return [atan2$1(cartesian[1], cartesian[0]), asin$1(cartesian[2])]; +} + +function cartesian(spherical) { + var lambda = spherical[0], phi = spherical[1], cosPhi = cos$1(phi); + return [cosPhi * cos$1(lambda), cosPhi * sin$1(lambda), sin$1(phi)]; +} + +function cartesianDot(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +} + +function cartesianCross(a, b) { + return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]]; +} + +// TODO return a +function cartesianAddInPlace(a, b) { + a[0] += b[0], a[1] += b[1], a[2] += b[2]; +} + +function cartesianScale(vector, k) { + return [vector[0] * k, vector[1] * k, vector[2] * k]; +} + +// TODO return d +function cartesianNormalizeInPlace(d) { + var l = sqrt$2(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); + d[0] /= l, d[1] /= l, d[2] /= l; +} + +var lambda0$1, phi0, lambda1, phi1, // bounds + lambda2, // previous lambda-coordinate + lambda00$1, phi00$1, // first point + p0, // previous 3D point + deltaSum, + ranges, + range; + +var boundsStream$2 = { + point: boundsPoint$1, + lineStart: boundsLineStart, + lineEnd: boundsLineEnd, + polygonStart: function() { + boundsStream$2.point = boundsRingPoint; + boundsStream$2.lineStart = boundsRingStart; + boundsStream$2.lineEnd = boundsRingEnd; + deltaSum = new Adder(); + areaStream$1.polygonStart(); + }, + polygonEnd: function() { + areaStream$1.polygonEnd(); + boundsStream$2.point = boundsPoint$1; + boundsStream$2.lineStart = boundsLineStart; + boundsStream$2.lineEnd = boundsLineEnd; + if (areaRingSum$1 < 0) lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90); + else if (deltaSum > epsilon$1) phi1 = 90; + else if (deltaSum < -epsilon$1) phi0 = -90; + range[0] = lambda0$1, range[1] = lambda1; + }, + sphere: function() { + lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90); + } +}; + +function boundsPoint$1(lambda, phi) { + ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]); + if (phi < phi0) phi0 = phi; + if (phi > phi1) phi1 = phi; +} + +function linePoint(lambda, phi) { + var p = cartesian([lambda * radians, phi * radians]); + if (p0) { + var normal = cartesianCross(p0, p), + equatorial = [normal[1], -normal[0], 0], + inflection = cartesianCross(equatorial, normal); + cartesianNormalizeInPlace(inflection); + inflection = spherical(inflection); + var delta = lambda - lambda2, + sign = delta > 0 ? 1 : -1, + lambdai = inflection[0] * degrees * sign, + phii, + antimeridian = abs$1(delta) > 180; + if (antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) { + phii = inflection[1] * degrees; + if (phii > phi1) phi1 = phii; + } else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) { + phii = -inflection[1] * degrees; + if (phii < phi0) phi0 = phii; + } else { + if (phi < phi0) phi0 = phi; + if (phi > phi1) phi1 = phi; + } + if (antimeridian) { + if (lambda < lambda2) { + if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda; + } else { + if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda; + } + } else { + if (lambda1 >= lambda0$1) { + if (lambda < lambda0$1) lambda0$1 = lambda; + if (lambda > lambda1) lambda1 = lambda; + } else { + if (lambda > lambda2) { + if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda; + } else { + if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda; + } + } + } + } else { + ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]); + } + if (phi < phi0) phi0 = phi; + if (phi > phi1) phi1 = phi; + p0 = p, lambda2 = lambda; +} + +function boundsLineStart() { + boundsStream$2.point = linePoint; +} + +function boundsLineEnd() { + range[0] = lambda0$1, range[1] = lambda1; + boundsStream$2.point = boundsPoint$1; + p0 = null; +} + +function boundsRingPoint(lambda, phi) { + if (p0) { + var delta = lambda - lambda2; + deltaSum.add(abs$1(delta) > 180 ? delta + (delta > 0 ? 360 : -360) : delta); + } else { + lambda00$1 = lambda, phi00$1 = phi; + } + areaStream$1.point(lambda, phi); + linePoint(lambda, phi); +} + +function boundsRingStart() { + areaStream$1.lineStart(); +} + +function boundsRingEnd() { + boundsRingPoint(lambda00$1, phi00$1); + areaStream$1.lineEnd(); + if (abs$1(deltaSum) > epsilon$1) lambda0$1 = -(lambda1 = 180); + range[0] = lambda0$1, range[1] = lambda1; + p0 = null; +} + +// Finds the left-right distance between two longitudes. +// This is almost the same as (lambda1 - lambda0 + 360°) % 360°, except that we want +// the distance between ±180° to be 360°. +function angle(lambda0, lambda1) { + return (lambda1 -= lambda0) < 0 ? lambda1 + 360 : lambda1; +} + +function rangeCompare(a, b) { + return a[0] - b[0]; +} + +function rangeContains(range, x) { + return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x; +} + +function bounds(feature) { + var i, n, a, b, merged, deltaMax, delta; + + phi1 = lambda1 = -(lambda0$1 = phi0 = Infinity); + ranges = []; + geoStream(feature, boundsStream$2); + + // First, sort ranges by their minimum longitudes. + if (n = ranges.length) { + ranges.sort(rangeCompare); + + // Then, merge any ranges that overlap. + for (i = 1, a = ranges[0], merged = [a]; i < n; ++i) { + b = ranges[i]; + if (rangeContains(a, b[0]) || rangeContains(a, b[1])) { + if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1]; + if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0]; + } else { + merged.push(a = b); + } + } + + // Finally, find the largest gap between the merged ranges. + // The final bounding box will be the inverse of this gap. + for (deltaMax = -Infinity, n = merged.length - 1, i = 0, a = merged[n]; i <= n; a = b, ++i) { + b = merged[i]; + if ((delta = angle(a[1], b[0])) > deltaMax) deltaMax = delta, lambda0$1 = b[0], lambda1 = a[1]; + } + } + + ranges = range = null; + + return lambda0$1 === Infinity || phi0 === Infinity + ? [[NaN, NaN], [NaN, NaN]] + : [[lambda0$1, phi0], [lambda1, phi1]]; +} + +var W0, W1, + X0$1, Y0$1, Z0$1, + X1$1, Y1$1, Z1$1, + X2$1, Y2$1, Z2$1, + lambda00, phi00, // first point + x0$4, y0$4, z0; // previous point + +var centroidStream$1 = { + sphere: noop$1, + point: centroidPoint$1, + lineStart: centroidLineStart$1, + lineEnd: centroidLineEnd$1, + polygonStart: function() { + centroidStream$1.lineStart = centroidRingStart$1; + centroidStream$1.lineEnd = centroidRingEnd$1; + }, + polygonEnd: function() { + centroidStream$1.lineStart = centroidLineStart$1; + centroidStream$1.lineEnd = centroidLineEnd$1; + } +}; + +// Arithmetic mean of Cartesian vectors. +function centroidPoint$1(lambda, phi) { + lambda *= radians, phi *= radians; + var cosPhi = cos$1(phi); + centroidPointCartesian(cosPhi * cos$1(lambda), cosPhi * sin$1(lambda), sin$1(phi)); +} + +function centroidPointCartesian(x, y, z) { + ++W0; + X0$1 += (x - X0$1) / W0; + Y0$1 += (y - Y0$1) / W0; + Z0$1 += (z - Z0$1) / W0; +} + +function centroidLineStart$1() { + centroidStream$1.point = centroidLinePointFirst; +} + +function centroidLinePointFirst(lambda, phi) { + lambda *= radians, phi *= radians; + var cosPhi = cos$1(phi); + x0$4 = cosPhi * cos$1(lambda); + y0$4 = cosPhi * sin$1(lambda); + z0 = sin$1(phi); + centroidStream$1.point = centroidLinePoint; + centroidPointCartesian(x0$4, y0$4, z0); +} + +function centroidLinePoint(lambda, phi) { + lambda *= radians, phi *= radians; + var cosPhi = cos$1(phi), + x = cosPhi * cos$1(lambda), + y = cosPhi * sin$1(lambda), + z = sin$1(phi), + w = atan2$1(sqrt$2((w = y0$4 * z - z0 * y) * w + (w = z0 * x - x0$4 * z) * w + (w = x0$4 * y - y0$4 * x) * w), x0$4 * x + y0$4 * y + z0 * z); + W1 += w; + X1$1 += w * (x0$4 + (x0$4 = x)); + Y1$1 += w * (y0$4 + (y0$4 = y)); + Z1$1 += w * (z0 + (z0 = z)); + centroidPointCartesian(x0$4, y0$4, z0); +} + +function centroidLineEnd$1() { + centroidStream$1.point = centroidPoint$1; +} + +// See J. E. Brock, The Inertia Tensor for a Spherical Triangle, +// J. Applied Mechanics 42, 239 (1975). +function centroidRingStart$1() { + centroidStream$1.point = centroidRingPointFirst; +} + +function centroidRingEnd$1() { + centroidRingPoint(lambda00, phi00); + centroidStream$1.point = centroidPoint$1; +} + +function centroidRingPointFirst(lambda, phi) { + lambda00 = lambda, phi00 = phi; + lambda *= radians, phi *= radians; + centroidStream$1.point = centroidRingPoint; + var cosPhi = cos$1(phi); + x0$4 = cosPhi * cos$1(lambda); + y0$4 = cosPhi * sin$1(lambda); + z0 = sin$1(phi); + centroidPointCartesian(x0$4, y0$4, z0); +} + +function centroidRingPoint(lambda, phi) { + lambda *= radians, phi *= radians; + var cosPhi = cos$1(phi), + x = cosPhi * cos$1(lambda), + y = cosPhi * sin$1(lambda), + z = sin$1(phi), + cx = y0$4 * z - z0 * y, + cy = z0 * x - x0$4 * z, + cz = x0$4 * y - y0$4 * x, + m = hypot(cx, cy, cz), + w = asin$1(m), // line weight = angle + v = m && -w / m; // area weight multiplier + X2$1.add(v * cx); + Y2$1.add(v * cy); + Z2$1.add(v * cz); + W1 += w; + X1$1 += w * (x0$4 + (x0$4 = x)); + Y1$1 += w * (y0$4 + (y0$4 = y)); + Z1$1 += w * (z0 + (z0 = z)); + centroidPointCartesian(x0$4, y0$4, z0); +} + +function centroid$1(object) { + W0 = W1 = + X0$1 = Y0$1 = Z0$1 = + X1$1 = Y1$1 = Z1$1 = 0; + X2$1 = new Adder(); + Y2$1 = new Adder(); + Z2$1 = new Adder(); + geoStream(object, centroidStream$1); + + var x = +X2$1, + y = +Y2$1, + z = +Z2$1, + m = hypot(x, y, z); + + // If the area-weighted ccentroid is undefined, fall back to length-weighted ccentroid. + if (m < epsilon2) { + x = X1$1, y = Y1$1, z = Z1$1; + // If the feature has zero length, fall back to arithmetic mean of point vectors. + if (W1 < epsilon$1) x = X0$1, y = Y0$1, z = Z0$1; + m = hypot(x, y, z); + // If the feature still has an undefined ccentroid, then return. + if (m < epsilon2) return [NaN, NaN]; + } + + return [atan2$1(y, x) * degrees, asin$1(z / m) * degrees]; +} + +function constant$3(x) { + return function() { + return x; + }; +} + +function compose(a, b) { + + function compose(x, y) { + return x = a(x, y), b(x[0], x[1]); + } + + if (a.invert && b.invert) compose.invert = function(x, y) { + return x = b.invert(x, y), x && a.invert(x[0], x[1]); + }; + + return compose; +} + +function rotationIdentity(lambda, phi) { + return [abs$1(lambda) > pi$1 ? lambda + Math.round(-lambda / tau$1) * tau$1 : lambda, phi]; +} + +rotationIdentity.invert = rotationIdentity; + +function rotateRadians(deltaLambda, deltaPhi, deltaGamma) { + return (deltaLambda %= tau$1) ? (deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma)) + : rotationLambda(deltaLambda)) + : (deltaPhi || deltaGamma ? rotationPhiGamma(deltaPhi, deltaGamma) + : rotationIdentity); +} + +function forwardRotationLambda(deltaLambda) { + return function(lambda, phi) { + return lambda += deltaLambda, [lambda > pi$1 ? lambda - tau$1 : lambda < -pi$1 ? lambda + tau$1 : lambda, phi]; + }; +} + +function rotationLambda(deltaLambda) { + var rotation = forwardRotationLambda(deltaLambda); + rotation.invert = forwardRotationLambda(-deltaLambda); + return rotation; +} + +function rotationPhiGamma(deltaPhi, deltaGamma) { + var cosDeltaPhi = cos$1(deltaPhi), + sinDeltaPhi = sin$1(deltaPhi), + cosDeltaGamma = cos$1(deltaGamma), + sinDeltaGamma = sin$1(deltaGamma); + + function rotation(lambda, phi) { + var cosPhi = cos$1(phi), + x = cos$1(lambda) * cosPhi, + y = sin$1(lambda) * cosPhi, + z = sin$1(phi), + k = z * cosDeltaPhi + x * sinDeltaPhi; + return [ + atan2$1(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi), + asin$1(k * cosDeltaGamma + y * sinDeltaGamma) + ]; + } + + rotation.invert = function(lambda, phi) { + var cosPhi = cos$1(phi), + x = cos$1(lambda) * cosPhi, + y = sin$1(lambda) * cosPhi, + z = sin$1(phi), + k = z * cosDeltaGamma - y * sinDeltaGamma; + return [ + atan2$1(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi), + asin$1(k * cosDeltaPhi - x * sinDeltaPhi) + ]; + }; + + return rotation; +} + +function rotation(rotate) { + rotate = rotateRadians(rotate[0] * radians, rotate[1] * radians, rotate.length > 2 ? rotate[2] * radians : 0); + + function forward(coordinates) { + coordinates = rotate(coordinates[0] * radians, coordinates[1] * radians); + return coordinates[0] *= degrees, coordinates[1] *= degrees, coordinates; + } + + forward.invert = function(coordinates) { + coordinates = rotate.invert(coordinates[0] * radians, coordinates[1] * radians); + return coordinates[0] *= degrees, coordinates[1] *= degrees, coordinates; + }; + + return forward; +} + +// Generates a circle centered at [0°, 0°], with a given radius and precision. +function circleStream(stream, radius, delta, direction, t0, t1) { + if (!delta) return; + var cosRadius = cos$1(radius), + sinRadius = sin$1(radius), + step = direction * delta; + if (t0 == null) { + t0 = radius + direction * tau$1; + t1 = radius - step / 2; + } else { + t0 = circleRadius(cosRadius, t0); + t1 = circleRadius(cosRadius, t1); + if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau$1; + } + for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) { + point = spherical([cosRadius, -sinRadius * cos$1(t), -sinRadius * sin$1(t)]); + stream.point(point[0], point[1]); + } +} + +// Returns the signed angle of a cartesian point relative to [cosRadius, 0, 0]. +function circleRadius(cosRadius, point) { + point = cartesian(point), point[0] -= cosRadius; + cartesianNormalizeInPlace(point); + var radius = acos$1(-point[1]); + return ((-point[2] < 0 ? -radius : radius) + tau$1 - epsilon$1) % tau$1; +} + +function circle$2() { + var center = constant$3([0, 0]), + radius = constant$3(90), + precision = constant$3(6), + ring, + rotate, + stream = {point: point}; + + function point(x, y) { + ring.push(x = rotate(x, y)); + x[0] *= degrees, x[1] *= degrees; + } + + function circle() { + var c = center.apply(this, arguments), + r = radius.apply(this, arguments) * radians, + p = precision.apply(this, arguments) * radians; + ring = []; + rotate = rotateRadians(-c[0] * radians, -c[1] * radians, 0).invert; + circleStream(stream, r, p, 1); + c = {type: "Polygon", coordinates: [ring]}; + ring = rotate = null; + return c; + } + + circle.center = function(_) { + return arguments.length ? (center = typeof _ === "function" ? _ : constant$3([+_[0], +_[1]]), circle) : center; + }; + + circle.radius = function(_) { + return arguments.length ? (radius = typeof _ === "function" ? _ : constant$3(+_), circle) : radius; + }; + + circle.precision = function(_) { + return arguments.length ? (precision = typeof _ === "function" ? _ : constant$3(+_), circle) : precision; + }; + + return circle; +} + +function clipBuffer() { + var lines = [], + line; + return { + point: function(x, y, m) { + line.push([x, y, m]); + }, + lineStart: function() { + lines.push(line = []); + }, + lineEnd: noop$1, + rejoin: function() { + if (lines.length > 1) lines.push(lines.pop().concat(lines.shift())); + }, + result: function() { + var result = lines; + lines = []; + line = null; + return result; + } + }; +} + +function pointEqual(a, b) { + return abs$1(a[0] - b[0]) < epsilon$1 && abs$1(a[1] - b[1]) < epsilon$1; +} + +function Intersection(point, points, other, entry) { + this.x = point; + this.z = points; + this.o = other; // another intersection + this.e = entry; // is an entry? + this.v = false; // visited + this.n = this.p = null; // next & previous +} + +// A generalized polygon clipping algorithm: given a polygon that has been cut +// into its visible line segments, and rejoins the segments by interpolating +// along the clip edge. +function clipRejoin(segments, compareIntersection, startInside, interpolate, stream) { + var subject = [], + clip = [], + i, + n; + + segments.forEach(function(segment) { + if ((n = segment.length - 1) <= 0) return; + var n, p0 = segment[0], p1 = segment[n], x; + + if (pointEqual(p0, p1)) { + if (!p0[2] && !p1[2]) { + stream.lineStart(); + for (i = 0; i < n; ++i) stream.point((p0 = segment[i])[0], p0[1]); + stream.lineEnd(); + return; + } + // handle degenerate cases by moving the point + p1[0] += 2 * epsilon$1; + } + + subject.push(x = new Intersection(p0, segment, null, true)); + clip.push(x.o = new Intersection(p0, null, x, false)); + subject.push(x = new Intersection(p1, segment, null, false)); + clip.push(x.o = new Intersection(p1, null, x, true)); + }); + + if (!subject.length) return; + + clip.sort(compareIntersection); + link$1(subject); + link$1(clip); + + for (i = 0, n = clip.length; i < n; ++i) { + clip[i].e = startInside = !startInside; + } + + var start = subject[0], + points, + point; + + while (1) { + // Find first unvisited intersection. + var current = start, + isSubject = true; + while (current.v) if ((current = current.n) === start) return; + points = current.z; + stream.lineStart(); + do { + current.v = current.o.v = true; + if (current.e) { + if (isSubject) { + for (i = 0, n = points.length; i < n; ++i) stream.point((point = points[i])[0], point[1]); + } else { + interpolate(current.x, current.n.x, 1, stream); + } + current = current.n; + } else { + if (isSubject) { + points = current.p.z; + for (i = points.length - 1; i >= 0; --i) stream.point((point = points[i])[0], point[1]); + } else { + interpolate(current.x, current.p.x, -1, stream); + } + current = current.p; + } + current = current.o; + points = current.z; + isSubject = !isSubject; + } while (!current.v); + stream.lineEnd(); + } +} + +function link$1(array) { + if (!(n = array.length)) return; + var n, + i = 0, + a = array[0], + b; + while (++i < n) { + a.n = b = array[i]; + b.p = a; + a = b; + } + a.n = b = array[0]; + b.p = a; +} + +function longitude(point) { + return abs$1(point[0]) <= pi$1 ? point[0] : sign$1(point[0]) * ((abs$1(point[0]) + pi$1) % tau$1 - pi$1); +} + +function polygonContains(polygon, point) { + var lambda = longitude(point), + phi = point[1], + sinPhi = sin$1(phi), + normal = [sin$1(lambda), -cos$1(lambda), 0], + angle = 0, + winding = 0; + + var sum = new Adder(); + + if (sinPhi === 1) phi = halfPi$1 + epsilon$1; + else if (sinPhi === -1) phi = -halfPi$1 - epsilon$1; + + for (var i = 0, n = polygon.length; i < n; ++i) { + if (!(m = (ring = polygon[i]).length)) continue; + var ring, + m, + point0 = ring[m - 1], + lambda0 = longitude(point0), + phi0 = point0[1] / 2 + quarterPi, + sinPhi0 = sin$1(phi0), + cosPhi0 = cos$1(phi0); + + for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) { + var point1 = ring[j], + lambda1 = longitude(point1), + phi1 = point1[1] / 2 + quarterPi, + sinPhi1 = sin$1(phi1), + cosPhi1 = cos$1(phi1), + delta = lambda1 - lambda0, + sign = delta >= 0 ? 1 : -1, + absDelta = sign * delta, + antimeridian = absDelta > pi$1, + k = sinPhi0 * sinPhi1; + + sum.add(atan2$1(k * sign * sin$1(absDelta), cosPhi0 * cosPhi1 + k * cos$1(absDelta))); + angle += antimeridian ? delta + sign * tau$1 : delta; + + // Are the longitudes either side of the point’s meridian (lambda), + // and are the latitudes smaller than the parallel (phi)? + if (antimeridian ^ lambda0 >= lambda ^ lambda1 >= lambda) { + var arc = cartesianCross(cartesian(point0), cartesian(point1)); + cartesianNormalizeInPlace(arc); + var intersection = cartesianCross(normal, arc); + cartesianNormalizeInPlace(intersection); + var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin$1(intersection[2]); + if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) { + winding += antimeridian ^ delta >= 0 ? 1 : -1; + } + } + } + } + + // First, determine whether the South pole is inside or outside: + // + // It is inside if: + // * the polygon winds around it in a clockwise direction. + // * the polygon does not (cumulatively) wind around it, but has a negative + // (counter-clockwise) area. + // + // Second, count the (signed) number of times a segment crosses a lambda + // from the point to the South pole. If it is zero, then the point is the + // same side as the South pole. + + return (angle < -epsilon$1 || angle < epsilon$1 && sum < -epsilon2) ^ (winding & 1); +} + +function clip(pointVisible, clipLine, interpolate, start) { + return function(sink) { + var line = clipLine(sink), + ringBuffer = clipBuffer(), + ringSink = clipLine(ringBuffer), + polygonStarted = false, + polygon, + segments, + ring; + + var clip = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + clip.point = pointRing; + clip.lineStart = ringStart; + clip.lineEnd = ringEnd; + segments = []; + polygon = []; + }, + polygonEnd: function() { + clip.point = point; + clip.lineStart = lineStart; + clip.lineEnd = lineEnd; + segments = merge(segments); + var startInside = polygonContains(polygon, start); + if (segments.length) { + if (!polygonStarted) sink.polygonStart(), polygonStarted = true; + clipRejoin(segments, compareIntersection, startInside, interpolate, sink); + } else if (startInside) { + if (!polygonStarted) sink.polygonStart(), polygonStarted = true; + sink.lineStart(); + interpolate(null, null, 1, sink); + sink.lineEnd(); + } + if (polygonStarted) sink.polygonEnd(), polygonStarted = false; + segments = polygon = null; + }, + sphere: function() { + sink.polygonStart(); + sink.lineStart(); + interpolate(null, null, 1, sink); + sink.lineEnd(); + sink.polygonEnd(); + } + }; + + function point(lambda, phi) { + if (pointVisible(lambda, phi)) sink.point(lambda, phi); + } + + function pointLine(lambda, phi) { + line.point(lambda, phi); + } + + function lineStart() { + clip.point = pointLine; + line.lineStart(); + } + + function lineEnd() { + clip.point = point; + line.lineEnd(); + } + + function pointRing(lambda, phi) { + ring.push([lambda, phi]); + ringSink.point(lambda, phi); + } + + function ringStart() { + ringSink.lineStart(); + ring = []; + } + + function ringEnd() { + pointRing(ring[0][0], ring[0][1]); + ringSink.lineEnd(); + + var clean = ringSink.clean(), + ringSegments = ringBuffer.result(), + i, n = ringSegments.length, m, + segment, + point; + + ring.pop(); + polygon.push(ring); + ring = null; + + if (!n) return; + + // No intersections. + if (clean & 1) { + segment = ringSegments[0]; + if ((m = segment.length - 1) > 0) { + if (!polygonStarted) sink.polygonStart(), polygonStarted = true; + sink.lineStart(); + for (i = 0; i < m; ++i) sink.point((point = segment[i])[0], point[1]); + sink.lineEnd(); + } + return; + } + + // Rejoin connected segments. + // TODO reuse ringBuffer.rejoin()? + if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift())); + + segments.push(ringSegments.filter(validSegment)); + } + + return clip; + }; +} + +function validSegment(segment) { + return segment.length > 1; +} + +// Intersections are sorted along the clip edge. For both antimeridian cutting +// and circle clipping, the same comparison is used. +function compareIntersection(a, b) { + return ((a = a.x)[0] < 0 ? a[1] - halfPi$1 - epsilon$1 : halfPi$1 - a[1]) + - ((b = b.x)[0] < 0 ? b[1] - halfPi$1 - epsilon$1 : halfPi$1 - b[1]); +} + +var clipAntimeridian = clip( + function() { return true; }, + clipAntimeridianLine, + clipAntimeridianInterpolate, + [-pi$1, -halfPi$1] +); + +// Takes a line and cuts into visible segments. Return values: 0 - there were +// intersections or the line was empty; 1 - no intersections; 2 - there were +// intersections, and the first and last segments should be rejoined. +function clipAntimeridianLine(stream) { + var lambda0 = NaN, + phi0 = NaN, + sign0 = NaN, + clean; // no intersections + + return { + lineStart: function() { + stream.lineStart(); + clean = 1; + }, + point: function(lambda1, phi1) { + var sign1 = lambda1 > 0 ? pi$1 : -pi$1, + delta = abs$1(lambda1 - lambda0); + if (abs$1(delta - pi$1) < epsilon$1) { // line crosses a pole + stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi$1 : -halfPi$1); + stream.point(sign0, phi0); + stream.lineEnd(); + stream.lineStart(); + stream.point(sign1, phi0); + stream.point(lambda1, phi0); + clean = 0; + } else if (sign0 !== sign1 && delta >= pi$1) { // line crosses antimeridian + if (abs$1(lambda0 - sign0) < epsilon$1) lambda0 -= sign0 * epsilon$1; // handle degeneracies + if (abs$1(lambda1 - sign1) < epsilon$1) lambda1 -= sign1 * epsilon$1; + phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1); + stream.point(sign0, phi0); + stream.lineEnd(); + stream.lineStart(); + stream.point(sign1, phi0); + clean = 0; + } + stream.point(lambda0 = lambda1, phi0 = phi1); + sign0 = sign1; + }, + lineEnd: function() { + stream.lineEnd(); + lambda0 = phi0 = NaN; + }, + clean: function() { + return 2 - clean; // if intersections, rejoin first and last segments + } + }; +} + +function clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1) { + var cosPhi0, + cosPhi1, + sinLambda0Lambda1 = sin$1(lambda0 - lambda1); + return abs$1(sinLambda0Lambda1) > epsilon$1 + ? atan((sin$1(phi0) * (cosPhi1 = cos$1(phi1)) * sin$1(lambda1) + - sin$1(phi1) * (cosPhi0 = cos$1(phi0)) * sin$1(lambda0)) + / (cosPhi0 * cosPhi1 * sinLambda0Lambda1)) + : (phi0 + phi1) / 2; +} + +function clipAntimeridianInterpolate(from, to, direction, stream) { + var phi; + if (from == null) { + phi = direction * halfPi$1; + stream.point(-pi$1, phi); + stream.point(0, phi); + stream.point(pi$1, phi); + stream.point(pi$1, 0); + stream.point(pi$1, -phi); + stream.point(0, -phi); + stream.point(-pi$1, -phi); + stream.point(-pi$1, 0); + stream.point(-pi$1, phi); + } else if (abs$1(from[0] - to[0]) > epsilon$1) { + var lambda = from[0] < to[0] ? pi$1 : -pi$1; + phi = direction * lambda / 2; + stream.point(-lambda, phi); + stream.point(0, phi); + stream.point(lambda, phi); + } else { + stream.point(to[0], to[1]); + } +} + +function clipCircle(radius) { + var cr = cos$1(radius), + delta = 6 * radians, + smallRadius = cr > 0, + notHemisphere = abs$1(cr) > epsilon$1; // TODO optimise for this common case + + function interpolate(from, to, direction, stream) { + circleStream(stream, radius, delta, direction, from, to); + } + + function visible(lambda, phi) { + return cos$1(lambda) * cos$1(phi) > cr; + } + + // Takes a line and cuts into visible segments. Return values used for polygon + // clipping: 0 - there were intersections or the line was empty; 1 - no + // intersections 2 - there were intersections, and the first and last segments + // should be rejoined. + function clipLine(stream) { + var point0, // previous point + c0, // code for previous point + v0, // visibility of previous point + v00, // visibility of first point + clean; // no intersections + return { + lineStart: function() { + v00 = v0 = false; + clean = 1; + }, + point: function(lambda, phi) { + var point1 = [lambda, phi], + point2, + v = visible(lambda, phi), + c = smallRadius + ? v ? 0 : code(lambda, phi) + : v ? code(lambda + (lambda < 0 ? pi$1 : -pi$1), phi) : 0; + if (!point0 && (v00 = v0 = v)) stream.lineStart(); + if (v !== v0) { + point2 = intersect(point0, point1); + if (!point2 || pointEqual(point0, point2) || pointEqual(point1, point2)) + point1[2] = 1; + } + if (v !== v0) { + clean = 0; + if (v) { + // outside going in + stream.lineStart(); + point2 = intersect(point1, point0); + stream.point(point2[0], point2[1]); + } else { + // inside going out + point2 = intersect(point0, point1); + stream.point(point2[0], point2[1], 2); + stream.lineEnd(); + } + point0 = point2; + } else if (notHemisphere && point0 && smallRadius ^ v) { + var t; + // If the codes for two points are different, or are both zero, + // and there this segment intersects with the small circle. + if (!(c & c0) && (t = intersect(point1, point0, true))) { + clean = 0; + if (smallRadius) { + stream.lineStart(); + stream.point(t[0][0], t[0][1]); + stream.point(t[1][0], t[1][1]); + stream.lineEnd(); + } else { + stream.point(t[1][0], t[1][1]); + stream.lineEnd(); + stream.lineStart(); + stream.point(t[0][0], t[0][1], 3); + } + } + } + if (v && (!point0 || !pointEqual(point0, point1))) { + stream.point(point1[0], point1[1]); + } + point0 = point1, v0 = v, c0 = c; + }, + lineEnd: function() { + if (v0) stream.lineEnd(); + point0 = null; + }, + // Rejoin first and last segments if there were intersections and the first + // and last points were visible. + clean: function() { + return clean | ((v00 && v0) << 1); + } + }; + } + + // Intersects the great circle between a and b with the clip circle. + function intersect(a, b, two) { + var pa = cartesian(a), + pb = cartesian(b); + + // We have two planes, n1.p = d1 and n2.p = d2. + // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2). + var n1 = [1, 0, 0], // normal + n2 = cartesianCross(pa, pb), + n2n2 = cartesianDot(n2, n2), + n1n2 = n2[0], // cartesianDot(n1, n2), + determinant = n2n2 - n1n2 * n1n2; + + // Two polar points. + if (!determinant) return !two && a; + + var c1 = cr * n2n2 / determinant, + c2 = -cr * n1n2 / determinant, + n1xn2 = cartesianCross(n1, n2), + A = cartesianScale(n1, c1), + B = cartesianScale(n2, c2); + cartesianAddInPlace(A, B); + + // Solve |p(t)|^2 = 1. + var u = n1xn2, + w = cartesianDot(A, u), + uu = cartesianDot(u, u), + t2 = w * w - uu * (cartesianDot(A, A) - 1); + + if (t2 < 0) return; + + var t = sqrt$2(t2), + q = cartesianScale(u, (-w - t) / uu); + cartesianAddInPlace(q, A); + q = spherical(q); + + if (!two) return q; + + // Two intersection points. + var lambda0 = a[0], + lambda1 = b[0], + phi0 = a[1], + phi1 = b[1], + z; + + if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z; + + var delta = lambda1 - lambda0, + polar = abs$1(delta - pi$1) < epsilon$1, + meridian = polar || delta < epsilon$1; + + if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z; + + // Check that the first point is between a and b. + if (meridian + ? polar + ? phi0 + phi1 > 0 ^ q[1] < (abs$1(q[0] - lambda0) < epsilon$1 ? phi0 : phi1) + : phi0 <= q[1] && q[1] <= phi1 + : delta > pi$1 ^ (lambda0 <= q[0] && q[0] <= lambda1)) { + var q1 = cartesianScale(u, (-w + t) / uu); + cartesianAddInPlace(q1, A); + return [q, spherical(q1)]; + } + } + + // Generates a 4-bit vector representing the location of a point relative to + // the small circle's bounding box. + function code(lambda, phi) { + var r = smallRadius ? radius : pi$1 - radius, + code = 0; + if (lambda < -r) code |= 1; // left + else if (lambda > r) code |= 2; // right + if (phi < -r) code |= 4; // below + else if (phi > r) code |= 8; // above + return code; + } + + return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi$1, radius - pi$1]); +} + +function clipLine(a, b, x0, y0, x1, y1) { + var ax = a[0], + ay = a[1], + bx = b[0], + by = b[1], + t0 = 0, + t1 = 1, + dx = bx - ax, + dy = by - ay, + r; + + r = x0 - ax; + if (!dx && r > 0) return; + r /= dx; + if (dx < 0) { + if (r < t0) return; + if (r < t1) t1 = r; + } else if (dx > 0) { + if (r > t1) return; + if (r > t0) t0 = r; + } + + r = x1 - ax; + if (!dx && r < 0) return; + r /= dx; + if (dx < 0) { + if (r > t1) return; + if (r > t0) t0 = r; + } else if (dx > 0) { + if (r < t0) return; + if (r < t1) t1 = r; + } + + r = y0 - ay; + if (!dy && r > 0) return; + r /= dy; + if (dy < 0) { + if (r < t0) return; + if (r < t1) t1 = r; + } else if (dy > 0) { + if (r > t1) return; + if (r > t0) t0 = r; + } + + r = y1 - ay; + if (!dy && r < 0) return; + r /= dy; + if (dy < 0) { + if (r > t1) return; + if (r > t0) t0 = r; + } else if (dy > 0) { + if (r < t0) return; + if (r < t1) t1 = r; + } + + if (t0 > 0) a[0] = ax + t0 * dx, a[1] = ay + t0 * dy; + if (t1 < 1) b[0] = ax + t1 * dx, b[1] = ay + t1 * dy; + return true; +} + +var clipMax = 1e9, clipMin = -clipMax; + +// TODO Use d3-polygon’s polygonContains here for the ring check? +// TODO Eliminate duplicate buffering in clipBuffer and polygon.push? + +function clipRectangle(x0, y0, x1, y1) { + + function visible(x, y) { + return x0 <= x && x <= x1 && y0 <= y && y <= y1; + } + + function interpolate(from, to, direction, stream) { + var a = 0, a1 = 0; + if (from == null + || (a = corner(from, direction)) !== (a1 = corner(to, direction)) + || comparePoint(from, to) < 0 ^ direction > 0) { + do stream.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0); + while ((a = (a + direction + 4) % 4) !== a1); + } else { + stream.point(to[0], to[1]); + } + } + + function corner(p, direction) { + return abs$1(p[0] - x0) < epsilon$1 ? direction > 0 ? 0 : 3 + : abs$1(p[0] - x1) < epsilon$1 ? direction > 0 ? 2 : 1 + : abs$1(p[1] - y0) < epsilon$1 ? direction > 0 ? 1 : 0 + : direction > 0 ? 3 : 2; // abs(p[1] - y1) < epsilon + } + + function compareIntersection(a, b) { + return comparePoint(a.x, b.x); + } + + function comparePoint(a, b) { + var ca = corner(a, 1), + cb = corner(b, 1); + return ca !== cb ? ca - cb + : ca === 0 ? b[1] - a[1] + : ca === 1 ? a[0] - b[0] + : ca === 2 ? a[1] - b[1] + : b[0] - a[0]; + } + + return function(stream) { + var activeStream = stream, + bufferStream = clipBuffer(), + segments, + polygon, + ring, + x__, y__, v__, // first point + x_, y_, v_, // previous point + first, + clean; + + var clipStream = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: polygonStart, + polygonEnd: polygonEnd + }; + + function point(x, y) { + if (visible(x, y)) activeStream.point(x, y); + } + + function polygonInside() { + var winding = 0; + + for (var i = 0, n = polygon.length; i < n; ++i) { + for (var ring = polygon[i], j = 1, m = ring.length, point = ring[0], a0, a1, b0 = point[0], b1 = point[1]; j < m; ++j) { + a0 = b0, a1 = b1, point = ring[j], b0 = point[0], b1 = point[1]; + if (a1 <= y1) { if (b1 > y1 && (b0 - a0) * (y1 - a1) > (b1 - a1) * (x0 - a0)) ++winding; } + else { if (b1 <= y1 && (b0 - a0) * (y1 - a1) < (b1 - a1) * (x0 - a0)) --winding; } + } + } + + return winding; + } + + // Buffer geometry within a polygon and then clip it en masse. + function polygonStart() { + activeStream = bufferStream, segments = [], polygon = [], clean = true; + } + + function polygonEnd() { + var startInside = polygonInside(), + cleanInside = clean && startInside, + visible = (segments = merge(segments)).length; + if (cleanInside || visible) { + stream.polygonStart(); + if (cleanInside) { + stream.lineStart(); + interpolate(null, null, 1, stream); + stream.lineEnd(); + } + if (visible) { + clipRejoin(segments, compareIntersection, startInside, interpolate, stream); + } + stream.polygonEnd(); + } + activeStream = stream, segments = polygon = ring = null; + } + + function lineStart() { + clipStream.point = linePoint; + if (polygon) polygon.push(ring = []); + first = true; + v_ = false; + x_ = y_ = NaN; + } + + // TODO rather than special-case polygons, simply handle them separately. + // Ideally, coincident intersection points should be jittered to avoid + // clipping issues. + function lineEnd() { + if (segments) { + linePoint(x__, y__); + if (v__ && v_) bufferStream.rejoin(); + segments.push(bufferStream.result()); + } + clipStream.point = point; + if (v_) activeStream.lineEnd(); + } + + function linePoint(x, y) { + var v = visible(x, y); + if (polygon) ring.push([x, y]); + if (first) { + x__ = x, y__ = y, v__ = v; + first = false; + if (v) { + activeStream.lineStart(); + activeStream.point(x, y); + } + } else { + if (v && v_) activeStream.point(x, y); + else { + var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))], + b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))]; + if (clipLine(a, b, x0, y0, x1, y1)) { + if (!v_) { + activeStream.lineStart(); + activeStream.point(a[0], a[1]); + } + activeStream.point(b[0], b[1]); + if (!v) activeStream.lineEnd(); + clean = false; + } else if (v) { + activeStream.lineStart(); + activeStream.point(x, y); + clean = false; + } + } + } + x_ = x, y_ = y, v_ = v; + } + + return clipStream; + }; +} + +function extent() { + var x0 = 0, + y0 = 0, + x1 = 960, + y1 = 500, + cache, + cacheStream, + clip; + + return clip = { + stream: function(stream) { + return cache && cacheStream === stream ? cache : cache = clipRectangle(x0, y0, x1, y1)(cacheStream = stream); + }, + extent: function(_) { + return arguments.length ? (x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1], cache = cacheStream = null, clip) : [[x0, y0], [x1, y1]]; + } + }; +} + +var lengthSum$1, + lambda0, + sinPhi0, + cosPhi0; + +var lengthStream$1 = { + sphere: noop$1, + point: noop$1, + lineStart: lengthLineStart, + lineEnd: noop$1, + polygonStart: noop$1, + polygonEnd: noop$1 +}; + +function lengthLineStart() { + lengthStream$1.point = lengthPointFirst$1; + lengthStream$1.lineEnd = lengthLineEnd; +} + +function lengthLineEnd() { + lengthStream$1.point = lengthStream$1.lineEnd = noop$1; +} + +function lengthPointFirst$1(lambda, phi) { + lambda *= radians, phi *= radians; + lambda0 = lambda, sinPhi0 = sin$1(phi), cosPhi0 = cos$1(phi); + lengthStream$1.point = lengthPoint$1; +} + +function lengthPoint$1(lambda, phi) { + lambda *= radians, phi *= radians; + var sinPhi = sin$1(phi), + cosPhi = cos$1(phi), + delta = abs$1(lambda - lambda0), + cosDelta = cos$1(delta), + sinDelta = sin$1(delta), + x = cosPhi * sinDelta, + y = cosPhi0 * sinPhi - sinPhi0 * cosPhi * cosDelta, + z = sinPhi0 * sinPhi + cosPhi0 * cosPhi * cosDelta; + lengthSum$1.add(atan2$1(sqrt$2(x * x + y * y), z)); + lambda0 = lambda, sinPhi0 = sinPhi, cosPhi0 = cosPhi; +} + +function length$1(object) { + lengthSum$1 = new Adder(); + geoStream(object, lengthStream$1); + return +lengthSum$1; +} + +var coordinates = [null, null], + object = {type: "LineString", coordinates: coordinates}; + +function distance(a, b) { + coordinates[0] = a; + coordinates[1] = b; + return length$1(object); +} + +var containsObjectType = { + Feature: function(object, point) { + return containsGeometry(object.geometry, point); + }, + FeatureCollection: function(object, point) { + var features = object.features, i = -1, n = features.length; + while (++i < n) if (containsGeometry(features[i].geometry, point)) return true; + return false; + } +}; + +var containsGeometryType = { + Sphere: function() { + return true; + }, + Point: function(object, point) { + return containsPoint(object.coordinates, point); + }, + MultiPoint: function(object, point) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) if (containsPoint(coordinates[i], point)) return true; + return false; + }, + LineString: function(object, point) { + return containsLine(object.coordinates, point); + }, + MultiLineString: function(object, point) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) if (containsLine(coordinates[i], point)) return true; + return false; + }, + Polygon: function(object, point) { + return containsPolygon(object.coordinates, point); + }, + MultiPolygon: function(object, point) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) if (containsPolygon(coordinates[i], point)) return true; + return false; + }, + GeometryCollection: function(object, point) { + var geometries = object.geometries, i = -1, n = geometries.length; + while (++i < n) if (containsGeometry(geometries[i], point)) return true; + return false; + } +}; + +function containsGeometry(geometry, point) { + return geometry && containsGeometryType.hasOwnProperty(geometry.type) + ? containsGeometryType[geometry.type](geometry, point) + : false; +} + +function containsPoint(coordinates, point) { + return distance(coordinates, point) === 0; +} + +function containsLine(coordinates, point) { + var ao, bo, ab; + for (var i = 0, n = coordinates.length; i < n; i++) { + bo = distance(coordinates[i], point); + if (bo === 0) return true; + if (i > 0) { + ab = distance(coordinates[i], coordinates[i - 1]); + if ( + ab > 0 && + ao <= ab && + bo <= ab && + (ao + bo - ab) * (1 - Math.pow((ao - bo) / ab, 2)) < epsilon2 * ab + ) + return true; + } + ao = bo; + } + return false; +} + +function containsPolygon(coordinates, point) { + return !!polygonContains(coordinates.map(ringRadians), pointRadians(point)); +} + +function ringRadians(ring) { + return ring = ring.map(pointRadians), ring.pop(), ring; +} + +function pointRadians(point) { + return [point[0] * radians, point[1] * radians]; +} + +function contains$1(object, point) { + return (object && containsObjectType.hasOwnProperty(object.type) + ? containsObjectType[object.type] + : containsGeometry)(object, point); +} + +function graticuleX(y0, y1, dy) { + var y = range$2(y0, y1 - epsilon$1, dy).concat(y1); + return function(x) { return y.map(function(y) { return [x, y]; }); }; +} + +function graticuleY(x0, x1, dx) { + var x = range$2(x0, x1 - epsilon$1, dx).concat(x1); + return function(y) { return x.map(function(x) { return [x, y]; }); }; +} + +function graticule() { + var x1, x0, X1, X0, + y1, y0, Y1, Y0, + dx = 10, dy = dx, DX = 90, DY = 360, + x, y, X, Y, + precision = 2.5; + + function graticule() { + return {type: "MultiLineString", coordinates: lines()}; + } + + function lines() { + return range$2(ceil(X0 / DX) * DX, X1, DX).map(X) + .concat(range$2(ceil(Y0 / DY) * DY, Y1, DY).map(Y)) + .concat(range$2(ceil(x0 / dx) * dx, x1, dx).filter(function(x) { return abs$1(x % DX) > epsilon$1; }).map(x)) + .concat(range$2(ceil(y0 / dy) * dy, y1, dy).filter(function(y) { return abs$1(y % DY) > epsilon$1; }).map(y)); + } + + graticule.lines = function() { + return lines().map(function(coordinates) { return {type: "LineString", coordinates: coordinates}; }); + }; + + graticule.outline = function() { + return { + type: "Polygon", + coordinates: [ + X(X0).concat( + Y(Y1).slice(1), + X(X1).reverse().slice(1), + Y(Y0).reverse().slice(1)) + ] + }; + }; + + graticule.extent = function(_) { + if (!arguments.length) return graticule.extentMinor(); + return graticule.extentMajor(_).extentMinor(_); + }; + + graticule.extentMajor = function(_) { + if (!arguments.length) return [[X0, Y0], [X1, Y1]]; + X0 = +_[0][0], X1 = +_[1][0]; + Y0 = +_[0][1], Y1 = +_[1][1]; + if (X0 > X1) _ = X0, X0 = X1, X1 = _; + if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _; + return graticule.precision(precision); + }; + + graticule.extentMinor = function(_) { + if (!arguments.length) return [[x0, y0], [x1, y1]]; + x0 = +_[0][0], x1 = +_[1][0]; + y0 = +_[0][1], y1 = +_[1][1]; + if (x0 > x1) _ = x0, x0 = x1, x1 = _; + if (y0 > y1) _ = y0, y0 = y1, y1 = _; + return graticule.precision(precision); + }; + + graticule.step = function(_) { + if (!arguments.length) return graticule.stepMinor(); + return graticule.stepMajor(_).stepMinor(_); + }; + + graticule.stepMajor = function(_) { + if (!arguments.length) return [DX, DY]; + DX = +_[0], DY = +_[1]; + return graticule; + }; + + graticule.stepMinor = function(_) { + if (!arguments.length) return [dx, dy]; + dx = +_[0], dy = +_[1]; + return graticule; + }; + + graticule.precision = function(_) { + if (!arguments.length) return precision; + precision = +_; + x = graticuleX(y0, y1, 90); + y = graticuleY(x0, x1, precision); + X = graticuleX(Y0, Y1, 90); + Y = graticuleY(X0, X1, precision); + return graticule; + }; + + return graticule + .extentMajor([[-180, -90 + epsilon$1], [180, 90 - epsilon$1]]) + .extentMinor([[-180, -80 - epsilon$1], [180, 80 + epsilon$1]]); +} + +function graticule10() { + return graticule()(); +} + +function interpolate(a, b) { + var x0 = a[0] * radians, + y0 = a[1] * radians, + x1 = b[0] * radians, + y1 = b[1] * radians, + cy0 = cos$1(y0), + sy0 = sin$1(y0), + cy1 = cos$1(y1), + sy1 = sin$1(y1), + kx0 = cy0 * cos$1(x0), + ky0 = cy0 * sin$1(x0), + kx1 = cy1 * cos$1(x1), + ky1 = cy1 * sin$1(x1), + d = 2 * asin$1(sqrt$2(haversin(y1 - y0) + cy0 * cy1 * haversin(x1 - x0))), + k = sin$1(d); + + var interpolate = d ? function(t) { + var B = sin$1(t *= d) / k, + A = sin$1(d - t) / k, + x = A * kx0 + B * kx1, + y = A * ky0 + B * ky1, + z = A * sy0 + B * sy1; + return [ + atan2$1(y, x) * degrees, + atan2$1(z, sqrt$2(x * x + y * y)) * degrees + ]; + } : function() { + return [x0 * degrees, y0 * degrees]; + }; + + interpolate.distance = d; + + return interpolate; +} + +var identity$5 = x => x; + +var areaSum = new Adder(), + areaRingSum = new Adder(), + x00$2, + y00$2, + x0$3, + y0$3; + +var areaStream = { + point: noop$1, + lineStart: noop$1, + lineEnd: noop$1, + polygonStart: function() { + areaStream.lineStart = areaRingStart; + areaStream.lineEnd = areaRingEnd; + }, + polygonEnd: function() { + areaStream.lineStart = areaStream.lineEnd = areaStream.point = noop$1; + areaSum.add(abs$1(areaRingSum)); + areaRingSum = new Adder(); + }, + result: function() { + var area = areaSum / 2; + areaSum = new Adder(); + return area; + } +}; + +function areaRingStart() { + areaStream.point = areaPointFirst; +} + +function areaPointFirst(x, y) { + areaStream.point = areaPoint; + x00$2 = x0$3 = x, y00$2 = y0$3 = y; +} + +function areaPoint(x, y) { + areaRingSum.add(y0$3 * x - x0$3 * y); + x0$3 = x, y0$3 = y; +} + +function areaRingEnd() { + areaPoint(x00$2, y00$2); +} + +var pathArea = areaStream; + +var x0$2 = Infinity, + y0$2 = x0$2, + x1 = -x0$2, + y1 = x1; + +var boundsStream = { + point: boundsPoint, + lineStart: noop$1, + lineEnd: noop$1, + polygonStart: noop$1, + polygonEnd: noop$1, + result: function() { + var bounds = [[x0$2, y0$2], [x1, y1]]; + x1 = y1 = -(y0$2 = x0$2 = Infinity); + return bounds; + } +}; + +function boundsPoint(x, y) { + if (x < x0$2) x0$2 = x; + if (x > x1) x1 = x; + if (y < y0$2) y0$2 = y; + if (y > y1) y1 = y; +} + +var boundsStream$1 = boundsStream; + +// TODO Enforce positive area for exterior, negative area for interior? + +var X0 = 0, + Y0 = 0, + Z0 = 0, + X1 = 0, + Y1 = 0, + Z1 = 0, + X2 = 0, + Y2 = 0, + Z2 = 0, + x00$1, + y00$1, + x0$1, + y0$1; + +var centroidStream = { + point: centroidPoint, + lineStart: centroidLineStart, + lineEnd: centroidLineEnd, + polygonStart: function() { + centroidStream.lineStart = centroidRingStart; + centroidStream.lineEnd = centroidRingEnd; + }, + polygonEnd: function() { + centroidStream.point = centroidPoint; + centroidStream.lineStart = centroidLineStart; + centroidStream.lineEnd = centroidLineEnd; + }, + result: function() { + var centroid = Z2 ? [X2 / Z2, Y2 / Z2] + : Z1 ? [X1 / Z1, Y1 / Z1] + : Z0 ? [X0 / Z0, Y0 / Z0] + : [NaN, NaN]; + X0 = Y0 = Z0 = + X1 = Y1 = Z1 = + X2 = Y2 = Z2 = 0; + return centroid; + } +}; + +function centroidPoint(x, y) { + X0 += x; + Y0 += y; + ++Z0; +} + +function centroidLineStart() { + centroidStream.point = centroidPointFirstLine; +} + +function centroidPointFirstLine(x, y) { + centroidStream.point = centroidPointLine; + centroidPoint(x0$1 = x, y0$1 = y); +} + +function centroidPointLine(x, y) { + var dx = x - x0$1, dy = y - y0$1, z = sqrt$2(dx * dx + dy * dy); + X1 += z * (x0$1 + x) / 2; + Y1 += z * (y0$1 + y) / 2; + Z1 += z; + centroidPoint(x0$1 = x, y0$1 = y); +} + +function centroidLineEnd() { + centroidStream.point = centroidPoint; +} + +function centroidRingStart() { + centroidStream.point = centroidPointFirstRing; +} + +function centroidRingEnd() { + centroidPointRing(x00$1, y00$1); +} + +function centroidPointFirstRing(x, y) { + centroidStream.point = centroidPointRing; + centroidPoint(x00$1 = x0$1 = x, y00$1 = y0$1 = y); +} + +function centroidPointRing(x, y) { + var dx = x - x0$1, + dy = y - y0$1, + z = sqrt$2(dx * dx + dy * dy); + + X1 += z * (x0$1 + x) / 2; + Y1 += z * (y0$1 + y) / 2; + Z1 += z; + + z = y0$1 * x - x0$1 * y; + X2 += z * (x0$1 + x); + Y2 += z * (y0$1 + y); + Z2 += z * 3; + centroidPoint(x0$1 = x, y0$1 = y); +} + +var pathCentroid = centroidStream; + +function PathContext(context) { + this._context = context; +} + +PathContext.prototype = { + _radius: 4.5, + pointRadius: function(_) { + return this._radius = _, this; + }, + polygonStart: function() { + this._line = 0; + }, + polygonEnd: function() { + this._line = NaN; + }, + lineStart: function() { + this._point = 0; + }, + lineEnd: function() { + if (this._line === 0) this._context.closePath(); + this._point = NaN; + }, + point: function(x, y) { + switch (this._point) { + case 0: { + this._context.moveTo(x, y); + this._point = 1; + break; + } + case 1: { + this._context.lineTo(x, y); + break; + } + default: { + this._context.moveTo(x + this._radius, y); + this._context.arc(x, y, this._radius, 0, tau$1); + break; + } + } + }, + result: noop$1 +}; + +var lengthSum = new Adder(), + lengthRing, + x00, + y00, + x0, + y0; + +var lengthStream = { + point: noop$1, + lineStart: function() { + lengthStream.point = lengthPointFirst; + }, + lineEnd: function() { + if (lengthRing) lengthPoint(x00, y00); + lengthStream.point = noop$1; + }, + polygonStart: function() { + lengthRing = true; + }, + polygonEnd: function() { + lengthRing = null; + }, + result: function() { + var length = +lengthSum; + lengthSum = new Adder(); + return length; + } +}; + +function lengthPointFirst(x, y) { + lengthStream.point = lengthPoint; + x00 = x0 = x, y00 = y0 = y; +} + +function lengthPoint(x, y) { + x0 -= x, y0 -= y; + lengthSum.add(sqrt$2(x0 * x0 + y0 * y0)); + x0 = x, y0 = y; +} + +var pathMeasure = lengthStream; + +function PathString() { + this._string = []; +} + +PathString.prototype = { + _radius: 4.5, + _circle: circle$1(4.5), + pointRadius: function(_) { + if ((_ = +_) !== this._radius) this._radius = _, this._circle = null; + return this; + }, + polygonStart: function() { + this._line = 0; + }, + polygonEnd: function() { + this._line = NaN; + }, + lineStart: function() { + this._point = 0; + }, + lineEnd: function() { + if (this._line === 0) this._string.push("Z"); + this._point = NaN; + }, + point: function(x, y) { + switch (this._point) { + case 0: { + this._string.push("M", x, ",", y); + this._point = 1; + break; + } + case 1: { + this._string.push("L", x, ",", y); + break; + } + default: { + if (this._circle == null) this._circle = circle$1(this._radius); + this._string.push("M", x, ",", y, this._circle); + break; + } + } + }, + result: function() { + if (this._string.length) { + var result = this._string.join(""); + this._string = []; + return result; + } else { + return null; + } + } +}; + +function circle$1(radius) { + return "m0," + radius + + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + + "z"; +} + +function index$2(projection, context) { + var pointRadius = 4.5, + projectionStream, + contextStream; + + function path(object) { + if (object) { + if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments)); + geoStream(object, projectionStream(contextStream)); + } + return contextStream.result(); + } + + path.area = function(object) { + geoStream(object, projectionStream(pathArea)); + return pathArea.result(); + }; + + path.measure = function(object) { + geoStream(object, projectionStream(pathMeasure)); + return pathMeasure.result(); + }; + + path.bounds = function(object) { + geoStream(object, projectionStream(boundsStream$1)); + return boundsStream$1.result(); + }; + + path.centroid = function(object) { + geoStream(object, projectionStream(pathCentroid)); + return pathCentroid.result(); + }; + + path.projection = function(_) { + return arguments.length ? (projectionStream = _ == null ? (projection = null, identity$5) : (projection = _).stream, path) : projection; + }; + + path.context = function(_) { + if (!arguments.length) return context; + contextStream = _ == null ? (context = null, new PathString) : new PathContext(context = _); + if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius); + return path; + }; + + path.pointRadius = function(_) { + if (!arguments.length) return pointRadius; + pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_); + return path; + }; + + return path.projection(projection).context(context); +} + +function transform$1(methods) { + return { + stream: transformer$3(methods) + }; +} + +function transformer$3(methods) { + return function(stream) { + var s = new TransformStream; + for (var key in methods) s[key] = methods[key]; + s.stream = stream; + return s; + }; +} + +function TransformStream() {} + +TransformStream.prototype = { + constructor: TransformStream, + point: function(x, y) { this.stream.point(x, y); }, + sphere: function() { this.stream.sphere(); }, + lineStart: function() { this.stream.lineStart(); }, + lineEnd: function() { this.stream.lineEnd(); }, + polygonStart: function() { this.stream.polygonStart(); }, + polygonEnd: function() { this.stream.polygonEnd(); } +}; + +function fit(projection, fitBounds, object) { + var clip = projection.clipExtent && projection.clipExtent(); + projection.scale(150).translate([0, 0]); + if (clip != null) projection.clipExtent(null); + geoStream(object, projection.stream(boundsStream$1)); + fitBounds(boundsStream$1.result()); + if (clip != null) projection.clipExtent(clip); + return projection; +} + +function fitExtent(projection, extent, object) { + return fit(projection, function(b) { + var w = extent[1][0] - extent[0][0], + h = extent[1][1] - extent[0][1], + k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1])), + x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2, + y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2; + projection.scale(150 * k).translate([x, y]); + }, object); +} + +function fitSize(projection, size, object) { + return fitExtent(projection, [[0, 0], size], object); +} + +function fitWidth(projection, width, object) { + return fit(projection, function(b) { + var w = +width, + k = w / (b[1][0] - b[0][0]), + x = (w - k * (b[1][0] + b[0][0])) / 2, + y = -k * b[0][1]; + projection.scale(150 * k).translate([x, y]); + }, object); +} + +function fitHeight(projection, height, object) { + return fit(projection, function(b) { + var h = +height, + k = h / (b[1][1] - b[0][1]), + x = -k * b[0][0], + y = (h - k * (b[1][1] + b[0][1])) / 2; + projection.scale(150 * k).translate([x, y]); + }, object); +} + +var maxDepth = 16, // maximum depth of subdivision + cosMinDistance = cos$1(30 * radians); // cos(minimum angular distance) + +function resample(project, delta2) { + return +delta2 ? resample$1(project, delta2) : resampleNone(project); +} + +function resampleNone(project) { + return transformer$3({ + point: function(x, y) { + x = project(x, y); + this.stream.point(x[0], x[1]); + } + }); +} + +function resample$1(project, delta2) { + + function resampleLineTo(x0, y0, lambda0, a0, b0, c0, x1, y1, lambda1, a1, b1, c1, depth, stream) { + var dx = x1 - x0, + dy = y1 - y0, + d2 = dx * dx + dy * dy; + if (d2 > 4 * delta2 && depth--) { + var a = a0 + a1, + b = b0 + b1, + c = c0 + c1, + m = sqrt$2(a * a + b * b + c * c), + phi2 = asin$1(c /= m), + lambda2 = abs$1(abs$1(c) - 1) < epsilon$1 || abs$1(lambda0 - lambda1) < epsilon$1 ? (lambda0 + lambda1) / 2 : atan2$1(b, a), + p = project(lambda2, phi2), + x2 = p[0], + y2 = p[1], + dx2 = x2 - x0, + dy2 = y2 - y0, + dz = dy * dx2 - dx * dy2; + if (dz * dz / d2 > delta2 // perpendicular projected distance + || abs$1((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end + || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { // angular distance + resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream); + stream.point(x2, y2); + resampleLineTo(x2, y2, lambda2, a, b, c, x1, y1, lambda1, a1, b1, c1, depth, stream); + } + } + } + return function(stream) { + var lambda00, x00, y00, a00, b00, c00, // first point + lambda0, x0, y0, a0, b0, c0; // previous point + + var resampleStream = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { stream.polygonStart(); resampleStream.lineStart = ringStart; }, + polygonEnd: function() { stream.polygonEnd(); resampleStream.lineStart = lineStart; } + }; + + function point(x, y) { + x = project(x, y); + stream.point(x[0], x[1]); + } + + function lineStart() { + x0 = NaN; + resampleStream.point = linePoint; + stream.lineStart(); + } + + function linePoint(lambda, phi) { + var c = cartesian([lambda, phi]), p = project(lambda, phi); + resampleLineTo(x0, y0, lambda0, a0, b0, c0, x0 = p[0], y0 = p[1], lambda0 = lambda, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream); + stream.point(x0, y0); + } + + function lineEnd() { + resampleStream.point = point; + stream.lineEnd(); + } + + function ringStart() { + lineStart(); + resampleStream.point = ringPoint; + resampleStream.lineEnd = ringEnd; + } + + function ringPoint(lambda, phi) { + linePoint(lambda00 = lambda, phi), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0; + resampleStream.point = linePoint; + } + + function ringEnd() { + resampleLineTo(x0, y0, lambda0, a0, b0, c0, x00, y00, lambda00, a00, b00, c00, maxDepth, stream); + resampleStream.lineEnd = lineEnd; + lineEnd(); + } + + return resampleStream; + }; +} + +var transformRadians = transformer$3({ + point: function(x, y) { + this.stream.point(x * radians, y * radians); + } +}); + +function transformRotate(rotate) { + return transformer$3({ + point: function(x, y) { + var r = rotate(x, y); + return this.stream.point(r[0], r[1]); + } + }); +} + +function scaleTranslate(k, dx, dy, sx, sy) { + function transform(x, y) { + x *= sx; y *= sy; + return [dx + k * x, dy - k * y]; + } + transform.invert = function(x, y) { + return [(x - dx) / k * sx, (dy - y) / k * sy]; + }; + return transform; +} + +function scaleTranslateRotate(k, dx, dy, sx, sy, alpha) { + if (!alpha) return scaleTranslate(k, dx, dy, sx, sy); + var cosAlpha = cos$1(alpha), + sinAlpha = sin$1(alpha), + a = cosAlpha * k, + b = sinAlpha * k, + ai = cosAlpha / k, + bi = sinAlpha / k, + ci = (sinAlpha * dy - cosAlpha * dx) / k, + fi = (sinAlpha * dx + cosAlpha * dy) / k; + function transform(x, y) { + x *= sx; y *= sy; + return [a * x - b * y + dx, dy - b * x - a * y]; + } + transform.invert = function(x, y) { + return [sx * (ai * x - bi * y + ci), sy * (fi - bi * x - ai * y)]; + }; + return transform; +} + +function projection(project) { + return projectionMutator(function() { return project; })(); +} + +function projectionMutator(projectAt) { + var project, + k = 150, // scale + x = 480, y = 250, // translate + lambda = 0, phi = 0, // center + deltaLambda = 0, deltaPhi = 0, deltaGamma = 0, rotate, // pre-rotate + alpha = 0, // post-rotate angle + sx = 1, // reflectX + sy = 1, // reflectX + theta = null, preclip = clipAntimeridian, // pre-clip angle + x0 = null, y0, x1, y1, postclip = identity$5, // post-clip extent + delta2 = 0.5, // precision + projectResample, + projectTransform, + projectRotateTransform, + cache, + cacheStream; + + function projection(point) { + return projectRotateTransform(point[0] * radians, point[1] * radians); + } + + function invert(point) { + point = projectRotateTransform.invert(point[0], point[1]); + return point && [point[0] * degrees, point[1] * degrees]; + } + + projection.stream = function(stream) { + return cache && cacheStream === stream ? cache : cache = transformRadians(transformRotate(rotate)(preclip(projectResample(postclip(cacheStream = stream))))); + }; + + projection.preclip = function(_) { + return arguments.length ? (preclip = _, theta = undefined, reset()) : preclip; + }; + + projection.postclip = function(_) { + return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip; + }; + + projection.clipAngle = function(_) { + return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees; + }; + + projection.clipExtent = function(_) { + return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$5) : clipRectangle(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]]; + }; + + projection.scale = function(_) { + return arguments.length ? (k = +_, recenter()) : k; + }; + + projection.translate = function(_) { + return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y]; + }; + + projection.center = function(_) { + return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees, phi * degrees]; + }; + + projection.rotate = function(_) { + return arguments.length ? (deltaLambda = _[0] % 360 * radians, deltaPhi = _[1] % 360 * radians, deltaGamma = _.length > 2 ? _[2] % 360 * radians : 0, recenter()) : [deltaLambda * degrees, deltaPhi * degrees, deltaGamma * degrees]; + }; + + projection.angle = function(_) { + return arguments.length ? (alpha = _ % 360 * radians, recenter()) : alpha * degrees; + }; + + projection.reflectX = function(_) { + return arguments.length ? (sx = _ ? -1 : 1, recenter()) : sx < 0; + }; + + projection.reflectY = function(_) { + return arguments.length ? (sy = _ ? -1 : 1, recenter()) : sy < 0; + }; + + projection.precision = function(_) { + return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt$2(delta2); + }; + + projection.fitExtent = function(extent, object) { + return fitExtent(projection, extent, object); + }; + + projection.fitSize = function(size, object) { + return fitSize(projection, size, object); + }; + + projection.fitWidth = function(width, object) { + return fitWidth(projection, width, object); + }; + + projection.fitHeight = function(height, object) { + return fitHeight(projection, height, object); + }; + + function recenter() { + var center = scaleTranslateRotate(k, 0, 0, sx, sy, alpha).apply(null, project(lambda, phi)), + transform = scaleTranslateRotate(k, x - center[0], y - center[1], sx, sy, alpha); + rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma); + projectTransform = compose(project, transform); + projectRotateTransform = compose(rotate, projectTransform); + projectResample = resample(projectTransform, delta2); + return reset(); + } + + function reset() { + cache = cacheStream = null; + return projection; + } + + return function() { + project = projectAt.apply(this, arguments); + projection.invert = project.invert && invert; + return recenter(); + }; +} + +function conicProjection(projectAt) { + var phi0 = 0, + phi1 = pi$1 / 3, + m = projectionMutator(projectAt), + p = m(phi0, phi1); + + p.parallels = function(_) { + return arguments.length ? m(phi0 = _[0] * radians, phi1 = _[1] * radians) : [phi0 * degrees, phi1 * degrees]; + }; + + return p; +} + +function cylindricalEqualAreaRaw(phi0) { + var cosPhi0 = cos$1(phi0); + + function forward(lambda, phi) { + return [lambda * cosPhi0, sin$1(phi) / cosPhi0]; + } + + forward.invert = function(x, y) { + return [x / cosPhi0, asin$1(y * cosPhi0)]; + }; + + return forward; +} + +function conicEqualAreaRaw(y0, y1) { + var sy0 = sin$1(y0), n = (sy0 + sin$1(y1)) / 2; + + // Are the parallels symmetrical around the Equator? + if (abs$1(n) < epsilon$1) return cylindricalEqualAreaRaw(y0); + + var c = 1 + sy0 * (2 * n - sy0), r0 = sqrt$2(c) / n; + + function project(x, y) { + var r = sqrt$2(c - 2 * n * sin$1(y)) / n; + return [r * sin$1(x *= n), r0 - r * cos$1(x)]; + } + + project.invert = function(x, y) { + var r0y = r0 - y, + l = atan2$1(x, abs$1(r0y)) * sign$1(r0y); + if (r0y * n < 0) + l -= pi$1 * sign$1(x) * sign$1(r0y); + return [l / n, asin$1((c - (x * x + r0y * r0y) * n * n) / (2 * n))]; + }; + + return project; +} + +function conicEqualArea() { + return conicProjection(conicEqualAreaRaw) + .scale(155.424) + .center([0, 33.6442]); +} + +function albers() { + return conicEqualArea() + .parallels([29.5, 45.5]) + .scale(1070) + .translate([480, 250]) + .rotate([96, 0]) + .center([-0.6, 38.7]); +} + +// The projections must have mutually exclusive clip regions on the sphere, +// as this will avoid emitting interleaving lines and polygons. +function multiplex(streams) { + var n = streams.length; + return { + point: function(x, y) { var i = -1; while (++i < n) streams[i].point(x, y); }, + sphere: function() { var i = -1; while (++i < n) streams[i].sphere(); }, + lineStart: function() { var i = -1; while (++i < n) streams[i].lineStart(); }, + lineEnd: function() { var i = -1; while (++i < n) streams[i].lineEnd(); }, + polygonStart: function() { var i = -1; while (++i < n) streams[i].polygonStart(); }, + polygonEnd: function() { var i = -1; while (++i < n) streams[i].polygonEnd(); } + }; +} + +// A composite projection for the United States, configured by default for +// 960×500. The projection also works quite well at 960×600 if you change the +// scale to 1285 and adjust the translate accordingly. The set of standard +// parallels for each region comes from USGS, which is published here: +// http://egsc.usgs.gov/isb/pubs/MapProjections/projections.html#albers +function albersUsa() { + var cache, + cacheStream, + lower48 = albers(), lower48Point, + alaska = conicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]), alaskaPoint, // EPSG:3338 + hawaii = conicEqualArea().rotate([157, 0]).center([-3, 19.9]).parallels([8, 18]), hawaiiPoint, // ESRI:102007 + point, pointStream = {point: function(x, y) { point = [x, y]; }}; + + function albersUsa(coordinates) { + var x = coordinates[0], y = coordinates[1]; + return point = null, + (lower48Point.point(x, y), point) + || (alaskaPoint.point(x, y), point) + || (hawaiiPoint.point(x, y), point); + } + + albersUsa.invert = function(coordinates) { + var k = lower48.scale(), + t = lower48.translate(), + x = (coordinates[0] - t[0]) / k, + y = (coordinates[1] - t[1]) / k; + return (y >= 0.120 && y < 0.234 && x >= -0.425 && x < -0.214 ? alaska + : y >= 0.166 && y < 0.234 && x >= -0.214 && x < -0.115 ? hawaii + : lower48).invert(coordinates); + }; + + albersUsa.stream = function(stream) { + return cache && cacheStream === stream ? cache : cache = multiplex([lower48.stream(cacheStream = stream), alaska.stream(stream), hawaii.stream(stream)]); + }; + + albersUsa.precision = function(_) { + if (!arguments.length) return lower48.precision(); + lower48.precision(_), alaska.precision(_), hawaii.precision(_); + return reset(); + }; + + albersUsa.scale = function(_) { + if (!arguments.length) return lower48.scale(); + lower48.scale(_), alaska.scale(_ * 0.35), hawaii.scale(_); + return albersUsa.translate(lower48.translate()); + }; + + albersUsa.translate = function(_) { + if (!arguments.length) return lower48.translate(); + var k = lower48.scale(), x = +_[0], y = +_[1]; + + lower48Point = lower48 + .translate(_) + .clipExtent([[x - 0.455 * k, y - 0.238 * k], [x + 0.455 * k, y + 0.238 * k]]) + .stream(pointStream); + + alaskaPoint = alaska + .translate([x - 0.307 * k, y + 0.201 * k]) + .clipExtent([[x - 0.425 * k + epsilon$1, y + 0.120 * k + epsilon$1], [x - 0.214 * k - epsilon$1, y + 0.234 * k - epsilon$1]]) + .stream(pointStream); + + hawaiiPoint = hawaii + .translate([x - 0.205 * k, y + 0.212 * k]) + .clipExtent([[x - 0.214 * k + epsilon$1, y + 0.166 * k + epsilon$1], [x - 0.115 * k - epsilon$1, y + 0.234 * k - epsilon$1]]) + .stream(pointStream); + + return reset(); + }; + + albersUsa.fitExtent = function(extent, object) { + return fitExtent(albersUsa, extent, object); + }; + + albersUsa.fitSize = function(size, object) { + return fitSize(albersUsa, size, object); + }; + + albersUsa.fitWidth = function(width, object) { + return fitWidth(albersUsa, width, object); + }; + + albersUsa.fitHeight = function(height, object) { + return fitHeight(albersUsa, height, object); + }; + + function reset() { + cache = cacheStream = null; + return albersUsa; + } + + return albersUsa.scale(1070); +} + +function azimuthalRaw(scale) { + return function(x, y) { + var cx = cos$1(x), + cy = cos$1(y), + k = scale(cx * cy); + if (k === Infinity) return [2, 0]; + return [ + k * cy * sin$1(x), + k * sin$1(y) + ]; + } +} + +function azimuthalInvert(angle) { + return function(x, y) { + var z = sqrt$2(x * x + y * y), + c = angle(z), + sc = sin$1(c), + cc = cos$1(c); + return [ + atan2$1(x * sc, z * cc), + asin$1(z && y * sc / z) + ]; + } +} + +var azimuthalEqualAreaRaw = azimuthalRaw(function(cxcy) { + return sqrt$2(2 / (1 + cxcy)); +}); + +azimuthalEqualAreaRaw.invert = azimuthalInvert(function(z) { + return 2 * asin$1(z / 2); +}); + +function azimuthalEqualArea() { + return projection(azimuthalEqualAreaRaw) + .scale(124.75) + .clipAngle(180 - 1e-3); +} + +var azimuthalEquidistantRaw = azimuthalRaw(function(c) { + return (c = acos$1(c)) && c / sin$1(c); +}); + +azimuthalEquidistantRaw.invert = azimuthalInvert(function(z) { + return z; +}); + +function azimuthalEquidistant() { + return projection(azimuthalEquidistantRaw) + .scale(79.4188) + .clipAngle(180 - 1e-3); +} + +function mercatorRaw(lambda, phi) { + return [lambda, log$1(tan((halfPi$1 + phi) / 2))]; +} + +mercatorRaw.invert = function(x, y) { + return [x, 2 * atan(exp(y)) - halfPi$1]; +}; + +function mercator() { + return mercatorProjection(mercatorRaw) + .scale(961 / tau$1); +} + +function mercatorProjection(project) { + var m = projection(project), + center = m.center, + scale = m.scale, + translate = m.translate, + clipExtent = m.clipExtent, + x0 = null, y0, x1, y1; // clip extent + + m.scale = function(_) { + return arguments.length ? (scale(_), reclip()) : scale(); + }; + + m.translate = function(_) { + return arguments.length ? (translate(_), reclip()) : translate(); + }; + + m.center = function(_) { + return arguments.length ? (center(_), reclip()) : center(); + }; + + m.clipExtent = function(_) { + return arguments.length ? ((_ == null ? x0 = y0 = x1 = y1 = null : (x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1])), reclip()) : x0 == null ? null : [[x0, y0], [x1, y1]]; + }; + + function reclip() { + var k = pi$1 * scale(), + t = m(rotation(m.rotate()).invert([0, 0])); + return clipExtent(x0 == null + ? [[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]] : project === mercatorRaw + ? [[Math.max(t[0] - k, x0), y0], [Math.min(t[0] + k, x1), y1]] + : [[x0, Math.max(t[1] - k, y0)], [x1, Math.min(t[1] + k, y1)]]); + } + + return reclip(); +} + +function tany(y) { + return tan((halfPi$1 + y) / 2); +} + +function conicConformalRaw(y0, y1) { + var cy0 = cos$1(y0), + n = y0 === y1 ? sin$1(y0) : log$1(cy0 / cos$1(y1)) / log$1(tany(y1) / tany(y0)), + f = cy0 * pow$1(tany(y0), n) / n; + + if (!n) return mercatorRaw; + + function project(x, y) { + if (f > 0) { if (y < -halfPi$1 + epsilon$1) y = -halfPi$1 + epsilon$1; } + else { if (y > halfPi$1 - epsilon$1) y = halfPi$1 - epsilon$1; } + var r = f / pow$1(tany(y), n); + return [r * sin$1(n * x), f - r * cos$1(n * x)]; + } + + project.invert = function(x, y) { + var fy = f - y, r = sign$1(n) * sqrt$2(x * x + fy * fy), + l = atan2$1(x, abs$1(fy)) * sign$1(fy); + if (fy * n < 0) + l -= pi$1 * sign$1(x) * sign$1(fy); + return [l / n, 2 * atan(pow$1(f / r, 1 / n)) - halfPi$1]; + }; + + return project; +} + +function conicConformal() { + return conicProjection(conicConformalRaw) + .scale(109.5) + .parallels([30, 30]); +} + +function equirectangularRaw(lambda, phi) { + return [lambda, phi]; +} + +equirectangularRaw.invert = equirectangularRaw; + +function equirectangular() { + return projection(equirectangularRaw) + .scale(152.63); +} + +function conicEquidistantRaw(y0, y1) { + var cy0 = cos$1(y0), + n = y0 === y1 ? sin$1(y0) : (cy0 - cos$1(y1)) / (y1 - y0), + g = cy0 / n + y0; + + if (abs$1(n) < epsilon$1) return equirectangularRaw; + + function project(x, y) { + var gy = g - y, nx = n * x; + return [gy * sin$1(nx), g - gy * cos$1(nx)]; + } + + project.invert = function(x, y) { + var gy = g - y, + l = atan2$1(x, abs$1(gy)) * sign$1(gy); + if (gy * n < 0) + l -= pi$1 * sign$1(x) * sign$1(gy); + return [l / n, g - sign$1(n) * sqrt$2(x * x + gy * gy)]; + }; + + return project; +} + +function conicEquidistant() { + return conicProjection(conicEquidistantRaw) + .scale(131.154) + .center([0, 13.9389]); +} + +var A1 = 1.340264, + A2 = -0.081106, + A3 = 0.000893, + A4 = 0.003796, + M = sqrt$2(3) / 2, + iterations = 12; + +function equalEarthRaw(lambda, phi) { + var l = asin$1(M * sin$1(phi)), l2 = l * l, l6 = l2 * l2 * l2; + return [ + lambda * cos$1(l) / (M * (A1 + 3 * A2 * l2 + l6 * (7 * A3 + 9 * A4 * l2))), + l * (A1 + A2 * l2 + l6 * (A3 + A4 * l2)) + ]; +} + +equalEarthRaw.invert = function(x, y) { + var l = y, l2 = l * l, l6 = l2 * l2 * l2; + for (var i = 0, delta, fy, fpy; i < iterations; ++i) { + fy = l * (A1 + A2 * l2 + l6 * (A3 + A4 * l2)) - y; + fpy = A1 + 3 * A2 * l2 + l6 * (7 * A3 + 9 * A4 * l2); + l -= delta = fy / fpy, l2 = l * l, l6 = l2 * l2 * l2; + if (abs$1(delta) < epsilon2) break; + } + return [ + M * x * (A1 + 3 * A2 * l2 + l6 * (7 * A3 + 9 * A4 * l2)) / cos$1(l), + asin$1(sin$1(l) / M) + ]; +}; + +function equalEarth() { + return projection(equalEarthRaw) + .scale(177.158); +} + +function gnomonicRaw(x, y) { + var cy = cos$1(y), k = cos$1(x) * cy; + return [cy * sin$1(x) / k, sin$1(y) / k]; +} + +gnomonicRaw.invert = azimuthalInvert(atan); + +function gnomonic() { + return projection(gnomonicRaw) + .scale(144.049) + .clipAngle(60); +} + +function identity$4() { + var k = 1, tx = 0, ty = 0, sx = 1, sy = 1, // scale, translate and reflect + alpha = 0, ca, sa, // angle + x0 = null, y0, x1, y1, // clip extent + kx = 1, ky = 1, + transform = transformer$3({ + point: function(x, y) { + var p = projection([x, y]); + this.stream.point(p[0], p[1]); + } + }), + postclip = identity$5, + cache, + cacheStream; + + function reset() { + kx = k * sx; + ky = k * sy; + cache = cacheStream = null; + return projection; + } + + function projection (p) { + var x = p[0] * kx, y = p[1] * ky; + if (alpha) { + var t = y * ca - x * sa; + x = x * ca + y * sa; + y = t; + } + return [x + tx, y + ty]; + } + projection.invert = function(p) { + var x = p[0] - tx, y = p[1] - ty; + if (alpha) { + var t = y * ca + x * sa; + x = x * ca - y * sa; + y = t; + } + return [x / kx, y / ky]; + }; + projection.stream = function(stream) { + return cache && cacheStream === stream ? cache : cache = transform(postclip(cacheStream = stream)); + }; + projection.postclip = function(_) { + return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip; + }; + projection.clipExtent = function(_) { + return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$5) : clipRectangle(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]]; + }; + projection.scale = function(_) { + return arguments.length ? (k = +_, reset()) : k; + }; + projection.translate = function(_) { + return arguments.length ? (tx = +_[0], ty = +_[1], reset()) : [tx, ty]; + }; + projection.angle = function(_) { + return arguments.length ? (alpha = _ % 360 * radians, sa = sin$1(alpha), ca = cos$1(alpha), reset()) : alpha * degrees; + }; + projection.reflectX = function(_) { + return arguments.length ? (sx = _ ? -1 : 1, reset()) : sx < 0; + }; + projection.reflectY = function(_) { + return arguments.length ? (sy = _ ? -1 : 1, reset()) : sy < 0; + }; + projection.fitExtent = function(extent, object) { + return fitExtent(projection, extent, object); + }; + projection.fitSize = function(size, object) { + return fitSize(projection, size, object); + }; + projection.fitWidth = function(width, object) { + return fitWidth(projection, width, object); + }; + projection.fitHeight = function(height, object) { + return fitHeight(projection, height, object); + }; + + return projection; +} + +function naturalEarth1Raw(lambda, phi) { + var phi2 = phi * phi, phi4 = phi2 * phi2; + return [ + lambda * (0.8707 - 0.131979 * phi2 + phi4 * (-0.013791 + phi4 * (0.003971 * phi2 - 0.001529 * phi4))), + phi * (1.007226 + phi2 * (0.015085 + phi4 * (-0.044475 + 0.028874 * phi2 - 0.005916 * phi4))) + ]; +} + +naturalEarth1Raw.invert = function(x, y) { + var phi = y, i = 25, delta; + do { + var phi2 = phi * phi, phi4 = phi2 * phi2; + phi -= delta = (phi * (1.007226 + phi2 * (0.015085 + phi4 * (-0.044475 + 0.028874 * phi2 - 0.005916 * phi4))) - y) / + (1.007226 + phi2 * (0.015085 * 3 + phi4 * (-0.044475 * 7 + 0.028874 * 9 * phi2 - 0.005916 * 11 * phi4))); + } while (abs$1(delta) > epsilon$1 && --i > 0); + return [ + x / (0.8707 + (phi2 = phi * phi) * (-0.131979 + phi2 * (-0.013791 + phi2 * phi2 * phi2 * (0.003971 - 0.001529 * phi2)))), + phi + ]; +}; + +function naturalEarth1() { + return projection(naturalEarth1Raw) + .scale(175.295); +} + +function orthographicRaw(x, y) { + return [cos$1(y) * sin$1(x), sin$1(y)]; +} + +orthographicRaw.invert = azimuthalInvert(asin$1); + +function orthographic() { + return projection(orthographicRaw) + .scale(249.5) + .clipAngle(90 + epsilon$1); +} + +function stereographicRaw(x, y) { + var cy = cos$1(y), k = 1 + cos$1(x) * cy; + return [cy * sin$1(x) / k, sin$1(y) / k]; +} + +stereographicRaw.invert = azimuthalInvert(function(z) { + return 2 * atan(z); +}); + +function stereographic() { + return projection(stereographicRaw) + .scale(250) + .clipAngle(142); +} + +function transverseMercatorRaw(lambda, phi) { + return [log$1(tan((halfPi$1 + phi) / 2)), -lambda]; +} + +transverseMercatorRaw.invert = function(x, y) { + return [-y, 2 * atan(exp(x)) - halfPi$1]; +}; + +function transverseMercator() { + var m = mercatorProjection(transverseMercatorRaw), + center = m.center, + rotate = m.rotate; + + m.center = function(_) { + return arguments.length ? center([-_[1], _[0]]) : (_ = center(), [_[1], -_[0]]); + }; + + m.rotate = function(_) { + return arguments.length ? rotate([_[0], _[1], _.length > 2 ? _[2] + 90 : 90]) : (_ = rotate(), [_[0], _[1], _[2] - 90]); + }; + + return rotate([0, 0, 90]) + .scale(159.155); +} + +function defaultSeparation$1(a, b) { + return a.parent === b.parent ? 1 : 2; +} + +function meanX(children) { + return children.reduce(meanXReduce, 0) / children.length; +} + +function meanXReduce(x, c) { + return x + c.x; +} + +function maxY(children) { + return 1 + children.reduce(maxYReduce, 0); +} + +function maxYReduce(y, c) { + return Math.max(y, c.y); +} + +function leafLeft(node) { + var children; + while (children = node.children) node = children[0]; + return node; +} + +function leafRight(node) { + var children; + while (children = node.children) node = children[children.length - 1]; + return node; +} + +function cluster() { + var separation = defaultSeparation$1, + dx = 1, + dy = 1, + nodeSize = false; + + function cluster(root) { + var previousNode, + x = 0; + + // First walk, computing the initial x & y values. + root.eachAfter(function(node) { + var children = node.children; + if (children) { + node.x = meanX(children); + node.y = maxY(children); + } else { + node.x = previousNode ? x += separation(node, previousNode) : 0; + node.y = 0; + previousNode = node; + } + }); + + var left = leafLeft(root), + right = leafRight(root), + x0 = left.x - separation(left, right) / 2, + x1 = right.x + separation(right, left) / 2; + + // Second walk, normalizing x & y to the desired size. + return root.eachAfter(nodeSize ? function(node) { + node.x = (node.x - root.x) * dx; + node.y = (root.y - node.y) * dy; + } : function(node) { + node.x = (node.x - x0) / (x1 - x0) * dx; + node.y = (1 - (root.y ? node.y / root.y : 1)) * dy; + }); + } + + cluster.separation = function(x) { + return arguments.length ? (separation = x, cluster) : separation; + }; + + cluster.size = function(x) { + return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? null : [dx, dy]); + }; + + cluster.nodeSize = function(x) { + return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? [dx, dy] : null); + }; + + return cluster; +} + +function count(node) { + var sum = 0, + children = node.children, + i = children && children.length; + if (!i) sum = 1; + else while (--i >= 0) sum += children[i].value; + node.value = sum; +} + +function node_count() { + return this.eachAfter(count); +} + +function node_each(callback, that) { + let index = -1; + for (const node of this) { + callback.call(that, node, ++index, this); + } + return this; +} + +function node_eachBefore(callback, that) { + var node = this, nodes = [node], children, i, index = -1; + while (node = nodes.pop()) { + callback.call(that, node, ++index, this); + if (children = node.children) { + for (i = children.length - 1; i >= 0; --i) { + nodes.push(children[i]); + } + } + } + return this; +} + +function node_eachAfter(callback, that) { + var node = this, nodes = [node], next = [], children, i, n, index = -1; + while (node = nodes.pop()) { + next.push(node); + if (children = node.children) { + for (i = 0, n = children.length; i < n; ++i) { + nodes.push(children[i]); + } + } + } + while (node = next.pop()) { + callback.call(that, node, ++index, this); + } + return this; +} + +function node_find(callback, that) { + let index = -1; + for (const node of this) { + if (callback.call(that, node, ++index, this)) { + return node; + } + } +} + +function node_sum(value) { + return this.eachAfter(function(node) { + var sum = +value(node.data) || 0, + children = node.children, + i = children && children.length; + while (--i >= 0) sum += children[i].value; + node.value = sum; + }); +} + +function node_sort(compare) { + return this.eachBefore(function(node) { + if (node.children) { + node.children.sort(compare); + } + }); +} + +function node_path(end) { + var start = this, + ancestor = leastCommonAncestor(start, end), + nodes = [start]; + while (start !== ancestor) { + start = start.parent; + nodes.push(start); + } + var k = nodes.length; + while (end !== ancestor) { + nodes.splice(k, 0, end); + end = end.parent; + } + return nodes; +} + +function leastCommonAncestor(a, b) { + if (a === b) return a; + var aNodes = a.ancestors(), + bNodes = b.ancestors(), + c = null; + a = aNodes.pop(); + b = bNodes.pop(); + while (a === b) { + c = a; + a = aNodes.pop(); + b = bNodes.pop(); + } + return c; +} + +function node_ancestors() { + var node = this, nodes = [node]; + while (node = node.parent) { + nodes.push(node); + } + return nodes; +} + +function node_descendants() { + return Array.from(this); +} + +function node_leaves() { + var leaves = []; + this.eachBefore(function(node) { + if (!node.children) { + leaves.push(node); + } + }); + return leaves; +} + +function node_links() { + var root = this, links = []; + root.each(function(node) { + if (node !== root) { // Don’t include the root’s parent, if any. + links.push({source: node.parent, target: node}); + } + }); + return links; +} + +function* node_iterator() { + var node = this, current, next = [node], children, i, n; + do { + current = next.reverse(), next = []; + while (node = current.pop()) { + yield node; + if (children = node.children) { + for (i = 0, n = children.length; i < n; ++i) { + next.push(children[i]); + } + } + } + } while (next.length); +} + +function hierarchy(data, children) { + if (data instanceof Map) { + data = [undefined, data]; + if (children === undefined) children = mapChildren; + } else if (children === undefined) { + children = objectChildren; + } + + var root = new Node$1(data), + node, + nodes = [root], + child, + childs, + i, + n; + + while (node = nodes.pop()) { + if ((childs = children(node.data)) && (n = (childs = Array.from(childs)).length)) { + node.children = childs; + for (i = n - 1; i >= 0; --i) { + nodes.push(child = childs[i] = new Node$1(childs[i])); + child.parent = node; + child.depth = node.depth + 1; + } + } + } + + return root.eachBefore(computeHeight); +} + +function node_copy() { + return hierarchy(this).eachBefore(copyData); +} + +function objectChildren(d) { + return d.children; +} + +function mapChildren(d) { + return Array.isArray(d) ? d[1] : null; +} + +function copyData(node) { + if (node.data.value !== undefined) node.value = node.data.value; + node.data = node.data.data; +} + +function computeHeight(node) { + var height = 0; + do node.height = height; + while ((node = node.parent) && (node.height < ++height)); +} + +function Node$1(data) { + this.data = data; + this.depth = + this.height = 0; + this.parent = null; +} + +Node$1.prototype = hierarchy.prototype = { + constructor: Node$1, + count: node_count, + each: node_each, + eachAfter: node_eachAfter, + eachBefore: node_eachBefore, + find: node_find, + sum: node_sum, + sort: node_sort, + path: node_path, + ancestors: node_ancestors, + descendants: node_descendants, + leaves: node_leaves, + links: node_links, + copy: node_copy, + [Symbol.iterator]: node_iterator +}; + +function array$1(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 shuffle(array) { + var m = array.length, + t, + i; + + while (m) { + i = Math.random() * m-- | 0; + t = array[m]; + array[m] = array[i]; + array[i] = t; + } + + return array; +} + +function enclose(circles) { + var i = 0, n = (circles = shuffle(Array.from(circles))).length, B = [], p, e; + + while (i < n) { + p = circles[i]; + if (e && enclosesWeak(e, p)) ++i; + else e = encloseBasis(B = extendBasis(B, p)), i = 0; + } + + return e; +} + +function extendBasis(B, p) { + var i, j; + + if (enclosesWeakAll(p, B)) return [p]; + + // If we get here then B must have at least one element. + for (i = 0; i < B.length; ++i) { + if (enclosesNot(p, B[i]) + && enclosesWeakAll(encloseBasis2(B[i], p), B)) { + return [B[i], p]; + } + } + + // If we get here then B must have at least two elements. + for (i = 0; i < B.length - 1; ++i) { + for (j = i + 1; j < B.length; ++j) { + if (enclosesNot(encloseBasis2(B[i], B[j]), p) + && enclosesNot(encloseBasis2(B[i], p), B[j]) + && enclosesNot(encloseBasis2(B[j], p), B[i]) + && enclosesWeakAll(encloseBasis3(B[i], B[j], p), B)) { + return [B[i], B[j], p]; + } + } + } + + // If we get here then something is very wrong. + throw new Error; +} + +function enclosesNot(a, b) { + var dr = a.r - b.r, dx = b.x - a.x, dy = b.y - a.y; + return dr < 0 || dr * dr < dx * dx + dy * dy; +} + +function enclosesWeak(a, b) { + var dr = a.r - b.r + Math.max(a.r, b.r, 1) * 1e-9, dx = b.x - a.x, dy = b.y - a.y; + return dr > 0 && dr * dr > dx * dx + dy * dy; +} + +function enclosesWeakAll(a, B) { + for (var i = 0; i < B.length; ++i) { + if (!enclosesWeak(a, B[i])) { + return false; + } + } + return true; +} + +function encloseBasis(B) { + switch (B.length) { + case 1: return encloseBasis1(B[0]); + case 2: return encloseBasis2(B[0], B[1]); + case 3: return encloseBasis3(B[0], B[1], B[2]); + } +} + +function encloseBasis1(a) { + return { + x: a.x, + y: a.y, + r: a.r + }; +} + +function encloseBasis2(a, b) { + var x1 = a.x, y1 = a.y, r1 = a.r, + x2 = b.x, y2 = b.y, r2 = b.r, + x21 = x2 - x1, y21 = y2 - y1, r21 = r2 - r1, + l = Math.sqrt(x21 * x21 + y21 * y21); + return { + x: (x1 + x2 + x21 / l * r21) / 2, + y: (y1 + y2 + y21 / l * r21) / 2, + r: (l + r1 + r2) / 2 + }; +} + +function encloseBasis3(a, b, c) { + var x1 = a.x, y1 = a.y, r1 = a.r, + x2 = b.x, y2 = b.y, r2 = b.r, + x3 = c.x, y3 = c.y, r3 = c.r, + a2 = x1 - x2, + a3 = x1 - x3, + b2 = y1 - y2, + b3 = y1 - y3, + c2 = r2 - r1, + c3 = r3 - r1, + d1 = x1 * x1 + y1 * y1 - r1 * r1, + d2 = d1 - x2 * x2 - y2 * y2 + r2 * r2, + d3 = d1 - x3 * x3 - y3 * y3 + r3 * r3, + ab = a3 * b2 - a2 * b3, + xa = (b2 * d3 - b3 * d2) / (ab * 2) - x1, + xb = (b3 * c2 - b2 * c3) / ab, + ya = (a3 * d2 - a2 * d3) / (ab * 2) - y1, + yb = (a2 * c3 - a3 * c2) / ab, + A = xb * xb + yb * yb - 1, + B = 2 * (r1 + xa * xb + ya * yb), + C = xa * xa + ya * ya - r1 * r1, + r = -(A ? (B + Math.sqrt(B * B - 4 * A * C)) / (2 * A) : C / B); + return { + x: x1 + xa + xb * r, + y: y1 + ya + yb * r, + r: r + }; +} + +function place(b, a, c) { + var dx = b.x - a.x, x, a2, + dy = b.y - a.y, y, b2, + d2 = dx * dx + dy * dy; + if (d2) { + a2 = a.r + c.r, a2 *= a2; + b2 = b.r + c.r, b2 *= b2; + if (a2 > b2) { + x = (d2 + b2 - a2) / (2 * d2); + y = Math.sqrt(Math.max(0, b2 / d2 - x * x)); + c.x = b.x - x * dx - y * dy; + c.y = b.y - x * dy + y * dx; + } else { + x = (d2 + a2 - b2) / (2 * d2); + y = Math.sqrt(Math.max(0, a2 / d2 - x * x)); + c.x = a.x + x * dx - y * dy; + c.y = a.y + x * dy + y * dx; + } + } else { + c.x = a.x + c.r; + c.y = a.y; + } +} + +function intersects(a, b) { + var dr = a.r + b.r - 1e-6, dx = b.x - a.x, dy = b.y - a.y; + return dr > 0 && dr * dr > dx * dx + dy * dy; +} + +function score(node) { + var a = node._, + b = node.next._, + ab = a.r + b.r, + dx = (a.x * b.r + b.x * a.r) / ab, + dy = (a.y * b.r + b.y * a.r) / ab; + return dx * dx + dy * dy; +} + +function Node(circle) { + this._ = circle; + this.next = null; + this.previous = null; +} + +function packEnclose(circles) { + if (!(n = (circles = array$1(circles)).length)) return 0; + + var a, b, c, n, aa, ca, i, j, k, sj, sk; + + // Place the first circle. + a = circles[0], a.x = 0, a.y = 0; + if (!(n > 1)) return a.r; + + // Place the second circle. + b = circles[1], a.x = -b.r, b.x = a.r, b.y = 0; + if (!(n > 2)) return a.r + b.r; + + // Place the third circle. + place(b, a, c = circles[2]); + + // Initialize the front-chain using the first three circles a, b and c. + a = new Node(a), b = new Node(b), c = new Node(c); + a.next = c.previous = b; + b.next = a.previous = c; + c.next = b.previous = a; + + // Attempt to place each remaining circle… + pack: for (i = 3; i < n; ++i) { + place(a._, b._, c = circles[i]), c = new Node(c); + + // Find the closest intersecting circle on the front-chain, if any. + // “Closeness” is determined by linear distance along the front-chain. + // “Ahead” or “behind” is likewise determined by linear distance. + j = b.next, k = a.previous, sj = b._.r, sk = a._.r; + do { + if (sj <= sk) { + if (intersects(j._, c._)) { + b = j, a.next = b, b.previous = a, --i; + continue pack; + } + sj += j._.r, j = j.next; + } else { + if (intersects(k._, c._)) { + a = k, a.next = b, b.previous = a, --i; + continue pack; + } + sk += k._.r, k = k.previous; + } + } while (j !== k.next); + + // Success! Insert the new circle c between a and b. + c.previous = a, c.next = b, a.next = b.previous = b = c; + + // Compute the new closest circle pair to the centroid. + aa = score(a); + while ((c = c.next) !== b) { + if ((ca = score(c)) < aa) { + a = c, aa = ca; + } + } + b = a.next; + } + + // Compute the enclosing circle of the front chain. + a = [b._], c = b; while ((c = c.next) !== b) a.push(c._); c = enclose(a); + + // Translate the circles to put the enclosing circle around the origin. + for (i = 0; i < n; ++i) a = circles[i], a.x -= c.x, a.y -= c.y; + + return c.r; +} + +function siblings(circles) { + packEnclose(circles); + return circles; +} + +function optional(f) { + return f == null ? null : required(f); +} + +function required(f) { + if (typeof f !== "function") throw new Error; + return f; +} + +function constantZero() { + return 0; +} + +function constant$2(x) { + return function() { + return x; + }; +} + +function defaultRadius(d) { + return Math.sqrt(d.value); +} + +function index$1() { + var radius = null, + dx = 1, + dy = 1, + padding = constantZero; + + function pack(root) { + root.x = dx / 2, root.y = dy / 2; + if (radius) { + root.eachBefore(radiusLeaf(radius)) + .eachAfter(packChildren(padding, 0.5)) + .eachBefore(translateChild(1)); + } else { + root.eachBefore(radiusLeaf(defaultRadius)) + .eachAfter(packChildren(constantZero, 1)) + .eachAfter(packChildren(padding, root.r / Math.min(dx, dy))) + .eachBefore(translateChild(Math.min(dx, dy) / (2 * root.r))); + } + return root; + } + + pack.radius = function(x) { + return arguments.length ? (radius = optional(x), pack) : radius; + }; + + pack.size = function(x) { + return arguments.length ? (dx = +x[0], dy = +x[1], pack) : [dx, dy]; + }; + + pack.padding = function(x) { + return arguments.length ? (padding = typeof x === "function" ? x : constant$2(+x), pack) : padding; + }; + + return pack; +} + +function radiusLeaf(radius) { + return function(node) { + if (!node.children) { + node.r = Math.max(0, +radius(node) || 0); + } + }; +} + +function packChildren(padding, k) { + return function(node) { + if (children = node.children) { + var children, + i, + n = children.length, + r = padding(node) * k || 0, + e; + + if (r) for (i = 0; i < n; ++i) children[i].r += r; + e = packEnclose(children); + if (r) for (i = 0; i < n; ++i) children[i].r -= r; + node.r = e + r; + } + }; +} + +function translateChild(k) { + return function(node) { + var parent = node.parent; + node.r *= k; + if (parent) { + node.x = parent.x + k * node.x; + node.y = parent.y + k * node.y; + } + }; +} + +function roundNode(node) { + node.x0 = Math.round(node.x0); + node.y0 = Math.round(node.y0); + node.x1 = Math.round(node.x1); + node.y1 = Math.round(node.y1); +} + +function treemapDice(parent, x0, y0, x1, y1) { + var nodes = parent.children, + node, + i = -1, + n = nodes.length, + k = parent.value && (x1 - x0) / parent.value; + + while (++i < n) { + node = nodes[i], node.y0 = y0, node.y1 = y1; + node.x0 = x0, node.x1 = x0 += node.value * k; + } +} + +function partition() { + var dx = 1, + dy = 1, + padding = 0, + round = false; + + function partition(root) { + var n = root.height + 1; + root.x0 = + root.y0 = padding; + root.x1 = dx; + root.y1 = dy / n; + root.eachBefore(positionNode(dy, n)); + if (round) root.eachBefore(roundNode); + return root; + } + + function positionNode(dy, n) { + return function(node) { + if (node.children) { + treemapDice(node, node.x0, dy * (node.depth + 1) / n, node.x1, dy * (node.depth + 2) / n); + } + var x0 = node.x0, + y0 = node.y0, + x1 = node.x1 - padding, + y1 = node.y1 - padding; + if (x1 < x0) x0 = x1 = (x0 + x1) / 2; + if (y1 < y0) y0 = y1 = (y0 + y1) / 2; + node.x0 = x0; + node.y0 = y0; + node.x1 = x1; + node.y1 = y1; + }; + } + + partition.round = function(x) { + return arguments.length ? (round = !!x, partition) : round; + }; + + partition.size = function(x) { + return arguments.length ? (dx = +x[0], dy = +x[1], partition) : [dx, dy]; + }; + + partition.padding = function(x) { + return arguments.length ? (padding = +x, partition) : padding; + }; + + return partition; +} + +var preroot = {depth: -1}, + ambiguous = {}; + +function defaultId(d) { + return d.id; +} + +function defaultParentId(d) { + return d.parentId; +} + +function stratify() { + var id = defaultId, + parentId = defaultParentId; + + function stratify(data) { + var nodes = Array.from(data), + n = nodes.length, + d, + i, + root, + parent, + node, + nodeId, + nodeKey, + nodeByKey = new Map; + + for (i = 0; i < n; ++i) { + d = nodes[i], node = nodes[i] = new Node$1(d); + if ((nodeId = id(d, i, data)) != null && (nodeId += "")) { + nodeKey = node.id = nodeId; + nodeByKey.set(nodeKey, nodeByKey.has(nodeKey) ? ambiguous : node); + } + if ((nodeId = parentId(d, i, data)) != null && (nodeId += "")) { + node.parent = nodeId; + } + } + + for (i = 0; i < n; ++i) { + node = nodes[i]; + if (nodeId = node.parent) { + parent = nodeByKey.get(nodeId); + if (!parent) throw new Error("missing: " + nodeId); + if (parent === ambiguous) throw new Error("ambiguous: " + nodeId); + if (parent.children) parent.children.push(node); + else parent.children = [node]; + node.parent = parent; + } else { + if (root) throw new Error("multiple roots"); + root = node; + } + } + + if (!root) throw new Error("no root"); + root.parent = preroot; + root.eachBefore(function(node) { node.depth = node.parent.depth + 1; --n; }).eachBefore(computeHeight); + root.parent = null; + if (n > 0) throw new Error("cycle"); + + return root; + } + + stratify.id = function(x) { + return arguments.length ? (id = required(x), stratify) : id; + }; + + stratify.parentId = function(x) { + return arguments.length ? (parentId = required(x), stratify) : parentId; + }; + + return stratify; +} + +function defaultSeparation(a, b) { + return a.parent === b.parent ? 1 : 2; +} + +// function radialSeparation(a, b) { +// return (a.parent === b.parent ? 1 : 2) / a.depth; +// } + +// This function is used to traverse the left contour of a subtree (or +// subforest). It returns the successor of v on this contour. This successor is +// either given by the leftmost child of v or by the thread of v. The function +// returns null if and only if v is on the highest level of its subtree. +function nextLeft(v) { + var children = v.children; + return children ? children[0] : v.t; +} + +// This function works analogously to nextLeft. +function nextRight(v) { + var children = v.children; + return children ? children[children.length - 1] : v.t; +} + +// Shifts the current subtree rooted at w+. This is done by increasing +// prelim(w+) and mod(w+) by shift. +function moveSubtree(wm, wp, shift) { + var change = shift / (wp.i - wm.i); + wp.c -= change; + wp.s += shift; + wm.c += change; + wp.z += shift; + wp.m += shift; +} + +// All other shifts, applied to the smaller subtrees between w- and w+, are +// performed by this function. To prepare the shifts, we have to adjust +// change(w+), shift(w+), and change(w-). +function executeShifts(v) { + var shift = 0, + change = 0, + children = v.children, + i = children.length, + w; + while (--i >= 0) { + w = children[i]; + w.z += shift; + w.m += shift; + shift += w.s + (change += w.c); + } +} + +// If vi-’s ancestor is a sibling of v, returns vi-’s ancestor. Otherwise, +// returns the specified (default) ancestor. +function nextAncestor(vim, v, ancestor) { + return vim.a.parent === v.parent ? vim.a : ancestor; +} + +function TreeNode(node, i) { + this._ = node; + this.parent = null; + this.children = null; + this.A = null; // default ancestor + this.a = this; // ancestor + this.z = 0; // prelim + this.m = 0; // mod + this.c = 0; // change + this.s = 0; // shift + this.t = null; // thread + this.i = i; // number +} + +TreeNode.prototype = Object.create(Node$1.prototype); + +function treeRoot(root) { + var tree = new TreeNode(root, 0), + node, + nodes = [tree], + child, + children, + i, + n; + + while (node = nodes.pop()) { + if (children = node._.children) { + node.children = new Array(n = children.length); + for (i = n - 1; i >= 0; --i) { + nodes.push(child = node.children[i] = new TreeNode(children[i], i)); + child.parent = node; + } + } + } + + (tree.parent = new TreeNode(null, 0)).children = [tree]; + return tree; +} + +// Node-link tree diagram using the Reingold-Tilford "tidy" algorithm +function tree() { + var separation = defaultSeparation, + dx = 1, + dy = 1, + nodeSize = null; + + function tree(root) { + var t = treeRoot(root); + + // Compute the layout using Buchheim et al.’s algorithm. + t.eachAfter(firstWalk), t.parent.m = -t.z; + t.eachBefore(secondWalk); + + // If a fixed node size is specified, scale x and y. + if (nodeSize) root.eachBefore(sizeNode); + + // If a fixed tree size is specified, scale x and y based on the extent. + // Compute the left-most, right-most, and depth-most nodes for extents. + else { + var left = root, + right = root, + bottom = root; + root.eachBefore(function(node) { + if (node.x < left.x) left = node; + if (node.x > right.x) right = node; + if (node.depth > bottom.depth) bottom = node; + }); + var s = left === right ? 1 : separation(left, right) / 2, + tx = s - left.x, + kx = dx / (right.x + s + tx), + ky = dy / (bottom.depth || 1); + root.eachBefore(function(node) { + node.x = (node.x + tx) * kx; + node.y = node.depth * ky; + }); + } + + return root; + } + + // Computes a preliminary x-coordinate for v. Before that, FIRST WALK is + // applied recursively to the children of v, as well as the function + // APPORTION. After spacing out the children by calling EXECUTE SHIFTS, the + // node v is placed to the midpoint of its outermost children. + function firstWalk(v) { + var children = v.children, + siblings = v.parent.children, + w = v.i ? siblings[v.i - 1] : null; + if (children) { + executeShifts(v); + var midpoint = (children[0].z + children[children.length - 1].z) / 2; + if (w) { + v.z = w.z + separation(v._, w._); + v.m = v.z - midpoint; + } else { + v.z = midpoint; + } + } else if (w) { + v.z = w.z + separation(v._, w._); + } + v.parent.A = apportion(v, w, v.parent.A || siblings[0]); + } + + // Computes all real x-coordinates by summing up the modifiers recursively. + function secondWalk(v) { + v._.x = v.z + v.parent.m; + v.m += v.parent.m; + } + + // The core of the algorithm. Here, a new subtree is combined with the + // previous subtrees. Threads are used to traverse the inside and outside + // contours of the left and right subtree up to the highest common level. The + // vertices used for the traversals are vi+, vi-, vo-, and vo+, where the + // superscript o means outside and i means inside, the subscript - means left + // subtree and + means right subtree. For summing up the modifiers along the + // contour, we use respective variables si+, si-, so-, and so+. Whenever two + // nodes of the inside contours conflict, we compute the left one of the + // greatest uncommon ancestors using the function ANCESTOR and call MOVE + // SUBTREE to shift the subtree and prepare the shifts of smaller subtrees. + // Finally, we add a new thread (if necessary). + function apportion(v, w, ancestor) { + if (w) { + var vip = v, + vop = v, + vim = w, + vom = vip.parent.children[0], + sip = vip.m, + sop = vop.m, + sim = vim.m, + som = vom.m, + shift; + while (vim = nextRight(vim), vip = nextLeft(vip), vim && vip) { + vom = nextLeft(vom); + vop = nextRight(vop); + vop.a = v; + shift = vim.z + sim - vip.z - sip + separation(vim._, vip._); + if (shift > 0) { + moveSubtree(nextAncestor(vim, v, ancestor), v, shift); + sip += shift; + sop += shift; + } + sim += vim.m; + sip += vip.m; + som += vom.m; + sop += vop.m; + } + if (vim && !nextRight(vop)) { + vop.t = vim; + vop.m += sim - sop; + } + if (vip && !nextLeft(vom)) { + vom.t = vip; + vom.m += sip - som; + ancestor = v; + } + } + return ancestor; + } + + function sizeNode(node) { + node.x *= dx; + node.y = node.depth * dy; + } + + tree.separation = function(x) { + return arguments.length ? (separation = x, tree) : separation; + }; + + tree.size = function(x) { + return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], tree) : (nodeSize ? null : [dx, dy]); + }; + + tree.nodeSize = function(x) { + return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], tree) : (nodeSize ? [dx, dy] : null); + }; + + return tree; +} + +function treemapSlice(parent, x0, y0, x1, y1) { + var nodes = parent.children, + node, + i = -1, + n = nodes.length, + k = parent.value && (y1 - y0) / parent.value; + + while (++i < n) { + node = nodes[i], node.x0 = x0, node.x1 = x1; + node.y0 = y0, node.y1 = y0 += node.value * k; + } +} + +var phi = (1 + Math.sqrt(5)) / 2; + +function squarifyRatio(ratio, parent, x0, y0, x1, y1) { + var rows = [], + nodes = parent.children, + row, + nodeValue, + i0 = 0, + i1 = 0, + n = nodes.length, + dx, dy, + value = parent.value, + sumValue, + minValue, + maxValue, + newRatio, + minRatio, + alpha, + beta; + + while (i0 < n) { + dx = x1 - x0, dy = y1 - y0; + + // Find the next non-empty node. + do sumValue = nodes[i1++].value; while (!sumValue && i1 < n); + minValue = maxValue = sumValue; + alpha = Math.max(dy / dx, dx / dy) / (value * ratio); + beta = sumValue * sumValue * alpha; + minRatio = Math.max(maxValue / beta, beta / minValue); + + // Keep adding nodes while the aspect ratio maintains or improves. + for (; i1 < n; ++i1) { + sumValue += nodeValue = nodes[i1].value; + if (nodeValue < minValue) minValue = nodeValue; + if (nodeValue > maxValue) maxValue = nodeValue; + beta = sumValue * sumValue * alpha; + newRatio = Math.max(maxValue / beta, beta / minValue); + if (newRatio > minRatio) { sumValue -= nodeValue; break; } + minRatio = newRatio; + } + + // Position and record the row orientation. + rows.push(row = {value: sumValue, dice: dx < dy, children: nodes.slice(i0, i1)}); + if (row.dice) treemapDice(row, x0, y0, x1, value ? y0 += dy * sumValue / value : y1); + else treemapSlice(row, x0, y0, value ? x0 += dx * sumValue / value : x1, y1); + value -= sumValue, i0 = i1; + } + + return rows; +} + +var squarify = (function custom(ratio) { + + function squarify(parent, x0, y0, x1, y1) { + squarifyRatio(ratio, parent, x0, y0, x1, y1); + } + + squarify.ratio = function(x) { + return custom((x = +x) > 1 ? x : 1); + }; + + return squarify; +})(phi); + +function index() { + var tile = squarify, + round = false, + dx = 1, + dy = 1, + paddingStack = [0], + paddingInner = constantZero, + paddingTop = constantZero, + paddingRight = constantZero, + paddingBottom = constantZero, + paddingLeft = constantZero; + + function treemap(root) { + root.x0 = + root.y0 = 0; + root.x1 = dx; + root.y1 = dy; + root.eachBefore(positionNode); + paddingStack = [0]; + if (round) root.eachBefore(roundNode); + return root; + } + + function positionNode(node) { + var p = paddingStack[node.depth], + x0 = node.x0 + p, + y0 = node.y0 + p, + x1 = node.x1 - p, + y1 = node.y1 - p; + if (x1 < x0) x0 = x1 = (x0 + x1) / 2; + if (y1 < y0) y0 = y1 = (y0 + y1) / 2; + node.x0 = x0; + node.y0 = y0; + node.x1 = x1; + node.y1 = y1; + if (node.children) { + p = paddingStack[node.depth + 1] = paddingInner(node) / 2; + x0 += paddingLeft(node) - p; + y0 += paddingTop(node) - p; + x1 -= paddingRight(node) - p; + y1 -= paddingBottom(node) - p; + if (x1 < x0) x0 = x1 = (x0 + x1) / 2; + if (y1 < y0) y0 = y1 = (y0 + y1) / 2; + tile(node, x0, y0, x1, y1); + } + } + + treemap.round = function(x) { + return arguments.length ? (round = !!x, treemap) : round; + }; + + treemap.size = function(x) { + return arguments.length ? (dx = +x[0], dy = +x[1], treemap) : [dx, dy]; + }; + + treemap.tile = function(x) { + return arguments.length ? (tile = required(x), treemap) : tile; + }; + + treemap.padding = function(x) { + return arguments.length ? treemap.paddingInner(x).paddingOuter(x) : treemap.paddingInner(); + }; + + treemap.paddingInner = function(x) { + return arguments.length ? (paddingInner = typeof x === "function" ? x : constant$2(+x), treemap) : paddingInner; + }; + + treemap.paddingOuter = function(x) { + return arguments.length ? treemap.paddingTop(x).paddingRight(x).paddingBottom(x).paddingLeft(x) : treemap.paddingTop(); + }; + + treemap.paddingTop = function(x) { + return arguments.length ? (paddingTop = typeof x === "function" ? x : constant$2(+x), treemap) : paddingTop; + }; + + treemap.paddingRight = function(x) { + return arguments.length ? (paddingRight = typeof x === "function" ? x : constant$2(+x), treemap) : paddingRight; + }; + + treemap.paddingBottom = function(x) { + return arguments.length ? (paddingBottom = typeof x === "function" ? x : constant$2(+x), treemap) : paddingBottom; + }; + + treemap.paddingLeft = function(x) { + return arguments.length ? (paddingLeft = typeof x === "function" ? x : constant$2(+x), treemap) : paddingLeft; + }; + + return treemap; +} + +function binary(parent, x0, y0, x1, y1) { + var nodes = parent.children, + i, n = nodes.length, + sum, sums = new Array(n + 1); + + for (sums[0] = sum = i = 0; i < n; ++i) { + sums[i + 1] = sum += nodes[i].value; + } + + partition(0, n, parent.value, x0, y0, x1, y1); + + function partition(i, j, value, x0, y0, x1, y1) { + if (i >= j - 1) { + var node = nodes[i]; + node.x0 = x0, node.y0 = y0; + node.x1 = x1, node.y1 = y1; + return; + } + + var valueOffset = sums[i], + valueTarget = (value / 2) + valueOffset, + k = i + 1, + hi = j - 1; + + while (k < hi) { + var mid = k + hi >>> 1; + if (sums[mid] < valueTarget) k = mid + 1; + else hi = mid; + } + + if ((valueTarget - sums[k - 1]) < (sums[k] - valueTarget) && i + 1 < k) --k; + + var valueLeft = sums[k] - valueOffset, + valueRight = value - valueLeft; + + if ((x1 - x0) > (y1 - y0)) { + var xk = value ? (x0 * valueRight + x1 * valueLeft) / value : x1; + partition(i, k, valueLeft, x0, y0, xk, y1); + partition(k, j, valueRight, xk, y0, x1, y1); + } else { + var yk = value ? (y0 * valueRight + y1 * valueLeft) / value : y1; + partition(i, k, valueLeft, x0, y0, x1, yk); + partition(k, j, valueRight, x0, yk, x1, y1); + } + } +} + +function sliceDice(parent, x0, y0, x1, y1) { + (parent.depth & 1 ? treemapSlice : treemapDice)(parent, x0, y0, x1, y1); +} + +var resquarify = (function custom(ratio) { + + function resquarify(parent, x0, y0, x1, y1) { + if ((rows = parent._squarify) && (rows.ratio === ratio)) { + var rows, + row, + nodes, + i, + j = -1, + n, + m = rows.length, + value = parent.value; + + while (++j < m) { + row = rows[j], nodes = row.children; + for (i = row.value = 0, n = nodes.length; i < n; ++i) row.value += nodes[i].value; + if (row.dice) treemapDice(row, x0, y0, x1, value ? y0 += (y1 - y0) * row.value / value : y1); + else treemapSlice(row, x0, y0, value ? x0 += (x1 - x0) * row.value / value : x1, y1); + value -= row.value; + } + } else { + parent._squarify = rows = squarifyRatio(ratio, parent, x0, y0, x1, y1); + rows.ratio = ratio; + } + } + + resquarify.ratio = function(x) { + return custom((x = +x) > 1 ? x : 1); + }; + + return resquarify; +})(phi); + +function area$1(polygon) { + var i = -1, + n = polygon.length, + a, + b = polygon[n - 1], + area = 0; + + while (++i < n) { + a = b; + b = polygon[i]; + area += a[1] * b[0] - a[0] * b[1]; + } + + return area / 2; +} + +function centroid(polygon) { + var i = -1, + n = polygon.length, + x = 0, + y = 0, + a, + b = polygon[n - 1], + c, + k = 0; + + while (++i < n) { + a = b; + b = polygon[i]; + k += c = a[0] * b[1] - b[0] * a[1]; + x += (a[0] + b[0]) * c; + y += (a[1] + b[1]) * c; + } + + return k *= 3, [x / k, y / k]; +} + +// Returns the 2D cross product of AB and AC vectors, i.e., the z-component of +// the 3D cross product in a quadrant I Cartesian coordinate system (+x is +// right, +y is up). Returns a positive value if ABC is counter-clockwise, +// negative if clockwise, and zero if the points are collinear. +function cross$1(a, b, c) { + return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]); +} + +function lexicographicOrder(a, b) { + return a[0] - b[0] || a[1] - b[1]; +} + +// Computes the upper convex hull per the monotone chain algorithm. +// Assumes points.length >= 3, is sorted by x, unique in y. +// Returns an array of indices into points in left-to-right order. +function computeUpperHullIndexes(points) { + const n = points.length, + indexes = [0, 1]; + let size = 2, i; + + for (i = 2; i < n; ++i) { + while (size > 1 && cross$1(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) --size; + indexes[size++] = i; + } + + return indexes.slice(0, size); // remove popped points +} + +function hull(points) { + if ((n = points.length) < 3) return null; + + var i, + n, + sortedPoints = new Array(n), + flippedPoints = new Array(n); + + for (i = 0; i < n; ++i) sortedPoints[i] = [+points[i][0], +points[i][1], i]; + sortedPoints.sort(lexicographicOrder); + for (i = 0; i < n; ++i) flippedPoints[i] = [sortedPoints[i][0], -sortedPoints[i][1]]; + + var upperIndexes = computeUpperHullIndexes(sortedPoints), + lowerIndexes = computeUpperHullIndexes(flippedPoints); + + // Construct the hull polygon, removing possible duplicate endpoints. + var skipLeft = lowerIndexes[0] === upperIndexes[0], + skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1], + hull = []; + + // Add upper hull in right-to-l order. + // Then add lower hull in left-to-right order. + for (i = upperIndexes.length - 1; i >= 0; --i) hull.push(points[sortedPoints[upperIndexes[i]][2]]); + for (i = +skipLeft; i < lowerIndexes.length - skipRight; ++i) hull.push(points[sortedPoints[lowerIndexes[i]][2]]); + + return hull; +} + +function contains(polygon, point) { + var n = polygon.length, + p = polygon[n - 1], + x = point[0], y = point[1], + x0 = p[0], y0 = p[1], + x1, y1, + inside = false; + + for (var i = 0; i < n; ++i) { + p = polygon[i], x1 = p[0], y1 = p[1]; + if (((y1 > y) !== (y0 > y)) && (x < (x0 - x1) * (y - y1) / (y0 - y1) + x1)) inside = !inside; + x0 = x1, y0 = y1; + } + + return inside; +} + +function length(polygon) { + var i = -1, + n = polygon.length, + b = polygon[n - 1], + xa, + ya, + xb = b[0], + yb = b[1], + perimeter = 0; + + while (++i < n) { + xa = xb; + ya = yb; + b = polygon[i]; + xb = b[0]; + yb = b[1]; + xa -= xb; + ya -= yb; + perimeter += Math.hypot(xa, ya); + } + + return perimeter; +} + +var defaultSource = Math.random; + +var uniform = (function sourceRandomUniform(source) { + function randomUniform(min, max) { + min = min == null ? 0 : +min; + max = max == null ? 1 : +max; + if (arguments.length === 1) max = min, min = 0; + else max -= min; + return function() { + return source() * max + min; + }; + } + + randomUniform.source = sourceRandomUniform; + + return randomUniform; +})(defaultSource); + +var int = (function sourceRandomInt(source) { + function randomInt(min, max) { + if (arguments.length < 2) max = min, min = 0; + min = Math.floor(min); + max = Math.floor(max) - min; + return function() { + return Math.floor(source() * max + min); + }; + } + + randomInt.source = sourceRandomInt; + + return randomInt; +})(defaultSource); + +var normal = (function sourceRandomNormal(source) { + function randomNormal(mu, sigma) { + var x, r; + mu = mu == null ? 0 : +mu; + sigma = sigma == null ? 1 : +sigma; + return function() { + var y; + + // If available, use the second previously-generated uniform random. + if (x != null) y = x, x = null; + + // Otherwise, generate a new x and y. + else do { + x = source() * 2 - 1; + y = source() * 2 - 1; + r = x * x + y * y; + } while (!r || r > 1); + + return mu + sigma * y * Math.sqrt(-2 * Math.log(r) / r); + }; + } + + randomNormal.source = sourceRandomNormal; + + return randomNormal; +})(defaultSource); + +var logNormal = (function sourceRandomLogNormal(source) { + var N = normal.source(source); + + function randomLogNormal() { + var randomNormal = N.apply(this, arguments); + return function() { + return Math.exp(randomNormal()); + }; + } + + randomLogNormal.source = sourceRandomLogNormal; + + return randomLogNormal; +})(defaultSource); + +var irwinHall = (function sourceRandomIrwinHall(source) { + function randomIrwinHall(n) { + if ((n = +n) <= 0) return () => 0; + return function() { + for (var sum = 0, i = n; i > 1; --i) sum += source(); + return sum + i * source(); + }; + } + + randomIrwinHall.source = sourceRandomIrwinHall; + + return randomIrwinHall; +})(defaultSource); + +var bates = (function sourceRandomBates(source) { + var I = irwinHall.source(source); + + function randomBates(n) { + // use limiting distribution at n === 0 + if ((n = +n) === 0) return source; + var randomIrwinHall = I(n); + return function() { + return randomIrwinHall() / n; + }; + } + + randomBates.source = sourceRandomBates; + + return randomBates; +})(defaultSource); + +var exponential = (function sourceRandomExponential(source) { + function randomExponential(lambda) { + return function() { + return -Math.log1p(-source()) / lambda; + }; + } + + randomExponential.source = sourceRandomExponential; + + return randomExponential; +})(defaultSource); + +var pareto = (function sourceRandomPareto(source) { + function randomPareto(alpha) { + if ((alpha = +alpha) < 0) throw new RangeError("invalid alpha"); + alpha = 1 / -alpha; + return function() { + return Math.pow(1 - source(), alpha); + }; + } + + randomPareto.source = sourceRandomPareto; + + return randomPareto; +})(defaultSource); + +var bernoulli = (function sourceRandomBernoulli(source) { + function randomBernoulli(p) { + if ((p = +p) < 0 || p > 1) throw new RangeError("invalid p"); + return function() { + return Math.floor(source() + p); + }; + } + + randomBernoulli.source = sourceRandomBernoulli; + + return randomBernoulli; +})(defaultSource); + +var geometric = (function sourceRandomGeometric(source) { + function randomGeometric(p) { + if ((p = +p) < 0 || p > 1) throw new RangeError("invalid p"); + if (p === 0) return () => Infinity; + if (p === 1) return () => 1; + p = Math.log1p(-p); + return function() { + return 1 + Math.floor(Math.log1p(-source()) / p); + }; + } + + randomGeometric.source = sourceRandomGeometric; + + return randomGeometric; +})(defaultSource); + +var gamma = (function sourceRandomGamma(source) { + var randomNormal = normal.source(source)(); + + function randomGamma(k, theta) { + if ((k = +k) < 0) throw new RangeError("invalid k"); + // degenerate distribution if k === 0 + if (k === 0) return () => 0; + theta = theta == null ? 1 : +theta; + // exponential distribution if k === 1 + if (k === 1) return () => -Math.log1p(-source()) * theta; + + var d = (k < 1 ? k + 1 : k) - 1 / 3, + c = 1 / (3 * Math.sqrt(d)), + multiplier = k < 1 ? () => Math.pow(source(), 1 / k) : () => 1; + return function() { + do { + do { + var x = randomNormal(), + v = 1 + c * x; + } while (v <= 0); + v *= v * v; + var u = 1 - source(); + } while (u >= 1 - 0.0331 * x * x * x * x && Math.log(u) >= 0.5 * x * x + d * (1 - v + Math.log(v))); + return d * v * multiplier() * theta; + }; + } + + randomGamma.source = sourceRandomGamma; + + return randomGamma; +})(defaultSource); + +var beta = (function sourceRandomBeta(source) { + var G = gamma.source(source); + + function randomBeta(alpha, beta) { + var X = G(alpha), + Y = G(beta); + return function() { + var x = X(); + return x === 0 ? 0 : x / (x + Y()); + }; + } + + randomBeta.source = sourceRandomBeta; + + return randomBeta; +})(defaultSource); + +var binomial = (function sourceRandomBinomial(source) { + var G = geometric.source(source), + B = beta.source(source); + + function randomBinomial(n, p) { + n = +n; + if ((p = +p) >= 1) return () => n; + if (p <= 0) return () => 0; + return function() { + var acc = 0, nn = n, pp = p; + while (nn * pp > 16 && nn * (1 - pp) > 16) { + var i = Math.floor((nn + 1) * pp), + y = B(i, nn - i + 1)(); + if (y <= pp) { + acc += i; + nn -= i; + pp = (pp - y) / (1 - y); + } else { + nn = i - 1; + pp /= y; + } + } + var sign = pp < 0.5, + pFinal = sign ? pp : 1 - pp, + g = G(pFinal); + for (var s = g(), k = 0; s <= nn; ++k) s += g(); + return acc + (sign ? k : nn - k); + }; + } + + randomBinomial.source = sourceRandomBinomial; + + return randomBinomial; +})(defaultSource); + +var weibull = (function sourceRandomWeibull(source) { + function randomWeibull(k, a, b) { + var outerFunc; + if ((k = +k) === 0) { + outerFunc = x => -Math.log(x); + } else { + k = 1 / k; + outerFunc = x => Math.pow(x, k); + } + a = a == null ? 0 : +a; + b = b == null ? 1 : +b; + return function() { + return a + b * outerFunc(-Math.log1p(-source())); + }; + } + + randomWeibull.source = sourceRandomWeibull; + + return randomWeibull; +})(defaultSource); + +var cauchy = (function sourceRandomCauchy(source) { + function randomCauchy(a, b) { + a = a == null ? 0 : +a; + b = b == null ? 1 : +b; + return function() { + return a + b * Math.tan(Math.PI * source()); + }; + } + + randomCauchy.source = sourceRandomCauchy; + + return randomCauchy; +})(defaultSource); + +var logistic = (function sourceRandomLogistic(source) { + function randomLogistic(a, b) { + a = a == null ? 0 : +a; + b = b == null ? 1 : +b; + return function() { + var u = source(); + return a + b * Math.log(u / (1 - u)); + }; + } + + randomLogistic.source = sourceRandomLogistic; + + return randomLogistic; +})(defaultSource); + +var poisson = (function sourceRandomPoisson(source) { + var G = gamma.source(source), + B = binomial.source(source); + + function randomPoisson(lambda) { + return function() { + var acc = 0, l = lambda; + while (l > 16) { + var n = Math.floor(0.875 * l), + t = G(n)(); + if (t > l) return acc + B(n - 1, l / t)(); + acc += n; + l -= t; + } + for (var s = -Math.log1p(-source()), k = 0; s <= l; ++k) s -= Math.log1p(-source()); + return acc + k; + }; + } + + randomPoisson.source = sourceRandomPoisson; + + return randomPoisson; +})(defaultSource); + +// https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use +const mul = 0x19660D; +const inc = 0x3C6EF35F; +const eps = 1 / 0x100000000; + +function lcg(seed = Math.random()) { + let state = (0 <= seed && seed < 1 ? seed / eps : Math.abs(seed)) | 0; + return () => (state = mul * state + inc | 0, eps * (state >>> 0)); +} + +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 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 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 = range$2(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$4() { + 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$3(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 = 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 = interpolate$2, + transform, + untransform, + unknown, + clamp = identity$3, + piecewise, + output, + input; + + function rescale() { + var n = Math.min(domain.length, range.length); + if (clamp !== identity$3) 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), 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 = interpolateRound, rescale(); + }; + + scale.clamp = function(_) { + return arguments.length ? (clamp = _ ? true : identity$3, rescale()) : clamp !== identity$3; + }; + + 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$3, identity$3); +} + +function tickFormat(start, stop, count, specifier) { + var step = tickStep(start, stop, count), + precision; + specifier = 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 = precisionPrefix(step, value))) specifier.precision = precision; + return exports.formatPrefix(specifier, value); + } + case "": + case "e": + case "g": + case "p": + case "r": { + if (specifier.precision == null && !isNaN(precision = 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 = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2; + break; + } + } + return exports.format(specifier); +} + +function linearish(scale) { + var domain = scale.domain; + + scale.ticks = function(count) { + var d = domain(); + return 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 = 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$2(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$2(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 = ticks(u, v, n); + } else { + z = 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 = formatSpecifier(specifier)).precision == null) specifier.trim = true; + specifier = exports.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$3, identity$3), + exponent = 1; + + function rescale() { + return exponent === 1 ? transform(identity$3, identity$3) + : 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$1() { + return pow.apply(null, arguments).exponent(0.5); +} + +function square$1(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$1(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$1)), 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] = quantileSorted(domain, i / n); + return scale; + } + + function scale(x) { + return x == null || isNaN(x = +x) ? unknown : range[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(ascending$3); + 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[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[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); +} + +var t0 = new Date, + t1 = new Date; + +function newInterval(floori, offseti, count, field) { + + function interval(date) { + return floori(date = arguments.length === 0 ? new Date : new Date(+date)), date; + } + + interval.floor = function(date) { + return floori(date = new Date(+date)), date; + }; + + interval.ceil = function(date) { + return floori(date = new Date(date - 1)), offseti(date, 1), floori(date), date; + }; + + interval.round = function(date) { + var d0 = interval(date), + d1 = interval.ceil(date); + return date - d0 < d1 - date ? d0 : d1; + }; + + interval.offset = function(date, step) { + return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date; + }; + + interval.range = function(start, stop, step) { + var range = [], previous; + start = interval.ceil(start); + step = step == null ? 1 : Math.floor(step); + if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date + do range.push(previous = new Date(+start)), offseti(start, step), floori(start); + while (previous < start && start < stop); + return range; + }; + + interval.filter = function(test) { + return newInterval(function(date) { + if (date >= date) while (floori(date), !test(date)) date.setTime(date - 1); + }, function(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 = function(start, end) { + t0.setTime(+start), t1.setTime(+end); + floori(t0), floori(t1); + return Math.floor(count(t0, t1)); + }; + + interval.every = function(step) { + step = Math.floor(step); + return !isFinite(step) || !(step > 0) ? null + : !(step > 1) ? interval + : interval.filter(field + ? function(d) { return field(d) % step === 0; } + : function(d) { return interval.count(0, d) % step === 0; }); + }; + } + + return interval; +} + +var millisecond = newInterval(function() { + // noop +}, function(date, step) { + date.setTime(+date + step); +}, function(start, end) { + return end - start; +}); + +// An optimized implementation for this simple case. +millisecond.every = function(k) { + k = Math.floor(k); + if (!isFinite(k) || !(k > 0)) return null; + if (!(k > 1)) return millisecond; + return newInterval(function(date) { + date.setTime(Math.floor(date / k) * k); + }, function(date, step) { + date.setTime(+date + step * k); + }, function(start, end) { + return (end - start) / k; + }); +}; + +var millisecond$1 = millisecond; +var 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; + +var second = newInterval(function(date) { + date.setTime(date - date.getMilliseconds()); +}, function(date, step) { + date.setTime(+date + step * durationSecond); +}, function(start, end) { + return (end - start) / durationSecond; +}, function(date) { + return date.getUTCSeconds(); +}); + +var utcSecond = second; +var seconds = second.range; + +var minute = newInterval(function(date) { + date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond); +}, function(date, step) { + date.setTime(+date + step * durationMinute); +}, function(start, end) { + return (end - start) / durationMinute; +}, function(date) { + return date.getMinutes(); +}); + +var timeMinute = minute; +var minutes = minute.range; + +var hour = newInterval(function(date) { + date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond - date.getMinutes() * durationMinute); +}, function(date, step) { + date.setTime(+date + step * durationHour); +}, function(start, end) { + return (end - start) / durationHour; +}, function(date) { + return date.getHours(); +}); + +var timeHour = hour; +var hours = hour.range; + +var day = newInterval( + 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 +); + +var timeDay = day; +var days = day.range; + +function weekday(i) { + return newInterval(function(date) { + date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7); + date.setHours(0, 0, 0, 0); + }, function(date, step) { + date.setDate(date.getDate() + step * 7); + }, function(start, end) { + return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationWeek; + }); +} + +var sunday = weekday(0); +var monday = weekday(1); +var tuesday = weekday(2); +var wednesday = weekday(3); +var thursday = weekday(4); +var friday = weekday(5); +var saturday = weekday(6); + +var sundays = sunday.range; +var mondays = monday.range; +var tuesdays = tuesday.range; +var wednesdays = wednesday.range; +var thursdays = thursday.range; +var fridays = friday.range; +var saturdays = saturday.range; + +var month = newInterval(function(date) { + date.setDate(1); + date.setHours(0, 0, 0, 0); +}, function(date, step) { + date.setMonth(date.getMonth() + step); +}, function(start, end) { + return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12; +}, function(date) { + return date.getMonth(); +}); + +var timeMonth = month; +var months = month.range; + +var year = newInterval(function(date) { + date.setMonth(0, 1); + date.setHours(0, 0, 0, 0); +}, function(date, step) { + date.setFullYear(date.getFullYear() + step); +}, function(start, end) { + return end.getFullYear() - start.getFullYear(); +}, function(date) { + return date.getFullYear(); +}); + +// An optimized implementation for this simple case. +year.every = function(k) { + return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) { + date.setFullYear(Math.floor(date.getFullYear() / k) * k); + date.setMonth(0, 1); + date.setHours(0, 0, 0, 0); + }, function(date, step) { + date.setFullYear(date.getFullYear() + step * k); + }); +}; + +var timeYear = year; +var years = year.range; + +var utcMinute = newInterval(function(date) { + date.setUTCSeconds(0, 0); +}, function(date, step) { + date.setTime(+date + step * durationMinute); +}, function(start, end) { + return (end - start) / durationMinute; +}, function(date) { + return date.getUTCMinutes(); +}); + +var utcMinute$1 = utcMinute; +var utcMinutes = utcMinute.range; + +var utcHour = newInterval(function(date) { + date.setUTCMinutes(0, 0, 0); +}, function(date, step) { + date.setTime(+date + step * durationHour); +}, function(start, end) { + return (end - start) / durationHour; +}, function(date) { + return date.getUTCHours(); +}); + +var utcHour$1 = utcHour; +var utcHours = utcHour.range; + +var utcDay = newInterval(function(date) { + date.setUTCHours(0, 0, 0, 0); +}, function(date, step) { + date.setUTCDate(date.getUTCDate() + step); +}, function(start, end) { + return (end - start) / durationDay; +}, function(date) { + return date.getUTCDate() - 1; +}); + +var utcDay$1 = utcDay; +var utcDays = utcDay.range; + +function utcWeekday(i) { + return newInterval(function(date) { + date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7); + date.setUTCHours(0, 0, 0, 0); + }, function(date, step) { + date.setUTCDate(date.getUTCDate() + step * 7); + }, function(start, end) { + return (end - start) / durationWeek; + }); +} + +var utcSunday = utcWeekday(0); +var utcMonday = utcWeekday(1); +var utcTuesday = utcWeekday(2); +var utcWednesday = utcWeekday(3); +var utcThursday = utcWeekday(4); +var utcFriday = utcWeekday(5); +var utcSaturday = utcWeekday(6); + +var utcSundays = utcSunday.range; +var utcMondays = utcMonday.range; +var utcTuesdays = utcTuesday.range; +var utcWednesdays = utcWednesday.range; +var utcThursdays = utcThursday.range; +var utcFridays = utcFriday.range; +var utcSaturdays = utcSaturday.range; + +var utcMonth = newInterval(function(date) { + date.setUTCDate(1); + date.setUTCHours(0, 0, 0, 0); +}, function(date, step) { + date.setUTCMonth(date.getUTCMonth() + step); +}, function(start, end) { + return end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12; +}, function(date) { + return date.getUTCMonth(); +}); + +var utcMonth$1 = utcMonth; +var utcMonths = utcMonth.range; + +var utcYear = newInterval(function(date) { + date.setUTCMonth(0, 1); + date.setUTCHours(0, 0, 0, 0); +}, function(date, step) { + date.setUTCFullYear(date.getUTCFullYear() + step); +}, function(start, end) { + return end.getUTCFullYear() - start.getUTCFullYear(); +}, function(date) { + return date.getUTCFullYear(); +}); + +// An optimized implementation for this simple case. +utcYear.every = function(k) { + return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) { + date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k); + date.setUTCMonth(0, 1); + date.setUTCHours(0, 0, 0, 0); + }, function(date, step) { + date.setUTCFullYear(date.getUTCFullYear() + step * k); + }); +}; + +var utcYear$1 = utcYear; +var utcYears = utcYear.range; + +function ticker(year, month, week, day, hour, minute) { + + const tickIntervals = [ + [utcSecond, 1, durationSecond], + [utcSecond, 5, 5 * durationSecond], + [utcSecond, 15, 15 * durationSecond], + [utcSecond, 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 = bisector(([,, step]) => step).right(tickIntervals, target); + if (i === tickIntervals.length) return year.every(tickStep(start / durationYear, stop / durationYear, count)); + if (i === 0) return millisecond$1.every(Math.max(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$1, utcMonth$1, utcSunday, utcDay$1, utcHour$1, utcMinute$1); +const [timeTicks, timeTickInterval] = ticker(timeYear, timeMonth, sunday, timeDay, timeHour, timeMinute); + +function localDate(d) { + if (0 <= d.y && d.y < 100) { + var date = new Date(-1, d.m, d.d, d.H, d.M, d.S, d.L); + date.setFullYear(d.y); + return date; + } + return new Date(d.y, d.m, d.d, d.H, d.M, d.S, d.L); +} + +function utcDate(d) { + if (0 <= d.y && d.y < 100) { + var date = new Date(Date.UTC(-1, d.m, d.d, d.H, d.M, d.S, d.L)); + date.setUTCFullYear(d.y); + return date; + } + return new Date(Date.UTC(d.y, d.m, d.d, d.H, d.M, d.S, d.L)); +} + +function newDate(y, m, d) { + return {y: y, m: m, d: d, H: 0, M: 0, S: 0, L: 0}; +} + +function formatLocale(locale) { + var locale_dateTime = locale.dateTime, + locale_date = locale.date, + locale_time = locale.time, + locale_periods = locale.periods, + locale_weekdays = locale.days, + locale_shortWeekdays = locale.shortDays, + locale_months = locale.months, + locale_shortMonths = locale.shortMonths; + + var periodRe = formatRe(locale_periods), + periodLookup = formatLookup(locale_periods), + weekdayRe = formatRe(locale_weekdays), + weekdayLookup = formatLookup(locale_weekdays), + shortWeekdayRe = formatRe(locale_shortWeekdays), + shortWeekdayLookup = formatLookup(locale_shortWeekdays), + monthRe = formatRe(locale_months), + monthLookup = formatLookup(locale_months), + shortMonthRe = formatRe(locale_shortMonths), + shortMonthLookup = formatLookup(locale_shortMonths); + + var formats = { + "a": formatShortWeekday, + "A": formatWeekday, + "b": formatShortMonth, + "B": formatMonth, + "c": null, + "d": formatDayOfMonth, + "e": formatDayOfMonth, + "f": formatMicroseconds, + "g": formatYearISO, + "G": formatFullYearISO, + "H": formatHour24, + "I": formatHour12, + "j": formatDayOfYear, + "L": formatMilliseconds, + "m": formatMonthNumber, + "M": formatMinutes, + "p": formatPeriod, + "q": formatQuarter, + "Q": formatUnixTimestamp, + "s": formatUnixTimestampSeconds, + "S": formatSeconds, + "u": formatWeekdayNumberMonday, + "U": formatWeekNumberSunday, + "V": formatWeekNumberISO, + "w": formatWeekdayNumberSunday, + "W": formatWeekNumberMonday, + "x": null, + "X": null, + "y": formatYear, + "Y": formatFullYear, + "Z": formatZone, + "%": formatLiteralPercent + }; + + var utcFormats = { + "a": formatUTCShortWeekday, + "A": formatUTCWeekday, + "b": formatUTCShortMonth, + "B": formatUTCMonth, + "c": null, + "d": formatUTCDayOfMonth, + "e": formatUTCDayOfMonth, + "f": formatUTCMicroseconds, + "g": formatUTCYearISO, + "G": formatUTCFullYearISO, + "H": formatUTCHour24, + "I": formatUTCHour12, + "j": formatUTCDayOfYear, + "L": formatUTCMilliseconds, + "m": formatUTCMonthNumber, + "M": formatUTCMinutes, + "p": formatUTCPeriod, + "q": formatUTCQuarter, + "Q": formatUnixTimestamp, + "s": formatUnixTimestampSeconds, + "S": formatUTCSeconds, + "u": formatUTCWeekdayNumberMonday, + "U": formatUTCWeekNumberSunday, + "V": formatUTCWeekNumberISO, + "w": formatUTCWeekdayNumberSunday, + "W": formatUTCWeekNumberMonday, + "x": null, + "X": null, + "y": formatUTCYear, + "Y": formatUTCFullYear, + "Z": formatUTCZone, + "%": formatLiteralPercent + }; + + var parses = { + "a": parseShortWeekday, + "A": parseWeekday, + "b": parseShortMonth, + "B": parseMonth, + "c": parseLocaleDateTime, + "d": parseDayOfMonth, + "e": parseDayOfMonth, + "f": parseMicroseconds, + "g": parseYear, + "G": parseFullYear, + "H": parseHour24, + "I": parseHour24, + "j": parseDayOfYear, + "L": parseMilliseconds, + "m": parseMonthNumber, + "M": parseMinutes, + "p": parsePeriod, + "q": parseQuarter, + "Q": parseUnixTimestamp, + "s": parseUnixTimestampSeconds, + "S": parseSeconds, + "u": parseWeekdayNumberMonday, + "U": parseWeekNumberSunday, + "V": parseWeekNumberISO, + "w": parseWeekdayNumberSunday, + "W": parseWeekNumberMonday, + "x": parseLocaleDate, + "X": parseLocaleTime, + "y": parseYear, + "Y": parseFullYear, + "Z": parseZone, + "%": parseLiteralPercent + }; + + // These recursive directive definitions must be deferred. + formats.x = newFormat(locale_date, formats); + formats.X = newFormat(locale_time, formats); + formats.c = newFormat(locale_dateTime, formats); + utcFormats.x = newFormat(locale_date, utcFormats); + utcFormats.X = newFormat(locale_time, utcFormats); + utcFormats.c = newFormat(locale_dateTime, utcFormats); + + function newFormat(specifier, formats) { + return function(date) { + var string = [], + i = -1, + j = 0, + n = specifier.length, + c, + pad, + format; + + if (!(date instanceof Date)) date = new Date(+date); + + while (++i < n) { + if (specifier.charCodeAt(i) === 37) { + string.push(specifier.slice(j, i)); + if ((pad = pads[c = specifier.charAt(++i)]) != null) c = specifier.charAt(++i); + else pad = c === "e" ? " " : "0"; + if (format = formats[c]) c = format(date, pad); + string.push(c); + j = i + 1; + } + } + + string.push(specifier.slice(j, i)); + return string.join(""); + }; + } + + function newParse(specifier, Z) { + return function(string) { + var d = newDate(1900, undefined, 1), + i = parseSpecifier(d, specifier, string += "", 0), + week, day; + if (i != string.length) return null; + + // If a UNIX timestamp is specified, return it. + if ("Q" in d) return new Date(d.Q); + if ("s" in d) return new Date(d.s * 1000 + ("L" in d ? d.L : 0)); + + // If this is utcParse, never use the local timezone. + if (Z && !("Z" in d)) d.Z = 0; + + // The am-pm flag is 0 for AM, and 1 for PM. + if ("p" in d) d.H = d.H % 12 + d.p * 12; + + // If the month was not specified, inherit from the quarter. + if (d.m === undefined) d.m = "q" in d ? d.q : 0; + + // Convert day-of-week and week-of-year to day-of-year. + if ("V" in d) { + if (d.V < 1 || d.V > 53) return null; + if (!("w" in d)) d.w = 1; + if ("Z" in d) { + week = utcDate(newDate(d.y, 0, 1)), day = week.getUTCDay(); + week = day > 4 || day === 0 ? utcMonday.ceil(week) : utcMonday(week); + week = utcDay$1.offset(week, (d.V - 1) * 7); + d.y = week.getUTCFullYear(); + d.m = week.getUTCMonth(); + d.d = week.getUTCDate() + (d.w + 6) % 7; + } else { + week = localDate(newDate(d.y, 0, 1)), day = week.getDay(); + week = day > 4 || day === 0 ? monday.ceil(week) : monday(week); + week = timeDay.offset(week, (d.V - 1) * 7); + d.y = week.getFullYear(); + d.m = week.getMonth(); + d.d = week.getDate() + (d.w + 6) % 7; + } + } else if ("W" in d || "U" in d) { + if (!("w" in d)) d.w = "u" in d ? d.u % 7 : "W" in d ? 1 : 0; + day = "Z" in d ? utcDate(newDate(d.y, 0, 1)).getUTCDay() : localDate(newDate(d.y, 0, 1)).getDay(); + d.m = 0; + d.d = "W" in d ? (d.w + 6) % 7 + d.W * 7 - (day + 5) % 7 : d.w + d.U * 7 - (day + 6) % 7; + } + + // If a time zone is specified, all fields are interpreted as UTC and then + // offset according to the specified time zone. + if ("Z" in d) { + d.H += d.Z / 100 | 0; + d.M += d.Z % 100; + return utcDate(d); + } + + // Otherwise, all fields are in local time. + return localDate(d); + }; + } + + function parseSpecifier(d, specifier, string, j) { + var i = 0, + n = specifier.length, + m = string.length, + c, + parse; + + while (i < n) { + if (j >= m) return -1; + c = specifier.charCodeAt(i++); + if (c === 37) { + c = specifier.charAt(i++); + parse = parses[c in pads ? specifier.charAt(i++) : c]; + if (!parse || ((j = parse(d, string, j)) < 0)) return -1; + } else if (c != string.charCodeAt(j++)) { + return -1; + } + } + + return j; + } + + function parsePeriod(d, string, i) { + var n = periodRe.exec(string.slice(i)); + return n ? (d.p = periodLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + + function parseShortWeekday(d, string, i) { + var n = shortWeekdayRe.exec(string.slice(i)); + return n ? (d.w = shortWeekdayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + + function parseWeekday(d, string, i) { + var n = weekdayRe.exec(string.slice(i)); + return n ? (d.w = weekdayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + + function parseShortMonth(d, string, i) { + var n = shortMonthRe.exec(string.slice(i)); + return n ? (d.m = shortMonthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + + function parseMonth(d, string, i) { + var n = monthRe.exec(string.slice(i)); + return n ? (d.m = monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + + function parseLocaleDateTime(d, string, i) { + return parseSpecifier(d, locale_dateTime, string, i); + } + + function parseLocaleDate(d, string, i) { + return parseSpecifier(d, locale_date, string, i); + } + + function parseLocaleTime(d, string, i) { + return parseSpecifier(d, locale_time, string, i); + } + + function formatShortWeekday(d) { + return locale_shortWeekdays[d.getDay()]; + } + + function formatWeekday(d) { + return locale_weekdays[d.getDay()]; + } + + function formatShortMonth(d) { + return locale_shortMonths[d.getMonth()]; + } + + function formatMonth(d) { + return locale_months[d.getMonth()]; + } + + function formatPeriod(d) { + return locale_periods[+(d.getHours() >= 12)]; + } + + function formatQuarter(d) { + return 1 + ~~(d.getMonth() / 3); + } + + function formatUTCShortWeekday(d) { + return locale_shortWeekdays[d.getUTCDay()]; + } + + function formatUTCWeekday(d) { + return locale_weekdays[d.getUTCDay()]; + } + + function formatUTCShortMonth(d) { + return locale_shortMonths[d.getUTCMonth()]; + } + + function formatUTCMonth(d) { + return locale_months[d.getUTCMonth()]; + } + + function formatUTCPeriod(d) { + return locale_periods[+(d.getUTCHours() >= 12)]; + } + + function formatUTCQuarter(d) { + return 1 + ~~(d.getUTCMonth() / 3); + } + + return { + format: function(specifier) { + var f = newFormat(specifier += "", formats); + f.toString = function() { return specifier; }; + return f; + }, + parse: function(specifier) { + var p = newParse(specifier += "", false); + p.toString = function() { return specifier; }; + return p; + }, + utcFormat: function(specifier) { + var f = newFormat(specifier += "", utcFormats); + f.toString = function() { return specifier; }; + return f; + }, + utcParse: function(specifier) { + var p = newParse(specifier += "", true); + p.toString = function() { return specifier; }; + return p; + } + }; +} + +var pads = {"-": "", "_": " ", "0": "0"}, + numberRe = /^\s*\d+/, // note: ignores next directive + percentRe = /^%/, + requoteRe = /[\\^$*+?|[\]().{}]/g; + +function pad(value, fill, width) { + var sign = value < 0 ? "-" : "", + string = (sign ? -value : value) + "", + length = string.length; + return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string); +} + +function requote(s) { + return s.replace(requoteRe, "\\$&"); +} + +function formatRe(names) { + return new RegExp("^(?:" + names.map(requote).join("|") + ")", "i"); +} + +function formatLookup(names) { + return new Map(names.map((name, i) => [name.toLowerCase(), i])); +} + +function parseWeekdayNumberSunday(d, string, i) { + var n = numberRe.exec(string.slice(i, i + 1)); + return n ? (d.w = +n[0], i + n[0].length) : -1; +} + +function parseWeekdayNumberMonday(d, string, i) { + var n = numberRe.exec(string.slice(i, i + 1)); + return n ? (d.u = +n[0], i + n[0].length) : -1; +} + +function parseWeekNumberSunday(d, string, i) { + var n = numberRe.exec(string.slice(i, i + 2)); + return n ? (d.U = +n[0], i + n[0].length) : -1; +} + +function parseWeekNumberISO(d, string, i) { + var n = numberRe.exec(string.slice(i, i + 2)); + return n ? (d.V = +n[0], i + n[0].length) : -1; +} + +function parseWeekNumberMonday(d, string, i) { + var n = numberRe.exec(string.slice(i, i + 2)); + return n ? (d.W = +n[0], i + n[0].length) : -1; +} + +function parseFullYear(d, string, i) { + var n = numberRe.exec(string.slice(i, i + 4)); + return n ? (d.y = +n[0], i + n[0].length) : -1; +} + +function parseYear(d, string, i) { + var n = numberRe.exec(string.slice(i, i + 2)); + return n ? (d.y = +n[0] + (+n[0] > 68 ? 1900 : 2000), i + n[0].length) : -1; +} + +function parseZone(d, string, i) { + var n = /^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(string.slice(i, i + 6)); + return n ? (d.Z = n[1] ? 0 : -(n[2] + (n[3] || "00")), i + n[0].length) : -1; +} + +function parseQuarter(d, string, i) { + var n = numberRe.exec(string.slice(i, i + 1)); + return n ? (d.q = n[0] * 3 - 3, i + n[0].length) : -1; +} + +function parseMonthNumber(d, string, i) { + var n = numberRe.exec(string.slice(i, i + 2)); + return n ? (d.m = n[0] - 1, i + n[0].length) : -1; +} + +function parseDayOfMonth(d, string, i) { + var n = numberRe.exec(string.slice(i, i + 2)); + return n ? (d.d = +n[0], i + n[0].length) : -1; +} + +function parseDayOfYear(d, string, i) { + var n = numberRe.exec(string.slice(i, i + 3)); + return n ? (d.m = 0, d.d = +n[0], i + n[0].length) : -1; +} + +function parseHour24(d, string, i) { + var n = numberRe.exec(string.slice(i, i + 2)); + return n ? (d.H = +n[0], i + n[0].length) : -1; +} + +function parseMinutes(d, string, i) { + var n = numberRe.exec(string.slice(i, i + 2)); + return n ? (d.M = +n[0], i + n[0].length) : -1; +} + +function parseSeconds(d, string, i) { + var n = numberRe.exec(string.slice(i, i + 2)); + return n ? (d.S = +n[0], i + n[0].length) : -1; +} + +function parseMilliseconds(d, string, i) { + var n = numberRe.exec(string.slice(i, i + 3)); + return n ? (d.L = +n[0], i + n[0].length) : -1; +} + +function parseMicroseconds(d, string, i) { + var n = numberRe.exec(string.slice(i, i + 6)); + return n ? (d.L = Math.floor(n[0] / 1000), i + n[0].length) : -1; +} + +function parseLiteralPercent(d, string, i) { + var n = percentRe.exec(string.slice(i, i + 1)); + return n ? i + n[0].length : -1; +} + +function parseUnixTimestamp(d, string, i) { + var n = numberRe.exec(string.slice(i)); + return n ? (d.Q = +n[0], i + n[0].length) : -1; +} + +function parseUnixTimestampSeconds(d, string, i) { + var n = numberRe.exec(string.slice(i)); + return n ? (d.s = +n[0], i + n[0].length) : -1; +} + +function formatDayOfMonth(d, p) { + return pad(d.getDate(), p, 2); +} + +function formatHour24(d, p) { + return pad(d.getHours(), p, 2); +} + +function formatHour12(d, p) { + return pad(d.getHours() % 12 || 12, p, 2); +} + +function formatDayOfYear(d, p) { + return pad(1 + timeDay.count(timeYear(d), d), p, 3); +} + +function formatMilliseconds(d, p) { + return pad(d.getMilliseconds(), p, 3); +} + +function formatMicroseconds(d, p) { + return formatMilliseconds(d, p) + "000"; +} + +function formatMonthNumber(d, p) { + return pad(d.getMonth() + 1, p, 2); +} + +function formatMinutes(d, p) { + return pad(d.getMinutes(), p, 2); +} + +function formatSeconds(d, p) { + return pad(d.getSeconds(), p, 2); +} + +function formatWeekdayNumberMonday(d) { + var day = d.getDay(); + return day === 0 ? 7 : day; +} + +function formatWeekNumberSunday(d, p) { + return pad(sunday.count(timeYear(d) - 1, d), p, 2); +} + +function dISO(d) { + var day = d.getDay(); + return (day >= 4 || day === 0) ? thursday(d) : thursday.ceil(d); +} + +function formatWeekNumberISO(d, p) { + d = dISO(d); + return pad(thursday.count(timeYear(d), d) + (timeYear(d).getDay() === 4), p, 2); +} + +function formatWeekdayNumberSunday(d) { + return d.getDay(); +} + +function formatWeekNumberMonday(d, p) { + return pad(monday.count(timeYear(d) - 1, d), p, 2); +} + +function formatYear(d, p) { + return pad(d.getFullYear() % 100, p, 2); +} + +function formatYearISO(d, p) { + d = dISO(d); + return pad(d.getFullYear() % 100, p, 2); +} + +function formatFullYear(d, p) { + return pad(d.getFullYear() % 10000, p, 4); +} + +function formatFullYearISO(d, p) { + var day = d.getDay(); + d = (day >= 4 || day === 0) ? thursday(d) : thursday.ceil(d); + return pad(d.getFullYear() % 10000, p, 4); +} + +function formatZone(d) { + var z = d.getTimezoneOffset(); + return (z > 0 ? "-" : (z *= -1, "+")) + + pad(z / 60 | 0, "0", 2) + + pad(z % 60, "0", 2); +} + +function formatUTCDayOfMonth(d, p) { + return pad(d.getUTCDate(), p, 2); +} + +function formatUTCHour24(d, p) { + return pad(d.getUTCHours(), p, 2); +} + +function formatUTCHour12(d, p) { + return pad(d.getUTCHours() % 12 || 12, p, 2); +} + +function formatUTCDayOfYear(d, p) { + return pad(1 + utcDay$1.count(utcYear$1(d), d), p, 3); +} + +function formatUTCMilliseconds(d, p) { + return pad(d.getUTCMilliseconds(), p, 3); +} + +function formatUTCMicroseconds(d, p) { + return formatUTCMilliseconds(d, p) + "000"; +} + +function formatUTCMonthNumber(d, p) { + return pad(d.getUTCMonth() + 1, p, 2); +} + +function formatUTCMinutes(d, p) { + return pad(d.getUTCMinutes(), p, 2); +} + +function formatUTCSeconds(d, p) { + return pad(d.getUTCSeconds(), p, 2); +} + +function formatUTCWeekdayNumberMonday(d) { + var dow = d.getUTCDay(); + return dow === 0 ? 7 : dow; +} + +function formatUTCWeekNumberSunday(d, p) { + return pad(utcSunday.count(utcYear$1(d) - 1, d), p, 2); +} + +function UTCdISO(d) { + var day = d.getUTCDay(); + return (day >= 4 || day === 0) ? utcThursday(d) : utcThursday.ceil(d); +} + +function formatUTCWeekNumberISO(d, p) { + d = UTCdISO(d); + return pad(utcThursday.count(utcYear$1(d), d) + (utcYear$1(d).getUTCDay() === 4), p, 2); +} + +function formatUTCWeekdayNumberSunday(d) { + return d.getUTCDay(); +} + +function formatUTCWeekNumberMonday(d, p) { + return pad(utcMonday.count(utcYear$1(d) - 1, d), p, 2); +} + +function formatUTCYear(d, p) { + return pad(d.getUTCFullYear() % 100, p, 2); +} + +function formatUTCYearISO(d, p) { + d = UTCdISO(d); + return pad(d.getUTCFullYear() % 100, p, 2); +} + +function formatUTCFullYear(d, p) { + return pad(d.getUTCFullYear() % 10000, p, 4); +} + +function formatUTCFullYearISO(d, p) { + var day = d.getUTCDay(); + d = (day >= 4 || day === 0) ? utcThursday(d) : utcThursday.ceil(d); + return pad(d.getUTCFullYear() % 10000, p, 4); +} + +function formatUTCZone() { + return "+0000"; +} + +function formatLiteralPercent() { + return "%"; +} + +function formatUnixTimestamp(d) { + return +d; +} + +function formatUnixTimestampSeconds(d) { + return Math.floor(+d / 1000); +} + +var locale; +exports.timeFormat = void 0; +exports.timeParse = void 0; +exports.utcFormat = void 0; +exports.utcParse = void 0; + +defaultLocale({ + dateTime: "%x, %X", + date: "%-m/%-d/%Y", + time: "%-I:%M:%S %p", + periods: ["AM", "PM"], + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + shortDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] +}); + +function defaultLocale(definition) { + locale = formatLocale(definition); + exports.timeFormat = locale.format; + exports.timeParse = locale.parse; + exports.utcFormat = locale.utcFormat; + exports.utcParse = locale.utcParse; + return locale; +} + +var isoSpecifier = "%Y-%m-%dT%H:%M:%S.%LZ"; + +function formatIsoNative(date) { + return date.toISOString(); +} + +var formatIso = Date.prototype.toISOString + ? formatIsoNative + : exports.utcFormat(isoSpecifier); + +var formatIso$1 = formatIso; + +function parseIsoNative(string) { + var date = new Date(string); + return isNaN(date) ? null : date; +} + +var parseIso = +new Date("2000-01-01T00:00:00.000Z") + ? parseIsoNative + : exports.utcParse(isoSpecifier); + +var parseIso$1 = parseIso; + +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(timeTicks, timeTickInterval, timeYear, timeMonth, sunday, timeDay, timeHour, timeMinute, utcSecond, exports.timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]), arguments); +} + +function utcTime() { + return initRange.apply(calendar(utcTicks, utcTickInterval, utcYear$1, utcMonth$1, utcSunday, utcDay$1, utcHour$1, utcMinute$1, utcSecond, exports.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$3, + 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(interpolate$2); + + scale.rangeRound = range(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$3)); + + 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$3; + + function scale(x) { + if (x != null && !isNaN(x = +x)) return interpolator((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(ascending$3); + 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) => quantile$1(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$3, + 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 = piecewise(interpolate, [r0, r1, r2]), scale) : [interpolator(0), interpolator(0.5), interpolator(1)]; + }; + } + + scale.range = range(interpolate$2); + + scale.rangeRound = range(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$1() { + var scale = linearish(transformer()(identity$3)); + + scale.copy = function() { + return copy(scale, diverging$1()); + }; + + 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); +} + +function colors(specifier) { + var n = specifier.length / 6 | 0, colors = new Array(n), i = 0; + while (i < n) colors[i] = "#" + specifier.slice(i * 6, ++i * 6); + return colors; +} + +var category10 = colors("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf"); + +var Accent = colors("7fc97fbeaed4fdc086ffff99386cb0f0027fbf5b17666666"); + +var Dark2 = colors("1b9e77d95f027570b3e7298a66a61ee6ab02a6761d666666"); + +var Paired = colors("a6cee31f78b4b2df8a33a02cfb9a99e31a1cfdbf6fff7f00cab2d66a3d9affff99b15928"); + +var Pastel1 = colors("fbb4aeb3cde3ccebc5decbe4fed9a6ffffcce5d8bdfddaecf2f2f2"); + +var Pastel2 = colors("b3e2cdfdcdaccbd5e8f4cae4e6f5c9fff2aef1e2cccccccc"); + +var Set1 = colors("e41a1c377eb84daf4a984ea3ff7f00ffff33a65628f781bf999999"); + +var Set2 = colors("66c2a5fc8d628da0cbe78ac3a6d854ffd92fe5c494b3b3b3"); + +var Set3 = colors("8dd3c7ffffb3bebadafb807280b1d3fdb462b3de69fccde5d9d9d9bc80bdccebc5ffed6f"); + +var Tableau10 = colors("4e79a7f28e2ce1575976b7b259a14fedc949af7aa1ff9da79c755fbab0ab"); + +var ramp$1 = scheme => rgbBasis(scheme[scheme.length - 1]); + +var scheme$q = new Array(3).concat( + "d8b365f5f5f55ab4ac", + "a6611adfc27d80cdc1018571", + "a6611adfc27df5f5f580cdc1018571", + "8c510ad8b365f6e8c3c7eae55ab4ac01665e", + "8c510ad8b365f6e8c3f5f5f5c7eae55ab4ac01665e", + "8c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e", + "8c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e", + "5430058c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e003c30", + "5430058c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e003c30" +).map(colors); + +var BrBG = ramp$1(scheme$q); + +var scheme$p = new Array(3).concat( + "af8dc3f7f7f77fbf7b", + "7b3294c2a5cfa6dba0008837", + "7b3294c2a5cff7f7f7a6dba0008837", + "762a83af8dc3e7d4e8d9f0d37fbf7b1b7837", + "762a83af8dc3e7d4e8f7f7f7d9f0d37fbf7b1b7837", + "762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b7837", + "762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b7837", + "40004b762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b783700441b", + "40004b762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b783700441b" +).map(colors); + +var PRGn = ramp$1(scheme$p); + +var scheme$o = new Array(3).concat( + "e9a3c9f7f7f7a1d76a", + "d01c8bf1b6dab8e1864dac26", + "d01c8bf1b6daf7f7f7b8e1864dac26", + "c51b7de9a3c9fde0efe6f5d0a1d76a4d9221", + "c51b7de9a3c9fde0eff7f7f7e6f5d0a1d76a4d9221", + "c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221", + "c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221", + "8e0152c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221276419", + "8e0152c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221276419" +).map(colors); + +var PiYG = ramp$1(scheme$o); + +var scheme$n = new Array(3).concat( + "998ec3f7f7f7f1a340", + "5e3c99b2abd2fdb863e66101", + "5e3c99b2abd2f7f7f7fdb863e66101", + "542788998ec3d8daebfee0b6f1a340b35806", + "542788998ec3d8daebf7f7f7fee0b6f1a340b35806", + "5427888073acb2abd2d8daebfee0b6fdb863e08214b35806", + "5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b35806", + "2d004b5427888073acb2abd2d8daebfee0b6fdb863e08214b358067f3b08", + "2d004b5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b358067f3b08" +).map(colors); + +var PuOr = ramp$1(scheme$n); + +var scheme$m = new Array(3).concat( + "ef8a62f7f7f767a9cf", + "ca0020f4a58292c5de0571b0", + "ca0020f4a582f7f7f792c5de0571b0", + "b2182bef8a62fddbc7d1e5f067a9cf2166ac", + "b2182bef8a62fddbc7f7f7f7d1e5f067a9cf2166ac", + "b2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac", + "b2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac", + "67001fb2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac053061", + "67001fb2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac053061" +).map(colors); + +var RdBu = ramp$1(scheme$m); + +var scheme$l = new Array(3).concat( + "ef8a62ffffff999999", + "ca0020f4a582bababa404040", + "ca0020f4a582ffffffbababa404040", + "b2182bef8a62fddbc7e0e0e09999994d4d4d", + "b2182bef8a62fddbc7ffffffe0e0e09999994d4d4d", + "b2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d", + "b2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d", + "67001fb2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d1a1a1a", + "67001fb2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d1a1a1a" +).map(colors); + +var RdGy = ramp$1(scheme$l); + +var scheme$k = new Array(3).concat( + "fc8d59ffffbf91bfdb", + "d7191cfdae61abd9e92c7bb6", + "d7191cfdae61ffffbfabd9e92c7bb6", + "d73027fc8d59fee090e0f3f891bfdb4575b4", + "d73027fc8d59fee090ffffbfe0f3f891bfdb4575b4", + "d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4", + "d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4", + "a50026d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4313695", + "a50026d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4313695" +).map(colors); + +var RdYlBu = ramp$1(scheme$k); + +var scheme$j = new Array(3).concat( + "fc8d59ffffbf91cf60", + "d7191cfdae61a6d96a1a9641", + "d7191cfdae61ffffbfa6d96a1a9641", + "d73027fc8d59fee08bd9ef8b91cf601a9850", + "d73027fc8d59fee08bffffbfd9ef8b91cf601a9850", + "d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850", + "d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850", + "a50026d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850006837", + "a50026d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850006837" +).map(colors); + +var RdYlGn = ramp$1(scheme$j); + +var scheme$i = new Array(3).concat( + "fc8d59ffffbf99d594", + "d7191cfdae61abdda42b83ba", + "d7191cfdae61ffffbfabdda42b83ba", + "d53e4ffc8d59fee08be6f59899d5943288bd", + "d53e4ffc8d59fee08bffffbfe6f59899d5943288bd", + "d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd", + "d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd", + "9e0142d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd5e4fa2", + "9e0142d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd5e4fa2" +).map(colors); + +var Spectral = ramp$1(scheme$i); + +var scheme$h = new Array(3).concat( + "e5f5f999d8c92ca25f", + "edf8fbb2e2e266c2a4238b45", + "edf8fbb2e2e266c2a42ca25f006d2c", + "edf8fbccece699d8c966c2a42ca25f006d2c", + "edf8fbccece699d8c966c2a441ae76238b45005824", + "f7fcfde5f5f9ccece699d8c966c2a441ae76238b45005824", + "f7fcfde5f5f9ccece699d8c966c2a441ae76238b45006d2c00441b" +).map(colors); + +var BuGn = ramp$1(scheme$h); + +var scheme$g = new Array(3).concat( + "e0ecf49ebcda8856a7", + "edf8fbb3cde38c96c688419d", + "edf8fbb3cde38c96c68856a7810f7c", + "edf8fbbfd3e69ebcda8c96c68856a7810f7c", + "edf8fbbfd3e69ebcda8c96c68c6bb188419d6e016b", + "f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d6e016b", + "f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d810f7c4d004b" +).map(colors); + +var BuPu = ramp$1(scheme$g); + +var scheme$f = new Array(3).concat( + "e0f3dba8ddb543a2ca", + "f0f9e8bae4bc7bccc42b8cbe", + "f0f9e8bae4bc7bccc443a2ca0868ac", + "f0f9e8ccebc5a8ddb57bccc443a2ca0868ac", + "f0f9e8ccebc5a8ddb57bccc44eb3d32b8cbe08589e", + "f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe08589e", + "f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe0868ac084081" +).map(colors); + +var GnBu = ramp$1(scheme$f); + +var scheme$e = new Array(3).concat( + "fee8c8fdbb84e34a33", + "fef0d9fdcc8afc8d59d7301f", + "fef0d9fdcc8afc8d59e34a33b30000", + "fef0d9fdd49efdbb84fc8d59e34a33b30000", + "fef0d9fdd49efdbb84fc8d59ef6548d7301f990000", + "fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301f990000", + "fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301fb300007f0000" +).map(colors); + +var OrRd = ramp$1(scheme$e); + +var scheme$d = new Array(3).concat( + "ece2f0a6bddb1c9099", + "f6eff7bdc9e167a9cf02818a", + "f6eff7bdc9e167a9cf1c9099016c59", + "f6eff7d0d1e6a6bddb67a9cf1c9099016c59", + "f6eff7d0d1e6a6bddb67a9cf3690c002818a016450", + "fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016450", + "fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016c59014636" +).map(colors); + +var PuBuGn = ramp$1(scheme$d); + +var scheme$c = new Array(3).concat( + "ece7f2a6bddb2b8cbe", + "f1eef6bdc9e174a9cf0570b0", + "f1eef6bdc9e174a9cf2b8cbe045a8d", + "f1eef6d0d1e6a6bddb74a9cf2b8cbe045a8d", + "f1eef6d0d1e6a6bddb74a9cf3690c00570b0034e7b", + "fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0034e7b", + "fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0045a8d023858" +).map(colors); + +var PuBu = ramp$1(scheme$c); + +var scheme$b = new Array(3).concat( + "e7e1efc994c7dd1c77", + "f1eef6d7b5d8df65b0ce1256", + "f1eef6d7b5d8df65b0dd1c77980043", + "f1eef6d4b9dac994c7df65b0dd1c77980043", + "f1eef6d4b9dac994c7df65b0e7298ace125691003f", + "f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125691003f", + "f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125698004367001f" +).map(colors); + +var PuRd = ramp$1(scheme$b); + +var scheme$a = new Array(3).concat( + "fde0ddfa9fb5c51b8a", + "feebe2fbb4b9f768a1ae017e", + "feebe2fbb4b9f768a1c51b8a7a0177", + "feebe2fcc5c0fa9fb5f768a1c51b8a7a0177", + "feebe2fcc5c0fa9fb5f768a1dd3497ae017e7a0177", + "fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a0177", + "fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a017749006a" +).map(colors); + +var RdPu = ramp$1(scheme$a); + +var scheme$9 = new Array(3).concat( + "edf8b17fcdbb2c7fb8", + "ffffcca1dab441b6c4225ea8", + "ffffcca1dab441b6c42c7fb8253494", + "ffffccc7e9b47fcdbb41b6c42c7fb8253494", + "ffffccc7e9b47fcdbb41b6c41d91c0225ea80c2c84", + "ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea80c2c84", + "ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea8253494081d58" +).map(colors); + +var YlGnBu = ramp$1(scheme$9); + +var scheme$8 = new Array(3).concat( + "f7fcb9addd8e31a354", + "ffffccc2e69978c679238443", + "ffffccc2e69978c67931a354006837", + "ffffccd9f0a3addd8e78c67931a354006837", + "ffffccd9f0a3addd8e78c67941ab5d238443005a32", + "ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443005a32", + "ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443006837004529" +).map(colors); + +var YlGn = ramp$1(scheme$8); + +var scheme$7 = new Array(3).concat( + "fff7bcfec44fd95f0e", + "ffffd4fed98efe9929cc4c02", + "ffffd4fed98efe9929d95f0e993404", + "ffffd4fee391fec44ffe9929d95f0e993404", + "ffffd4fee391fec44ffe9929ec7014cc4c028c2d04", + "ffffe5fff7bcfee391fec44ffe9929ec7014cc4c028c2d04", + "ffffe5fff7bcfee391fec44ffe9929ec7014cc4c02993404662506" +).map(colors); + +var YlOrBr = ramp$1(scheme$7); + +var scheme$6 = new Array(3).concat( + "ffeda0feb24cf03b20", + "ffffb2fecc5cfd8d3ce31a1c", + "ffffb2fecc5cfd8d3cf03b20bd0026", + "ffffb2fed976feb24cfd8d3cf03b20bd0026", + "ffffb2fed976feb24cfd8d3cfc4e2ae31a1cb10026", + "ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cb10026", + "ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cbd0026800026" +).map(colors); + +var YlOrRd = ramp$1(scheme$6); + +var scheme$5 = new Array(3).concat( + "deebf79ecae13182bd", + "eff3ffbdd7e76baed62171b5", + "eff3ffbdd7e76baed63182bd08519c", + "eff3ffc6dbef9ecae16baed63182bd08519c", + "eff3ffc6dbef9ecae16baed64292c62171b5084594", + "f7fbffdeebf7c6dbef9ecae16baed64292c62171b5084594", + "f7fbffdeebf7c6dbef9ecae16baed64292c62171b508519c08306b" +).map(colors); + +var Blues = ramp$1(scheme$5); + +var scheme$4 = new Array(3).concat( + "e5f5e0a1d99b31a354", + "edf8e9bae4b374c476238b45", + "edf8e9bae4b374c47631a354006d2c", + "edf8e9c7e9c0a1d99b74c47631a354006d2c", + "edf8e9c7e9c0a1d99b74c47641ab5d238b45005a32", + "f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45005a32", + "f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45006d2c00441b" +).map(colors); + +var Greens = ramp$1(scheme$4); + +var scheme$3 = new Array(3).concat( + "f0f0f0bdbdbd636363", + "f7f7f7cccccc969696525252", + "f7f7f7cccccc969696636363252525", + "f7f7f7d9d9d9bdbdbd969696636363252525", + "f7f7f7d9d9d9bdbdbd969696737373525252252525", + "fffffff0f0f0d9d9d9bdbdbd969696737373525252252525", + "fffffff0f0f0d9d9d9bdbdbd969696737373525252252525000000" +).map(colors); + +var Greys = ramp$1(scheme$3); + +var scheme$2 = new Array(3).concat( + "efedf5bcbddc756bb1", + "f2f0f7cbc9e29e9ac86a51a3", + "f2f0f7cbc9e29e9ac8756bb154278f", + "f2f0f7dadaebbcbddc9e9ac8756bb154278f", + "f2f0f7dadaebbcbddc9e9ac8807dba6a51a34a1486", + "fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a34a1486", + "fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a354278f3f007d" +).map(colors); + +var Purples = ramp$1(scheme$2); + +var scheme$1 = new Array(3).concat( + "fee0d2fc9272de2d26", + "fee5d9fcae91fb6a4acb181d", + "fee5d9fcae91fb6a4ade2d26a50f15", + "fee5d9fcbba1fc9272fb6a4ade2d26a50f15", + "fee5d9fcbba1fc9272fb6a4aef3b2ccb181d99000d", + "fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181d99000d", + "fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181da50f1567000d" +).map(colors); + +var Reds = ramp$1(scheme$1); + +var scheme = new Array(3).concat( + "fee6cefdae6be6550d", + "feeddefdbe85fd8d3cd94701", + "feeddefdbe85fd8d3ce6550da63603", + "feeddefdd0a2fdae6bfd8d3ce6550da63603", + "feeddefdd0a2fdae6bfd8d3cf16913d948018c2d04", + "fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d948018c2d04", + "fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d94801a636037f2704" +).map(colors); + +var Oranges = ramp$1(scheme); + +function cividis(t) { + t = Math.max(0, Math.min(1, t)); + return "rgb(" + + Math.max(0, Math.min(255, Math.round(-4.54 - t * (35.34 - t * (2381.73 - t * (6402.7 - t * (7024.72 - t * 2710.57))))))) + ", " + + Math.max(0, Math.min(255, Math.round(32.49 + t * (170.73 + t * (52.82 - t * (131.46 - t * (176.58 - t * 67.37))))))) + ", " + + Math.max(0, Math.min(255, Math.round(81.24 + t * (442.36 - t * (2482.43 - t * (6167.24 - t * (6614.94 - t * 2475.67))))))) + + ")"; +} + +var cubehelix = cubehelixLong(cubehelix$3(300, 0.5, 0.0), cubehelix$3(-240, 0.5, 1.0)); + +var warm = cubehelixLong(cubehelix$3(-100, 0.75, 0.35), cubehelix$3(80, 1.50, 0.8)); + +var cool = cubehelixLong(cubehelix$3(260, 0.75, 0.35), cubehelix$3(80, 1.50, 0.8)); + +var c$2 = cubehelix$3(); + +function rainbow(t) { + if (t < 0 || t > 1) t -= Math.floor(t); + var ts = Math.abs(t - 0.5); + c$2.h = 360 * t - 100; + c$2.s = 1.5 - 1.5 * ts; + c$2.l = 0.8 - 0.9 * ts; + return c$2 + ""; +} + +var c$1 = rgb(), + pi_1_3 = Math.PI / 3, + pi_2_3 = Math.PI * 2 / 3; + +function sinebow(t) { + var x; + t = (0.5 - t) * Math.PI; + c$1.r = 255 * (x = Math.sin(t)) * x; + c$1.g = 255 * (x = Math.sin(t + pi_1_3)) * x; + c$1.b = 255 * (x = Math.sin(t + pi_2_3)) * x; + return c$1 + ""; +} + +function turbo(t) { + t = Math.max(0, Math.min(1, t)); + return "rgb(" + + Math.max(0, Math.min(255, Math.round(34.61 + t * (1172.33 - t * (10793.56 - t * (33300.12 - t * (38394.49 - t * 14825.05))))))) + ", " + + Math.max(0, Math.min(255, Math.round(23.31 + t * (557.33 + t * (1225.33 - t * (3574.96 - t * (1073.77 + t * 707.56))))))) + ", " + + Math.max(0, Math.min(255, Math.round(27.2 + t * (3211.1 - t * (15327.97 - t * (27814 - t * (22569.18 - t * 6838.66))))))) + + ")"; +} + +function ramp(range) { + var n = range.length; + return function(t) { + return range[Math.max(0, Math.min(n - 1, Math.floor(t * n)))]; + }; +} + +var viridis = ramp(colors("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")); + +var magma = ramp(colors("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")); + +var inferno = ramp(colors("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")); + +var plasma = ramp(colors("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921")); + +function constant$1(x) { + return function constant() { + return x; + }; +} + +var abs = Math.abs; +var atan2 = Math.atan2; +var cos = Math.cos; +var max = Math.max; +var min = Math.min; +var sin = Math.sin; +var sqrt = Math.sqrt; + +var epsilon = 1e-12; +var pi = Math.PI; +var halfPi = pi / 2; +var 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 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$1(0), + padRadius = null, + startAngle = arcStartAngle, + endAngle = arcEndAngle, + padAngle = arcPadAngle, + context = null; + + 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 (da < pi && (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)); + } + } + + // 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$1(+_), arc) : innerRadius; + }; + + arc.outerRadius = function(_) { + return arguments.length ? (outerRadius = typeof _ === "function" ? _ : constant$1(+_), arc) : outerRadius; + }; + + arc.cornerRadius = function(_) { + return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant$1(+_), arc) : cornerRadius; + }; + + arc.padRadius = function(_) { + return arguments.length ? (padRadius = _ == null ? null : typeof _ === "function" ? _ : constant$1(+_), arc) : padRadius; + }; + + arc.startAngle = function(_) { + return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$1(+_), arc) : startAngle; + }; + + arc.endAngle = function(_) { + return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$1(+_), arc) : endAngle; + }; + + arc.padAngle = function(_) { + return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$1(+_), 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$1(true), + context = null, + curve = curveLinear, + output = null; + + x$1 = typeof x$1 === "function" ? x$1 : (x$1 === undefined) ? x : constant$1(x$1); + y$1 = typeof y$1 === "function" ? y$1 : (y$1 === undefined) ? y : constant$1(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$1(+_), line) : x$1; + }; + + line.y = function(_) { + return arguments.length ? (y$1 = typeof _ === "function" ? _ : constant$1(+_), line) : y$1; + }; + + line.defined = function(_) { + return arguments.length ? (defined = typeof _ === "function" ? _ : constant$1(!!_), 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$1(true), + context = null, + curve = curveLinear, + output = null; + + x0 = typeof x0 === "function" ? x0 : (x0 === undefined) ? x : constant$1(+x0); + y0 = typeof y0 === "function" ? y0 : (y0 === undefined) ? constant$1(0) : constant$1(+y0); + y1 = typeof y1 === "function" ? y1 : (y1 === undefined) ? y : constant$1(+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$1(+_), x1 = null, area) : x0; + }; + + area.x0 = function(_) { + return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$1(+_), area) : x0; + }; + + area.x1 = function(_) { + return arguments.length ? (x1 = _ == null ? null : typeof _ === "function" ? _ : constant$1(+_), area) : x1; + }; + + area.y = function(_) { + return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$1(+_), y1 = null, area) : y0; + }; + + area.y0 = function(_) { + return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$1(+_), area) : y0; + }; + + area.y1 = function(_) { + return arguments.length ? (y1 = _ == null ? null : typeof _ === "function" ? _ : constant$1(+_), 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$1(!!_), 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$1(d) { + return d; +} + +function pie() { + var value = identity$1, + sortValues = descending$1, + sort = null, + startAngle = constant$1(0), + endAngle = constant$1(tau), + padAngle = constant$1(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$1(+_), 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$1(+_), pie) : startAngle; + }; + + pie.endAngle = function(_) { + return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$1(+_), pie) : endAngle; + }; + + pie.padAngle = function(_) { + return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$1(+_), pie) : padAngle; + }; + + return pie; +} + +var curveRadialLinear = curveRadial$1(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$1(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$1(_)) : 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$1(_)) : c()._curve; + }; + + return a; +} + +function pointRadial(x, y) { + return [(y = +y) * Math.cos(x -= Math.PI / 2), y * Math.sin(x)]; +} + +function linkSource(d) { + return d.source; +} + +function linkTarget(d) { + return d.target; +} + +function link(curve) { + var source = linkSource, + target = linkTarget, + x$1 = x, + y$1 = y, + context = null; + + function link() { + var buffer, argv = slice.call(arguments), s = source.apply(this, argv), t = target.apply(this, argv); + if (!context) context = buffer = path(); + curve(context, +x$1.apply(this, (argv[0] = s, argv)), +y$1.apply(this, argv), +x$1.apply(this, (argv[0] = t, argv)), +y$1.apply(this, argv)); + if (buffer) return context = 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$1(+_), link) : x$1; + }; + + link.y = function(_) { + return arguments.length ? (y$1 = typeof _ === "function" ? _ : constant$1(+_), link) : y$1; + }; + + link.context = function(_) { + return arguments.length ? ((context = _ == null ? null : _), link) : context; + }; + + return link; +} + +function curveHorizontal(context, x0, y0, x1, y1) { + context.moveTo(x0, y0); + context.bezierCurveTo(x0 = (x0 + x1) / 2, y0, x0, y1, x1, y1); +} + +function curveVertical(context, x0, y0, x1, y1) { + context.moveTo(x0, y0); + context.bezierCurveTo(x0, y0 = (y0 + y1) / 2, x1, y0, x1, y1); +} + +function curveRadial(context, x0, y0, x1, y1) { + var p0 = pointRadial(x0, y0), + p1 = pointRadial(x0, y0 = (y0 + y1) / 2), + p2 = pointRadial(x1, y0), + p3 = pointRadial(x1, y1); + context.moveTo(p0[0], p0[1]); + context.bezierCurveTo(p1[0], p1[1], p2[0], p2[1], p3[0], p3[1]); +} + +function linkHorizontal() { + return link(curveHorizontal); +} + +function linkVertical() { + return link(curveVertical); +} + +function linkRadial() { + var l = link(curveRadial); + l.angle = l.x, delete l.x; + l.radius = l.y, delete l.y; + return l; +} + +var circle = { + draw: function(context, size) { + var r = Math.sqrt(size / pi); + context.moveTo(r, 0); + context.arc(0, 0, r, 0, tau); + } +}; + +var cross = { + draw: function(context, size) { + var r = Math.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(); + } +}; + +var tan30 = Math.sqrt(1 / 3), + tan30_2 = tan30 * 2; + +var diamond = { + draw: function(context, size) { + var y = Math.sqrt(size / tan30_2), + x = y * tan30; + context.moveTo(0, -y); + context.lineTo(x, 0); + context.lineTo(0, y); + context.lineTo(-x, 0); + context.closePath(); + } +}; + +var ka = 0.89081309152928522810, + kr = Math.sin(pi / 10) / Math.sin(7 * pi / 10), + kx = Math.sin(tau / 10) * kr, + ky = -Math.cos(tau / 10) * kr; + +var star = { + draw: function(context, size) { + var r = Math.sqrt(size * ka), + x = kx * r, + y = ky * r; + context.moveTo(0, -r); + context.lineTo(x, y); + for (var i = 1; i < 5; ++i) { + var a = tau * i / 5, + c = Math.cos(a), + s = Math.sin(a); + context.lineTo(s * r, -c * r); + context.lineTo(c * x - s * y, s * x + c * y); + } + context.closePath(); + } +}; + +var square = { + draw: function(context, size) { + var w = Math.sqrt(size), + x = -w / 2; + context.rect(x, x, w, w); + } +}; + +var sqrt3 = Math.sqrt(3); + +var triangle = { + draw: function(context, size) { + var y = -Math.sqrt(size / (sqrt3 * 3)); + context.moveTo(0, y * 2); + context.lineTo(-sqrt3 * y, -y); + context.lineTo(sqrt3 * y, -y); + context.closePath(); + } +}; + +var c = -0.5, + s = Math.sqrt(3) / 2, + k = 1 / Math.sqrt(12), + a = (k / 2 + 1) * 3; + +var wye = { + draw: function(context, size) { + var r = Math.sqrt(size / a), + x0 = r / 2, + y0 = r * k, + x1 = x0, + y1 = r * k + r, + 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 symbols = [ + circle, + cross, + diamond, + square, + star, + triangle, + wye +]; + +function symbol(type, size) { + var context = null; + type = typeof type === "function" ? type : constant$1(type || circle); + size = typeof size === "function" ? size : constant$1(size === undefined ? 64 : +size); + + function symbol() { + var 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$1(_), symbol) : type; + }; + + symbol.size = function(_) { + return arguments.length ? (size = typeof _ === "function" ? _ : constant$1(+_), 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); +} + +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; + } +} + +function bumpX(context) { + return new Bump(context, true); +} + +function bumpY(context) { + return new Bump(context, false); +} + +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$1([]), + 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$1(Array.from(_)), stack) : keys; + }; + + stack.value = function(_) { + return arguments.length ? (value = typeof _ === "function" ? _ : constant$1(+_), stack) : value; + }; + + stack.order = function(_) { + return arguments.length ? (order = _ == null ? none : typeof _ === "function" ? _ : constant$1(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(); +} + +var constant = x => () => x; + +function ZoomEvent(type, { + sourceEvent, + target, + transform, + dispatch +}) { + Object.defineProperties(this, { + type: {value: type, enumerable: true, configurable: true}, + sourceEvent: {value: sourceEvent, enumerable: true, configurable: true}, + target: {value: target, enumerable: true, configurable: true}, + transform: {value: transform, enumerable: true, configurable: true}, + _: {value: dispatch} + }); +} + +function Transform(k, x, y) { + this.k = k; + this.x = x; + this.y = y; +} + +Transform.prototype = { + constructor: Transform, + scale: function(k) { + return k === 1 ? this : new Transform(this.k * k, this.x, this.y); + }, + translate: function(x, y) { + return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y); + }, + apply: function(point) { + return [point[0] * this.k + this.x, point[1] * this.k + this.y]; + }, + applyX: function(x) { + return x * this.k + this.x; + }, + applyY: function(y) { + return y * this.k + this.y; + }, + invert: function(location) { + return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k]; + }, + invertX: function(x) { + return (x - this.x) / this.k; + }, + invertY: function(y) { + return (y - this.y) / this.k; + }, + rescaleX: function(x) { + return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x)); + }, + rescaleY: function(y) { + return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y)); + }, + toString: function() { + return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")"; + } +}; + +var identity = new Transform(1, 0, 0); + +transform.prototype = Transform.prototype; + +function transform(node) { + while (!node.__zoom) if (!(node = node.parentNode)) return identity; + return node.__zoom; +} + +function nopropagation(event) { + event.stopImmediatePropagation(); +} + +function noevent(event) { + event.preventDefault(); + event.stopImmediatePropagation(); +} + +// Ignore right-click, since that should open the context menu. +// except for pinch-to-zoom, which is sent as a wheel+ctrlKey event +function defaultFilter(event) { + return (!event.ctrlKey || event.type === 'wheel') && !event.button; +} + +function defaultExtent() { + var e = this; + if (e instanceof SVGElement) { + e = e.ownerSVGElement || e; + if (e.hasAttribute("viewBox")) { + e = e.viewBox.baseVal; + return [[e.x, e.y], [e.x + e.width, e.y + e.height]]; + } + return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]]; + } + return [[0, 0], [e.clientWidth, e.clientHeight]]; +} + +function defaultTransform() { + return this.__zoom || identity; +} + +function defaultWheelDelta(event) { + return -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * (event.ctrlKey ? 10 : 1); +} + +function defaultTouchable() { + return navigator.maxTouchPoints || ("ontouchstart" in this); +} + +function defaultConstrain(transform, extent, translateExtent) { + var dx0 = transform.invertX(extent[0][0]) - translateExtent[0][0], + dx1 = transform.invertX(extent[1][0]) - translateExtent[1][0], + dy0 = transform.invertY(extent[0][1]) - translateExtent[0][1], + dy1 = transform.invertY(extent[1][1]) - translateExtent[1][1]; + return transform.translate( + dx1 > dx0 ? (dx0 + dx1) / 2 : Math.min(0, dx0) || Math.max(0, dx1), + dy1 > dy0 ? (dy0 + dy1) / 2 : Math.min(0, dy0) || Math.max(0, dy1) + ); +} + +function zoom() { + var filter = defaultFilter, + extent = defaultExtent, + constrain = defaultConstrain, + wheelDelta = defaultWheelDelta, + touchable = defaultTouchable, + scaleExtent = [0, Infinity], + translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]], + duration = 250, + interpolate = interpolateZoom, + listeners = dispatch("start", "zoom", "end"), + touchstarting, + touchfirst, + touchending, + touchDelay = 500, + wheelDelay = 150, + clickDistance2 = 0, + tapDistance = 10; + + function zoom(selection) { + selection + .property("__zoom", defaultTransform) + .on("wheel.zoom", wheeled, {passive: false}) + .on("mousedown.zoom", mousedowned) + .on("dblclick.zoom", dblclicked) + .filter(touchable) + .on("touchstart.zoom", touchstarted) + .on("touchmove.zoom", touchmoved) + .on("touchend.zoom touchcancel.zoom", touchended) + .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)"); + } + + zoom.transform = function(collection, transform, point, event) { + var selection = collection.selection ? collection.selection() : collection; + selection.property("__zoom", defaultTransform); + if (collection !== selection) { + schedule(collection, transform, point, event); + } else { + selection.interrupt().each(function() { + gesture(this, arguments) + .event(event) + .start() + .zoom(null, typeof transform === "function" ? transform.apply(this, arguments) : transform) + .end(); + }); + } + }; + + zoom.scaleBy = function(selection, k, p, event) { + zoom.scaleTo(selection, function() { + var k0 = this.__zoom.k, + k1 = typeof k === "function" ? k.apply(this, arguments) : k; + return k0 * k1; + }, p, event); + }; + + zoom.scaleTo = function(selection, k, p, event) { + zoom.transform(selection, function() { + var e = extent.apply(this, arguments), + t0 = this.__zoom, + p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p, + p1 = t0.invert(p0), + k1 = typeof k === "function" ? k.apply(this, arguments) : k; + return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent); + }, p, event); + }; + + zoom.translateBy = function(selection, x, y, event) { + zoom.transform(selection, function() { + return constrain(this.__zoom.translate( + typeof x === "function" ? x.apply(this, arguments) : x, + typeof y === "function" ? y.apply(this, arguments) : y + ), extent.apply(this, arguments), translateExtent); + }, null, event); + }; + + zoom.translateTo = function(selection, x, y, p, event) { + zoom.transform(selection, function() { + var e = extent.apply(this, arguments), + t = this.__zoom, + p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p; + return constrain(identity.translate(p0[0], p0[1]).scale(t.k).translate( + typeof x === "function" ? -x.apply(this, arguments) : -x, + typeof y === "function" ? -y.apply(this, arguments) : -y + ), e, translateExtent); + }, p, event); + }; + + function scale(transform, k) { + k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k)); + return k === transform.k ? transform : new Transform(k, transform.x, transform.y); + } + + function translate(transform, p0, p1) { + var x = p0[0] - p1[0] * transform.k, y = p0[1] - p1[1] * transform.k; + return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y); + } + + function centroid(extent) { + return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2]; + } + + function schedule(transition, transform, point, event) { + transition + .on("start.zoom", function() { gesture(this, arguments).event(event).start(); }) + .on("interrupt.zoom end.zoom", function() { gesture(this, arguments).event(event).end(); }) + .tween("zoom", function() { + var that = this, + args = arguments, + g = gesture(that, args).event(event), + e = extent.apply(that, args), + p = point == null ? centroid(e) : typeof point === "function" ? point.apply(that, args) : point, + w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]), + a = that.__zoom, + b = typeof transform === "function" ? transform.apply(that, args) : transform, + i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k)); + return function(t) { + if (t === 1) t = b; // Avoid rounding error on end. + else { var l = i(t), k = w / l[2]; t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k); } + g.zoom(null, t); + }; + }); + } + + function gesture(that, args, clean) { + return (!clean && that.__zooming) || new Gesture(that, args); + } + + function Gesture(that, args) { + this.that = that; + this.args = args; + this.active = 0; + this.sourceEvent = null; + this.extent = extent.apply(that, args); + this.taps = 0; + } + + Gesture.prototype = { + event: function(event) { + if (event) this.sourceEvent = event; + return this; + }, + start: function() { + if (++this.active === 1) { + this.that.__zooming = this; + this.emit("start"); + } + return this; + }, + zoom: function(key, transform) { + if (this.mouse && key !== "mouse") this.mouse[1] = transform.invert(this.mouse[0]); + if (this.touch0 && key !== "touch") this.touch0[1] = transform.invert(this.touch0[0]); + if (this.touch1 && key !== "touch") this.touch1[1] = transform.invert(this.touch1[0]); + this.that.__zoom = transform; + this.emit("zoom"); + return this; + }, + end: function() { + if (--this.active === 0) { + delete this.that.__zooming; + this.emit("end"); + } + return this; + }, + emit: function(type) { + var d = select(this.that).datum(); + listeners.call( + type, + this.that, + new ZoomEvent(type, { + sourceEvent: this.sourceEvent, + target: zoom, + type, + transform: this.that.__zoom, + dispatch: listeners + }), + d + ); + } + }; + + function wheeled(event, ...args) { + if (!filter.apply(this, arguments)) return; + var g = gesture(this, args).event(event), + t = this.__zoom, + k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))), + p = pointer(event); + + // If the mouse is in the same location as before, reuse it. + // If there were recent wheel events, reset the wheel idle timeout. + if (g.wheel) { + if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) { + g.mouse[1] = t.invert(g.mouse[0] = p); + } + clearTimeout(g.wheel); + } + + // If this wheel event won’t trigger a transform change, ignore it. + else if (t.k === k) return; + + // Otherwise, capture the mouse point and location at the start. + else { + g.mouse = [p, t.invert(p)]; + interrupt(this); + g.start(); + } + + noevent(event); + g.wheel = setTimeout(wheelidled, wheelDelay); + g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent)); + + function wheelidled() { + g.wheel = null; + g.end(); + } + } + + function mousedowned(event, ...args) { + if (touchending || !filter.apply(this, arguments)) return; + var currentTarget = event.currentTarget, + g = gesture(this, args, true).event(event), + v = select(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true), + p = pointer(event, currentTarget), + x0 = event.clientX, + y0 = event.clientY; + + dragDisable(event.view); + nopropagation(event); + g.mouse = [p, this.__zoom.invert(p)]; + interrupt(this); + g.start(); + + function mousemoved(event) { + noevent(event); + if (!g.moved) { + var dx = event.clientX - x0, dy = event.clientY - y0; + g.moved = dx * dx + dy * dy > clickDistance2; + } + g.event(event) + .zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = pointer(event, currentTarget), g.mouse[1]), g.extent, translateExtent)); + } + + function mouseupped(event) { + v.on("mousemove.zoom mouseup.zoom", null); + yesdrag(event.view, g.moved); + noevent(event); + g.event(event).end(); + } + } + + function dblclicked(event, ...args) { + if (!filter.apply(this, arguments)) return; + var t0 = this.__zoom, + p0 = pointer(event.changedTouches ? event.changedTouches[0] : event, this), + p1 = t0.invert(p0), + k1 = t0.k * (event.shiftKey ? 0.5 : 2), + t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, args), translateExtent); + + noevent(event); + if (duration > 0) select(this).transition().duration(duration).call(schedule, t1, p0, event); + else select(this).call(zoom.transform, t1, p0, event); + } + + function touchstarted(event, ...args) { + if (!filter.apply(this, arguments)) return; + var touches = event.touches, + n = touches.length, + g = gesture(this, args, event.changedTouches.length === n).event(event), + started, i, t, p; + + nopropagation(event); + for (i = 0; i < n; ++i) { + t = touches[i], p = pointer(t, this); + p = [p, this.__zoom.invert(p), t.identifier]; + if (!g.touch0) g.touch0 = p, started = true, g.taps = 1 + !!touchstarting; + else if (!g.touch1 && g.touch0[2] !== p[2]) g.touch1 = p, g.taps = 0; + } + + if (touchstarting) touchstarting = clearTimeout(touchstarting); + + if (started) { + if (g.taps < 2) touchfirst = p[0], touchstarting = setTimeout(function() { touchstarting = null; }, touchDelay); + interrupt(this); + g.start(); + } + } + + function touchmoved(event, ...args) { + if (!this.__zooming) return; + var g = gesture(this, args).event(event), + touches = event.changedTouches, + n = touches.length, i, t, p, l; + + noevent(event); + for (i = 0; i < n; ++i) { + t = touches[i], p = pointer(t, this); + if (g.touch0 && g.touch0[2] === t.identifier) g.touch0[0] = p; + else if (g.touch1 && g.touch1[2] === t.identifier) g.touch1[0] = p; + } + t = g.that.__zoom; + if (g.touch1) { + var p0 = g.touch0[0], l0 = g.touch0[1], + p1 = g.touch1[0], l1 = g.touch1[1], + dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp, + dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl; + t = scale(t, Math.sqrt(dp / dl)); + p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2]; + l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2]; + } + else if (g.touch0) p = g.touch0[0], l = g.touch0[1]; + else return; + + g.zoom("touch", constrain(translate(t, p, l), g.extent, translateExtent)); + } + + function touchended(event, ...args) { + if (!this.__zooming) return; + var g = gesture(this, args).event(event), + touches = event.changedTouches, + n = touches.length, i, t; + + nopropagation(event); + if (touchending) clearTimeout(touchending); + touchending = setTimeout(function() { touchending = null; }, touchDelay); + for (i = 0; i < n; ++i) { + t = touches[i]; + if (g.touch0 && g.touch0[2] === t.identifier) delete g.touch0; + else if (g.touch1 && g.touch1[2] === t.identifier) delete g.touch1; + } + if (g.touch1 && !g.touch0) g.touch0 = g.touch1, delete g.touch1; + if (g.touch0) g.touch0[1] = this.__zoom.invert(g.touch0[0]); + else { + g.end(); + // If this was a dbltap, reroute to the (optional) dblclick.zoom handler. + if (g.taps === 2) { + t = pointer(t, this); + if (Math.hypot(touchfirst[0] - t[0], touchfirst[1] - t[1]) < tapDistance) { + var p = select(this).on("dblclick.zoom"); + if (p) p.apply(this, arguments); + } + } + } + } + + zoom.wheelDelta = function(_) { + return arguments.length ? (wheelDelta = typeof _ === "function" ? _ : constant(+_), zoom) : wheelDelta; + }; + + zoom.filter = function(_) { + return arguments.length ? (filter = typeof _ === "function" ? _ : constant(!!_), zoom) : filter; + }; + + zoom.touchable = function(_) { + return arguments.length ? (touchable = typeof _ === "function" ? _ : constant(!!_), zoom) : touchable; + }; + + zoom.extent = function(_) { + return arguments.length ? (extent = typeof _ === "function" ? _ : constant([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent; + }; + + zoom.scaleExtent = function(_) { + return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]]; + }; + + zoom.translateExtent = function(_) { + return arguments.length ? (translateExtent[0][0] = +_[0][0], translateExtent[1][0] = +_[1][0], translateExtent[0][1] = +_[0][1], translateExtent[1][1] = +_[1][1], zoom) : [[translateExtent[0][0], translateExtent[0][1]], [translateExtent[1][0], translateExtent[1][1]]]; + }; + + zoom.constrain = function(_) { + return arguments.length ? (constrain = _, zoom) : constrain; + }; + + zoom.duration = function(_) { + return arguments.length ? (duration = +_, zoom) : duration; + }; + + zoom.interpolate = function(_) { + return arguments.length ? (interpolate = _, zoom) : interpolate; + }; + + zoom.on = function() { + var value = listeners.on.apply(listeners, arguments); + return value === listeners ? zoom : value; + }; + + zoom.clickDistance = function(_) { + return arguments.length ? (clickDistance2 = (_ = +_) * _, zoom) : Math.sqrt(clickDistance2); + }; + + zoom.tapDistance = function(_) { + return arguments.length ? (tapDistance = +_, zoom) : tapDistance; + }; + + return zoom; +} + +exports.Adder = Adder; +exports.Delaunay = Delaunay; +exports.FormatSpecifier = FormatSpecifier; +exports.InternMap = InternMap; +exports.InternSet = InternSet; +exports.Node = Node$1; +exports.Voronoi = Voronoi; +exports.ZoomTransform = Transform; +exports.active = active; +exports.arc = arc; +exports.area = area; +exports.areaRadial = areaRadial; +exports.ascending = ascending$3; +exports.autoType = autoType; +exports.axisBottom = axisBottom; +exports.axisLeft = axisLeft; +exports.axisRight = axisRight; +exports.axisTop = axisTop; +exports.bin = bin; +exports.bisect = bisect; +exports.bisectCenter = bisectCenter; +exports.bisectLeft = bisectLeft; +exports.bisectRight = bisectRight; +exports.bisector = bisector; +exports.blob = blob; +exports.brush = brush; +exports.brushSelection = brushSelection; +exports.brushX = brushX; +exports.brushY = brushY; +exports.buffer = buffer; +exports.chord = chord; +exports.chordDirected = chordDirected; +exports.chordTranspose = chordTranspose; +exports.cluster = cluster; +exports.color = color; +exports.contourDensity = density; +exports.contours = contours; +exports.count = count$1; +exports.create = create$1; +exports.creator = creator; +exports.cross = cross$2; +exports.csv = csv; +exports.csvFormat = csvFormat; +exports.csvFormatBody = csvFormatBody; +exports.csvFormatRow = csvFormatRow; +exports.csvFormatRows = csvFormatRows; +exports.csvFormatValue = csvFormatValue; +exports.csvParse = csvParse; +exports.csvParseRows = csvParseRows; +exports.cubehelix = cubehelix$3; +exports.cumsum = cumsum; +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.descending = descending$2; +exports.deviation = deviation; +exports.difference = difference; +exports.disjoint = disjoint; +exports.dispatch = dispatch; +exports.drag = drag; +exports.dragDisable = dragDisable; +exports.dragEnable = yesdrag; +exports.dsv = dsv; +exports.dsvFormat = dsvFormat; +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$1; +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; +exports.every = every; +exports.extent = extent$1; +exports.fcumsum = fcumsum; +exports.filter = filter$1; +exports.flatGroup = flatGroup; +exports.flatRollup = flatRollup; +exports.forceCenter = center; +exports.forceCollide = collide; +exports.forceLink = link$2; +exports.forceManyBody = manyBody; +exports.forceRadial = radial$1; +exports.forceSimulation = simulation; +exports.forceX = x$1; +exports.forceY = y$1; +exports.formatDefaultLocale = defaultLocale$1; +exports.formatLocale = formatLocale$1; +exports.formatSpecifier = formatSpecifier; +exports.fsum = fsum; +exports.geoAlbers = albers; +exports.geoAlbersUsa = albersUsa; +exports.geoArea = area$2; +exports.geoAzimuthalEqualArea = azimuthalEqualArea; +exports.geoAzimuthalEqualAreaRaw = azimuthalEqualAreaRaw; +exports.geoAzimuthalEquidistant = azimuthalEquidistant; +exports.geoAzimuthalEquidistantRaw = azimuthalEquidistantRaw; +exports.geoBounds = bounds; +exports.geoCentroid = centroid$1; +exports.geoCircle = circle$2; +exports.geoClipAntimeridian = clipAntimeridian; +exports.geoClipCircle = clipCircle; +exports.geoClipExtent = extent; +exports.geoClipRectangle = clipRectangle; +exports.geoConicConformal = conicConformal; +exports.geoConicConformalRaw = conicConformalRaw; +exports.geoConicEqualArea = conicEqualArea; +exports.geoConicEqualAreaRaw = conicEqualAreaRaw; +exports.geoConicEquidistant = conicEquidistant; +exports.geoConicEquidistantRaw = conicEquidistantRaw; +exports.geoContains = contains$1; +exports.geoDistance = distance; +exports.geoEqualEarth = equalEarth; +exports.geoEqualEarthRaw = equalEarthRaw; +exports.geoEquirectangular = equirectangular; +exports.geoEquirectangularRaw = equirectangularRaw; +exports.geoGnomonic = gnomonic; +exports.geoGnomonicRaw = gnomonicRaw; +exports.geoGraticule = graticule; +exports.geoGraticule10 = graticule10; +exports.geoIdentity = identity$4; +exports.geoInterpolate = interpolate; +exports.geoLength = length$1; +exports.geoMercator = mercator; +exports.geoMercatorRaw = mercatorRaw; +exports.geoNaturalEarth1 = naturalEarth1; +exports.geoNaturalEarth1Raw = naturalEarth1Raw; +exports.geoOrthographic = orthographic; +exports.geoOrthographicRaw = orthographicRaw; +exports.geoPath = index$2; +exports.geoProjection = projection; +exports.geoProjectionMutator = projectionMutator; +exports.geoRotation = rotation; +exports.geoStereographic = stereographic; +exports.geoStereographicRaw = stereographicRaw; +exports.geoStream = geoStream; +exports.geoTransform = transform$1; +exports.geoTransverseMercator = transverseMercator; +exports.geoTransverseMercatorRaw = transverseMercatorRaw; +exports.gray = gray; +exports.greatest = greatest; +exports.greatestIndex = greatestIndex; +exports.group = group; +exports.groupSort = groupSort; +exports.groups = groups; +exports.hcl = hcl$2; +exports.hierarchy = hierarchy; +exports.histogram = bin; +exports.hsl = hsl$2; +exports.html = html; +exports.image = image; +exports.index = index$4; +exports.indexes = indexes; +exports.interpolate = interpolate$2; +exports.interpolateArray = array$3; +exports.interpolateBasis = basis$2; +exports.interpolateBasisClosed = basisClosed$1; +exports.interpolateBlues = Blues; +exports.interpolateBrBG = BrBG; +exports.interpolateBuGn = BuGn; +exports.interpolateBuPu = BuPu; +exports.interpolateCividis = cividis; +exports.interpolateCool = cool; +exports.interpolateCubehelix = cubehelix$2; +exports.interpolateCubehelixDefault = cubehelix; +exports.interpolateCubehelixLong = cubehelixLong; +exports.interpolateDate = date$1; +exports.interpolateDiscrete = discrete; +exports.interpolateGnBu = GnBu; +exports.interpolateGreens = Greens; +exports.interpolateGreys = Greys; +exports.interpolateHcl = hcl$1; +exports.interpolateHclLong = hclLong; +exports.interpolateHsl = hsl$1; +exports.interpolateHslLong = hslLong; +exports.interpolateHue = hue; +exports.interpolateInferno = inferno; +exports.interpolateLab = lab; +exports.interpolateMagma = magma; +exports.interpolateNumber = interpolateNumber; +exports.interpolateNumberArray = numberArray; +exports.interpolateObject = object$1; +exports.interpolateOrRd = OrRd; +exports.interpolateOranges = Oranges; +exports.interpolatePRGn = PRGn; +exports.interpolatePiYG = PiYG; +exports.interpolatePlasma = plasma; +exports.interpolatePuBu = PuBu; +exports.interpolatePuBuGn = PuBuGn; +exports.interpolatePuOr = PuOr; +exports.interpolatePuRd = PuRd; +exports.interpolatePurples = Purples; +exports.interpolateRainbow = rainbow; +exports.interpolateRdBu = RdBu; +exports.interpolateRdGy = RdGy; +exports.interpolateRdPu = RdPu; +exports.interpolateRdYlBu = RdYlBu; +exports.interpolateRdYlGn = RdYlGn; +exports.interpolateReds = Reds; +exports.interpolateRgb = interpolateRgb; +exports.interpolateRgbBasis = rgbBasis; +exports.interpolateRgbBasisClosed = rgbBasisClosed; +exports.interpolateRound = interpolateRound; +exports.interpolateSinebow = sinebow; +exports.interpolateSpectral = Spectral; +exports.interpolateString = interpolateString; +exports.interpolateTransformCss = interpolateTransformCss; +exports.interpolateTransformSvg = interpolateTransformSvg; +exports.interpolateTurbo = turbo; +exports.interpolateViridis = viridis; +exports.interpolateWarm = warm; +exports.interpolateYlGn = YlGn; +exports.interpolateYlGnBu = YlGnBu; +exports.interpolateYlOrBr = YlOrBr; +exports.interpolateYlOrRd = YlOrRd; +exports.interpolateZoom = interpolateZoom; +exports.interrupt = interrupt; +exports.intersection = intersection; +exports.interval = interval; +exports.isoFormat = formatIso$1; +exports.isoParse = parseIso$1; +exports.json = json; +exports.lab = lab$1; +exports.lch = lch; +exports.least = least; +exports.leastIndex = leastIndex; +exports.line = line; +exports.lineRadial = lineRadial$1; +exports.linkHorizontal = linkHorizontal; +exports.linkRadial = linkRadial; +exports.linkVertical = linkVertical; +exports.local = local$1; +exports.map = map$1; +exports.matcher = matcher; +exports.max = max$3; +exports.maxIndex = maxIndex; +exports.mean = mean; +exports.median = median; +exports.merge = merge; +exports.min = min$2; +exports.minIndex = minIndex; +exports.mode = mode; +exports.namespace = namespace; +exports.namespaces = namespaces; +exports.nice = nice$1; +exports.now = now; +exports.pack = index$1; +exports.packEnclose = enclose; +exports.packSiblings = siblings; +exports.pairs = pairs; +exports.partition = partition; +exports.path = path; +exports.permute = permute; +exports.pie = pie; +exports.piecewise = piecewise; +exports.pointRadial = pointRadial; +exports.pointer = pointer; +exports.pointers = pointers; +exports.polygonArea = area$1; +exports.polygonCentroid = centroid; +exports.polygonContains = contains; +exports.polygonHull = hull; +exports.polygonLength = length; +exports.precisionFixed = precisionFixed; +exports.precisionPrefix = precisionPrefix; +exports.precisionRound = precisionRound; +exports.quadtree = quadtree; +exports.quantile = quantile$1; +exports.quantileSorted = quantileSorted; +exports.quantize = quantize$1; +exports.quickselect = quickselect; +exports.radialArea = areaRadial; +exports.radialLine = lineRadial$1; +exports.randomBates = bates; +exports.randomBernoulli = bernoulli; +exports.randomBeta = beta; +exports.randomBinomial = binomial; +exports.randomCauchy = cauchy; +exports.randomExponential = exponential; +exports.randomGamma = gamma; +exports.randomGeometric = geometric; +exports.randomInt = int; +exports.randomIrwinHall = irwinHall; +exports.randomLcg = lcg; +exports.randomLogNormal = logNormal; +exports.randomLogistic = logistic; +exports.randomNormal = normal; +exports.randomPareto = pareto; +exports.randomPoisson = poisson; +exports.randomUniform = uniform; +exports.randomWeibull = weibull; +exports.range = range$2; +exports.rank = rank; +exports.reduce = reduce; +exports.reverse = reverse$1; +exports.rgb = rgb; +exports.ribbon = ribbon$1; +exports.ribbonArrow = ribbonArrow; +exports.rollup = rollup; +exports.rollups = rollups; +exports.scaleBand = band; +exports.scaleDiverging = diverging$1; +exports.scaleDivergingLog = divergingLog; +exports.scaleDivergingPow = divergingPow; +exports.scaleDivergingSqrt = divergingSqrt; +exports.scaleDivergingSymlog = divergingSymlog; +exports.scaleIdentity = identity$2; +exports.scaleImplicit = implicit; +exports.scaleLinear = linear; +exports.scaleLog = log; +exports.scaleOrdinal = ordinal; +exports.scalePoint = point$4; +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$1; +exports.scaleSymlog = symlog; +exports.scaleThreshold = threshold; +exports.scaleTime = time; +exports.scaleUtc = utcTime; +exports.scan = scan; +exports.schemeAccent = Accent; +exports.schemeBlues = scheme$5; +exports.schemeBrBG = scheme$q; +exports.schemeBuGn = scheme$h; +exports.schemeBuPu = scheme$g; +exports.schemeCategory10 = category10; +exports.schemeDark2 = Dark2; +exports.schemeGnBu = scheme$f; +exports.schemeGreens = scheme$4; +exports.schemeGreys = scheme$3; +exports.schemeOrRd = scheme$e; +exports.schemeOranges = scheme; +exports.schemePRGn = scheme$p; +exports.schemePaired = Paired; +exports.schemePastel1 = Pastel1; +exports.schemePastel2 = Pastel2; +exports.schemePiYG = scheme$o; +exports.schemePuBu = scheme$c; +exports.schemePuBuGn = scheme$d; +exports.schemePuOr = scheme$n; +exports.schemePuRd = scheme$b; +exports.schemePurples = scheme$2; +exports.schemeRdBu = scheme$m; +exports.schemeRdGy = scheme$l; +exports.schemeRdPu = scheme$a; +exports.schemeRdYlBu = scheme$k; +exports.schemeRdYlGn = scheme$j; +exports.schemeReds = scheme$1; +exports.schemeSet1 = Set1; +exports.schemeSet2 = Set2; +exports.schemeSet3 = Set3; +exports.schemeSpectral = scheme$i; +exports.schemeTableau10 = Tableau10; +exports.schemeYlGn = scheme$8; +exports.schemeYlGnBu = scheme$9; +exports.schemeYlOrBr = scheme$7; +exports.schemeYlOrRd = scheme$6; +exports.select = select; +exports.selectAll = selectAll; +exports.selection = selection; +exports.selector = selector; +exports.selectorAll = selectorAll; +exports.shuffle = shuffle$1; +exports.shuffler = shuffler; +exports.some = some; +exports.sort = sort; +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.stratify = stratify; +exports.style = styleValue; +exports.subset = subset; +exports.sum = sum$2; +exports.superset = superset; +exports.svg = svg; +exports.symbol = symbol; +exports.symbolCircle = circle; +exports.symbolCross = cross; +exports.symbolDiamond = diamond; +exports.symbolSquare = square; +exports.symbolStar = star; +exports.symbolTriangle = triangle; +exports.symbolWye = wye; +exports.symbols = symbols; +exports.text = text; +exports.thresholdFreedmanDiaconis = thresholdFreedmanDiaconis; +exports.thresholdScott = thresholdScott; +exports.thresholdSturges = thresholdSturges; +exports.tickFormat = tickFormat; +exports.tickIncrement = tickIncrement; +exports.tickStep = tickStep; +exports.ticks = ticks; +exports.timeDay = timeDay; +exports.timeDays = days; +exports.timeFormatDefaultLocale = defaultLocale; +exports.timeFormatLocale = formatLocale; +exports.timeFriday = friday; +exports.timeFridays = fridays; +exports.timeHour = timeHour; +exports.timeHours = hours; +exports.timeInterval = newInterval; +exports.timeMillisecond = millisecond$1; +exports.timeMilliseconds = milliseconds; +exports.timeMinute = timeMinute; +exports.timeMinutes = minutes; +exports.timeMonday = monday; +exports.timeMondays = mondays; +exports.timeMonth = timeMonth; +exports.timeMonths = months; +exports.timeSaturday = saturday; +exports.timeSaturdays = saturdays; +exports.timeSecond = utcSecond; +exports.timeSeconds = seconds; +exports.timeSunday = sunday; +exports.timeSundays = sundays; +exports.timeThursday = thursday; +exports.timeThursdays = thursdays; +exports.timeTickInterval = timeTickInterval; +exports.timeTicks = timeTicks; +exports.timeTuesday = tuesday; +exports.timeTuesdays = tuesdays; +exports.timeWednesday = wednesday; +exports.timeWednesdays = wednesdays; +exports.timeWeek = sunday; +exports.timeWeeks = sundays; +exports.timeYear = timeYear; +exports.timeYears = years; +exports.timeout = timeout; +exports.timer = timer; +exports.timerFlush = timerFlush; +exports.transition = transition; +exports.transpose = transpose; +exports.tree = tree; +exports.treemap = index; +exports.treemapBinary = binary; +exports.treemapDice = treemapDice; +exports.treemapResquarify = resquarify; +exports.treemapSlice = treemapSlice; +exports.treemapSliceDice = sliceDice; +exports.treemapSquarify = squarify; +exports.tsv = tsv; +exports.tsvFormat = tsvFormat; +exports.tsvFormatBody = tsvFormatBody; +exports.tsvFormatRow = tsvFormatRow; +exports.tsvFormatRows = tsvFormatRows; +exports.tsvFormatValue = tsvFormatValue; +exports.tsvParse = tsvParse; +exports.tsvParseRows = tsvParseRows; +exports.union = union; +exports.utcDay = utcDay$1; +exports.utcDays = utcDays; +exports.utcFriday = utcFriday; +exports.utcFridays = utcFridays; +exports.utcHour = utcHour$1; +exports.utcHours = utcHours; +exports.utcMillisecond = millisecond$1; +exports.utcMilliseconds = milliseconds; +exports.utcMinute = utcMinute$1; +exports.utcMinutes = utcMinutes; +exports.utcMonday = utcMonday; +exports.utcMondays = utcMondays; +exports.utcMonth = utcMonth$1; +exports.utcMonths = utcMonths; +exports.utcSaturday = utcSaturday; +exports.utcSaturdays = utcSaturdays; +exports.utcSecond = utcSecond; +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$1; +exports.utcYears = utcYears; +exports.variance = variance; +exports.version = version; +exports.window = defaultView; +exports.xml = xml; +exports.zip = zip; +exports.zoom = zoom; +exports.zoomIdentity = identity; +exports.zoomTransform = transform; + +Object.defineProperty(exports, '__esModule', { value: true }); + +})); diff --git a/main.js b/main.js index 6cab8c0a..3826d90d 100644 --- a/main.js +++ b/main.js @@ -15,8 +15,8 @@ const ERROR = true; // if map version is not stored, clear localStorage and show a message if (rn(localStorage.getItem("version"), 1) !== rn(version, 1)) { - localStorage.clear(); - setTimeout(showWelcomeMessage, 8000); + localStorage.clear(); + setTimeout(showWelcomeMessage, 8000); } // append svg layers (in default order) @@ -133,25 +133,26 @@ let viewY = 0; const zoomThrottled = throttle(doWorkOnZoom, 100); function zoomed() { - const {k, x, y} = d3.event.transform; + const {k, x, y} = d3.event.transform; - const isScaleChanged = Boolean(scale - k); - const isPositionChanged = Boolean(viewX - x || viewY - y); - scale = k; - viewX = x; - viewY = y; + const isScaleChanged = Boolean(scale - k); + const isPositionChanged = Boolean(viewX - x || viewY - y); - zoomThrottled(isScaleChanged, isPositionChanged); + scale = k; + viewX = x; + viewY = y; + + zoomThrottled(isScaleChanged, isPositionChanged); } const zoom = d3.zoom().scaleExtent([1, 20]).on("zoom", zoomed); // default options let options = { - pinNotes: false, - showMFCGMap: true, - winds: [225, 45, 225, 315, 135, 315], - stateLabelsMode: "auto" + pinNotes: false, + showMFCGMap: true, + winds: [225, 45, 225, 315, 135, 315], + stateLabelsMode: "auto" }; let mapCoordinates = {}; // map coordinates on globe let populationRate = +document.getElementById("populationRateInput").value; @@ -180,236 +181,237 @@ d3.select("#tooltip").transition().duration(4000).style("opacity", 1); // decide which map should be loaded or generated on page load void (function checkLoadParameters() { - const url = new URL(window.location.href); - const params = url.searchParams; + const url = new URL(window.location.href); + const params = url.searchParams; - // of there is a valid maplink, try to load .map file from URL - if (params.get("maplink")) { - WARN && console.warn("Load map from URL"); - const maplink = params.get("maplink"); - const pattern = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/; - const valid = pattern.test(maplink); - if (valid) { - loadMapFromURL(maplink, 1); - return; - } else showUploadErrorMessage("Map link is not a valid URL", maplink); - } + // of there is a valid maplink, try to load .map file from URL + if (params.get("maplink")) { + WARN && console.warn("Load map from URL"); + const maplink = params.get("maplink"); + const pattern = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/; + const valid = pattern.test(maplink); + if (valid) { + loadMapFromURL(maplink, 1); + return; + } else showUploadErrorMessage("Map link is not a valid URL", maplink); + } - // if there is a seed (user of MFCG provided), generate map for it - if (params.get("seed")) { - WARN && console.warn("Generate map for seed"); - generateMapOnLoad(); - return; - } - - // open latest map if option is active and map is stored - if (onloadMap.value === "saved") { - ldb.get("lastMap", blob => { - if (blob) { - WARN && console.warn("Load last saved map"); - try { - uploadMap(blob); - } catch (error) { - ERROR && console.error(error); - WARN && console.warn("Cannot load stored map, random map to be generated"); - generateMapOnLoad(); - } - } else { - ERROR && console.error("No map stored, random map to be generated"); + // if there is a seed (user of MFCG provided), generate map for it + if (params.get("seed")) { + WARN && console.warn("Generate map for seed"); generateMapOnLoad(); - } - }); - return; - } + return; + } - WARN && console.warn("Generate random map"); - generateMapOnLoad(); + // open latest map if option is active and map is stored + if (onloadMap.value === "saved") { + ldb.get("lastMap", blob => { + if (blob) { + WARN && console.warn("Load last saved map"); + try { + uploadMap(blob); + } catch (error) { + ERROR && console.error(error); + WARN && console.warn("Cannot load stored map, random map to be generated"); + generateMapOnLoad(); + } + } else { + ERROR && console.error("No map stored, random map to be generated"); + generateMapOnLoad(); + } + }); + return; + } + + WARN && console.warn("Generate random map"); + generateMapOnLoad(); })(); function generateMapOnLoad() { - applyStyleOnLoad(); // apply default or previously selected style - generate(); // generate map - focusOn(); // based on searchParams focus on point, cell or burg from MFCG - applyPreset(); // apply saved layers preset + applyStyleOnLoad(); // apply default or previously selected style + generate(); // generate map + focusOn(); // based on searchParams focus on point, cell or burg from MFCG + applyPreset(); // apply saved layers preset } // focus on coordinates, cell or burg provided in searchParams function focusOn() { - const url = new URL(window.location.href); - const params = url.searchParams; + const url = new URL(window.location.href); + const params = url.searchParams; - const fromMGCG = params.get("from") === "MFCG" && document.referrer; - if (fromMGCG) { - if (params.get("seed").length === 13) { - // show back burg from MFCG - const burgSeed = params.get("seed").slice(-4); - params.set("burg", burgSeed); - } else { - // select burg for MFCG - findBurgForMFCG(params); - return; - } - } - - const scaleParam = params.get("scale"); - const cellParam = params.get("cell"); - const burgParam = params.get("burg"); - - if (scaleParam || cellParam || burgParam) { - const scale = +scaleParam || 8; - - if (cellParam) { - const cell = +params.get("cell"); - const [x, y] = pack.cells.p[cell]; - zoomTo(x, y, scale, 1600); - return; + const fromMGCG = params.get("from") === "MFCG" && document.referrer; + if (fromMGCG) { + if (params.get("seed").length === 13) { + // show back burg from MFCG + const burgSeed = params.get("seed").slice(-4); + params.set("burg", burgSeed); + } else { + // select burg for MFCG + findBurgForMFCG(params); + return; + } } - if (burgParam) { - const burg = isNaN(+burgParam) ? pack.burgs.find(burg => burg.name === burgParam) : pack.burgs[+burgParam]; - if (!burg) return; + const scaleParam = params.get("scale"); + const cellParam = params.get("cell"); + const burgParam = params.get("burg"); - const {x, y} = burg; - zoomTo(x, y, scale, 1600); - return; + if (scaleParam || cellParam || burgParam) { + const scale = +scaleParam || 8; + + if (cellParam) { + const cell = +params.get("cell"); + const [x, y] = pack.cells.p[cell]; + zoomTo(x, y, scale, 1600); + return; + } + + if (burgParam) { + const burg = isNaN(+burgParam) ? pack.burgs.find(burg => burg.name === burgParam) : pack.burgs[+burgParam]; + if (!burg) return; + + const {x, y} = burg; + zoomTo(x, y, scale, 1600); + return; + } + + const x = +params.get("x") || graphWidth / 2; + const y = +params.get("y") || graphHeight / 2; + zoomTo(x, y, scale, 1600); } - - const x = +params.get("x") || graphWidth / 2; - const y = +params.get("y") || graphHeight / 2; - zoomTo(x, y, scale, 1600); - } } // find burg for MFCG and focus on it function findBurgForMFCG(params) { - const cells = pack.cells, - burgs = pack.burgs; - if (pack.burgs.length < 2) { - ERROR && console.error("Cannot select a burg for MFCG"); - return; - } + const cells = pack.cells, + burgs = pack.burgs; + if (pack.burgs.length < 2) { + ERROR && console.error("Cannot select a burg for MFCG"); + return; + } - // used for selection - const size = +params.get("size"); - const coast = +params.get("coast"); - const port = +params.get("port"); - const river = +params.get("river"); + // used for selection + const size = +params.get("size"); + const coast = +params.get("coast"); + const port = +params.get("port"); + const river = +params.get("river"); - let selection = defineSelection(coast, port, river); - if (!selection.length) selection = defineSelection(coast, !port, !river); - if (!selection.length) selection = defineSelection(!coast, 0, !river); - if (!selection.length) selection = [burgs[1]]; // select first if nothing is found + let selection = defineSelection(coast, port, river); + if (!selection.length) selection = defineSelection(coast, !port, !river); + if (!selection.length) selection = defineSelection(!coast, 0, !river); + if (!selection.length) selection = [burgs[1]]; // select first if nothing is found - function defineSelection(coast, port, river) { - if (port && river) return burgs.filter(b => b.port && cells.r[b.cell]); - if (!port && coast && river) return burgs.filter(b => !b.port && cells.t[b.cell] === 1 && cells.r[b.cell]); - if (!coast && !river) return burgs.filter(b => cells.t[b.cell] !== 1 && !cells.r[b.cell]); - if (!coast && river) return burgs.filter(b => cells.t[b.cell] !== 1 && cells.r[b.cell]); - if (coast && river) return burgs.filter(b => cells.t[b.cell] === 1 && cells.r[b.cell]); - return []; - } + function defineSelection(coast, port, river) { + if (port && river) return burgs.filter(b => b.port && cells.r[b.cell]); + if (!port && coast && river) return burgs.filter(b => !b.port && cells.t[b.cell] === 1 && cells.r[b.cell]); + if (!coast && !river) return burgs.filter(b => cells.t[b.cell] !== 1 && !cells.r[b.cell]); + if (!coast && river) return burgs.filter(b => cells.t[b.cell] !== 1 && cells.r[b.cell]); + if (coast && river) return burgs.filter(b => cells.t[b.cell] === 1 && cells.r[b.cell]); + return []; + } - // select a burg with closest population from selection - const selected = d3.scan(selection, (a, b) => Math.abs(a.population - size) - Math.abs(b.population - size)); - const burgId = selection[selected].i; - if (!burgId) { - ERROR && console.error("Cannot select a burg for MFCG"); - return; - } + // select a burg with closest population from selection + const selected = d3.scan(selection, (a, b) => Math.abs(a.population - size) - Math.abs(b.population - size)); + const burgId = selection[selected].i; + if (!burgId) { + ERROR && console.error("Cannot select a burg for MFCG"); + return; + } - const b = burgs[burgId]; - const referrer = new URL(document.referrer); - for (let p of referrer.searchParams) { - if (p[0] === "name") b.name = p[1]; - else if (p[0] === "size") b.population = +p[1]; - else if (p[0] === "seed") b.MFCG = +p[1]; - else if (p[0] === "shantytown") b.shanty = +p[1]; - else b[p[0]] = +p[1]; // other parameters - } - if (params.get("name") && params.get("name") != "null") b.name = params.get("name"); + const b = burgs[burgId]; + const referrer = new URL(document.referrer); + for (let p of referrer.searchParams) { + if (p[0] === "name") b.name = p[1]; + else if (p[0] === "size") b.population = +p[1]; + else if (p[0] === "seed") b.MFCG = +p[1]; + else if (p[0] === "shantytown") b.shanty = +p[1]; + else b[p[0]] = +p[1]; // other parameters + } + if (params.get("name") && params.get("name") != "null") b.name = params.get("name"); - const label = burgLabels.select("[data-id='" + burgId + "']"); - if (label.size()) { - label - .text(b.name) - .classed("drag", true) - .on("mouseover", function () { - d3.select(this).classed("drag", false); - label.on("mouseover", null); - }); - } + const label = burgLabels.select("[data-id='" + burgId + "']"); + if (label.size()) { + label + .text(b.name) + .classed("drag", true) + .on("mouseover", function () { + d3.select(this).classed("drag", false); + label.on("mouseover", null); + }); + } - zoomTo(b.x, b.y, 8, 1600); - invokeActiveZooming(); - tip("Here stands the glorious city of " + b.name, true, "success", 15000); + zoomTo(b.x, b.y, 8, 1600); + invokeActiveZooming(); + tip("Here stands the glorious city of " + b.name, true, "success", 15000); } // apply default biomes data function applyDefaultBiomesSystem() { - const name = [ - "Marine", - "Hot desert", - "Cold desert", - "Savanna", - "Grassland", - "Tropical seasonal forest", - "Temperate deciduous forest", - "Tropical rainforest", - "Temperate rainforest", - "Taiga", - "Tundra", - "Glacier", - "Wetland" - ]; - const color = ["#466eab", "#fbe79f", "#b5b887", "#d2d082", "#c8d68f", "#b6d95d", "#29bc56", "#7dcb35", "#409c43", "#4b6b32", "#96784b", "#d5e7eb", "#0b9131"]; - const habitability = [0, 4, 10, 22, 30, 50, 100, 80, 90, 12, 4, 0, 12]; - const iconsDensity = [0, 3, 2, 120, 120, 120, 120, 150, 150, 100, 5, 0, 150]; - const icons = [ - {}, - {dune: 3, cactus: 6, deadTree: 1}, - {dune: 9, deadTree: 1}, - {acacia: 1, grass: 9}, - {grass: 1}, - {acacia: 8, palm: 1}, - {deciduous: 1}, - {acacia: 5, palm: 3, deciduous: 1, swamp: 1}, - {deciduous: 6, swamp: 1}, - {conifer: 1}, - {grass: 1}, - {}, - {swamp: 1} - ]; - const cost = [10, 200, 150, 60, 50, 70, 70, 80, 90, 200, 1000, 5000, 150]; // biome movement cost - const biomesMartix = [ - // hot ↔ cold [>19°C; <-4°C]; dry ↕ wet - new Uint8Array([1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10]), - new Uint8Array([3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 9, 9, 9, 9, 10, 10, 10]), - new Uint8Array([5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 9, 9, 9, 9, 9, 10, 10, 10]), - new Uint8Array([5, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10]), - new Uint8Array([7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10]) - ]; + const biomeName = [ + "Marine", // 0 + "Hot desert", // 1 + "Cold desert", // 2 + "Savanna", // 3 + "Grassland", // 4 + "Tropical seasonal forest", // 5 + "Temperate deciduous forest", // 6 + "Tropical rainforest", // 7 + "Temperate rainforest", // 8 + "Taiga", // 9 + "Tundra", // 10 + "Glacier", // 11 + "Wetland" // 12 + ]; + const biomeColor = ["#466eab", "#fbe79f", "#b5b887", "#d2d082", "#c8d68f", "#b6d95d", "#29bc56", "#7dcb35", "#409c43", "#4b6b32", "#96784b", "#d5e7eb", "#0b9131"]; + const biomeIx = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; // For Readability -]:-)> + const habitability = [2, 20, 25, 32, 35, 50, 50, 20, 45, 12, 4, 1, 75]; + const iconsDensity = [0, 3, 2, 120, 120, 120, 120, 150, 150, 100, 5, 0, 150]; + const icons = [ + {}, + {dune: 3, cactus: 6, deadTree: 1}, + {dune: 9, deadTree: 1}, + {acacia: 1, grass: 9}, + {grass: 1}, + {acacia: 8, palm: 1}, + {deciduous: 1}, + {acacia: 5, palm: 3, deciduous: 1, swamp: 1}, + {deciduous: 6, swamp: 1}, + {conifer: 1}, + {grass: 1}, + {}, + {swamp: 1} + ]; + const cost = [10, 200, 150, 60, 50, 70, 70, 80, 90, 200, 1000, 5000, 150]; // biome movement cost + const biomesMartix = [ + // hot ↔ cold [>19°C; <-4°C]; dry ↕ wet + new Uint8Array([1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10]), + new Uint8Array([3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 9, 9, 9, 9, 10, 10, 10]), + new Uint8Array([5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 9, 9, 9, 9, 9, 10, 10, 10]), + new Uint8Array([5, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10]), + new Uint8Array([7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10]) + ]; - // parse icons weighted array into a simple array - for (let i = 0; i < icons.length; i++) { - const parsed = []; - for (const icon in icons[i]) { - for (let j = 0; j < icons[i][icon]; j++) { - parsed.push(icon); - } + // parse icons weighted array into a simple array + for (let i = 0; i < icons.length; i++) { + const parsed = []; + for (const icon in icons[i]) { + for (let j = 0; j < icons[i][icon]; j++) { + parsed.push(icon); + } + } + icons[i] = parsed; } - icons[i] = parsed; - } - return {i: d3.range(0, name.length), name, color, biomesMartix, habitability, iconsDensity, icons, cost}; + return {i: d3.range(0, biomeName.length), name: biomeName, color: biomeColor, biomesMartix, habitability, iconsDensity, icons, cost}; } function showWelcomeMessage() { - const changelog = link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Changelog", "previous versions"); - const reddit = link("https://www.reddit.com/r/FantasyMapGenerator", "Reddit community"); - const discord = link("https://discordapp.com/invite/X7E84HU", "Discord server"); - const patreon = link("https://www.patreon.com/azgaar", "Patreon"); + const changelog = link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Changelog", "previous versions"); + const reddit = link("https://www.reddit.com/r/FantasyMapGenerator", "Reddit community"); + const discord = link("https://discordapp.com/invite/X7E84HU", "Discord server"); + const patreon = link("https://www.patreon.com/azgaar", "Patreon"); - alertMessage.innerHTML = `The Fantasy Map Generator is updated up to version ${version}. + alertMessage.innerHTML = `The Fantasy Map Generator is updated up to version ${version}. This version is compatible with ${changelog}, loaded .map files will be auto-updated.

    Main changes:
  • Ability to limit military units by biome, state, culture and religion
  • @@ -426,1426 +428,1446 @@ function showWelcomeMessage() {

    Join our ${discord} and ${reddit} to ask questions, share maps, discuss the Generator and Worlbuilding, report bugs and propose new features.

    Thanks for all supporters on
    Patreon!`; - $("#alert").dialog({ - resizable: false, - title: "Fantasy Map Generator update", - width: "28em", - buttons: { - OK: function () { - $(this).dialog("close"); - } - }, - position: {my: "center center-4em", at: "center", of: "svg"}, - close: () => localStorage.setItem("version", version) - }); + $("#alert").dialog({ + resizable: false, + title: "Fantasy Map Generator update", + width: "28em", + buttons: { + OK: function () { + $(this).dialog("close"); + } + }, + position: {my: "center center-4em", at: "center", of: "svg"}, + close: () => localStorage.setItem("version", version) + }); } function doWorkOnZoom(isScaleChanged, isPositionChanged) { - viewbox.attr("transform", `translate(${viewX} ${viewY}) scale(${scale})`); + viewbox.attr("transform", `translate(${viewX} ${viewY}) scale(${scale})`); - if (isPositionChanged) drawCoordinates(); + if (isPositionChanged) drawCoordinates(); - if (isScaleChanged) { - invokeActiveZooming(); - drawScaleBar(); - } + if (isScaleChanged) { + invokeActiveZooming(); + drawScaleBar(); + } - // zoom image converter overlay - if (customization === 1) { - const canvas = document.getElementById("canvas"); - if (!canvas || canvas.style.opacity === "0") return; + // zoom image converter overlay + if (customization === 1) { + const canvas = document.getElementById("canvas"); + if (!canvas || canvas.style.opacity === "0") return; - const img = document.getElementById("imageToConvert"); - if (!img) return; + const img = document.getElementById("imageToConvert"); + if (!img) return; - const ctx = canvas.getContext("2d"); - ctx.clearRect(0, 0, canvas.width, canvas.height); - ctx.setTransform(scale, 0, 0, scale, viewX, viewY); - ctx.drawImage(img, 0, 0, canvas.width, canvas.height); - } + const ctx = canvas.getContext("2d"); + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.setTransform(scale, 0, 0, scale, viewX, viewY); + ctx.drawImage(img, 0, 0, canvas.width, canvas.height); + } } // Zoom to a specific point function zoomTo(x, y, z = 8, d = 2000) { - const transform = d3.zoomIdentity.translate(x * -z + graphWidth / 2, y * -z + graphHeight / 2).scale(z); - svg.transition().duration(d).call(zoom.transform, transform); + const transform = d3.zoomIdentity.translate(x * -z + graphWidth / 2, y * -z + graphHeight / 2).scale(z); + svg.transition().duration(d).call(zoom.transform, transform); } // Reset zoom to initial function resetZoom(d = 1000) { - svg.transition().duration(d).call(zoom.transform, d3.zoomIdentity); + svg.transition().duration(d).call(zoom.transform, d3.zoomIdentity); } // calculate x y extreme points of viewBox function getViewBoxExtent() { - return [ - [Math.abs(viewX / scale), Math.abs(viewY / scale)], - [Math.abs(viewX / scale) + graphWidth / scale, Math.abs(viewY / scale) + graphHeight / scale] - ]; + return [ + [Math.abs(viewX / scale), Math.abs(viewY / scale)], + [Math.abs(viewX / scale) + graphWidth / scale, Math.abs(viewY / scale) + graphHeight / scale] + ]; } // active zooming feature function invokeActiveZooming() { - if (coastline.select("#sea_island").size() && +coastline.select("#sea_island").attr("auto-filter")) { - // toggle shade/blur filter for coatline on zoom - const filter = scale > 1.5 && scale <= 2.6 ? null : scale > 2.6 ? "url(#blurFilter)" : "url(#dropShadow)"; - coastline.select("#sea_island").attr("filter", filter); - } + if (coastline.select("#sea_island").size() && +coastline.select("#sea_island").attr("auto-filter")) { + // toggle shade/blur filter for coatline on zoom + const filter = scale > 1.5 && scale <= 2.6 ? null : scale > 2.6 ? "url(#blurFilter)" : "url(#dropShadow)"; + coastline.select("#sea_island").attr("filter", filter); + } - // rescale lables on zoom - if (labels.style("display") !== "none") { - labels.selectAll("g").each(function () { - if (this.id === "burgLabels") return; - const desired = +this.dataset.size; - const relative = Math.max(rn((desired + desired / scale) / 2, 2), 1); - if (rescaleLabels.checked) this.setAttribute("font-size", relative); + // rescale lables on zoom + if (labels.style("display") !== "none") { + labels.selectAll("g").each(function () { + if (this.id === "burgLabels") return; + const desired = +this.dataset.size; + const relative = Math.max(rn((desired + desired / scale) / 2, 2), 1); + if (rescaleLabels.checked) this.setAttribute("font-size", relative); - const hidden = hideLabels.checked && (relative * scale < 6 || relative * scale > 60); - if (hidden) this.classList.add("hidden"); - else this.classList.remove("hidden"); - }); - } + const hidden = hideLabels.checked && (relative * scale < 6 || relative * scale > 60); + if (hidden) this.classList.add("hidden"); + else this.classList.remove("hidden"); + }); + } - // rescale emblems on zoom - if (emblems.style("display") !== "none") { - emblems.selectAll("g").each(function () { - const size = this.getAttribute("font-size") * scale; - const hidden = hideEmblems.checked && (size < 25 || size > 300); - if (hidden) this.classList.add("hidden"); - else this.classList.remove("hidden"); - if (!hidden && window.COArenderer && this.children.length && !this.children[0].getAttribute("href")) renderGroupCOAs(this); - }); - } + // rescale emblems on zoom + if (emblems.style("display") !== "none") { + emblems.selectAll("g").each(function () { + const size = this.getAttribute("font-size") * scale; + const hidden = hideEmblems.checked && (size < 25 || size > 300); + if (hidden) this.classList.add("hidden"); + else this.classList.remove("hidden"); + if (!hidden && window.COArenderer && this.children.length && !this.children[0].getAttribute("href")) renderGroupCOAs(this); + }); + } - // turn off ocean pattern if scale is big (improves performance) - oceanPattern - .select("rect") - .attr("fill", scale > 10 ? "#fff" : "url(#oceanic)") - .attr("opacity", scale > 10 ? 0.2 : null); + // turn off ocean pattern if scale is big (improves performance) + oceanPattern + .select("rect") + .attr("fill", scale > 10 ? "#fff" : "url(#oceanic)") + .attr("opacity", scale > 10 ? 0.2 : null); - // change states halo width - if (!customization) { - const desired = +statesHalo.attr("data-width"); - const haloSize = rn(desired / scale ** 0.8, 2); - statesHalo.attr("stroke-width", haloSize).style("display", haloSize > 0.1 ? "block" : "none"); - } + // change states halo width + if (!customization) { + const desired = +statesHalo.attr("data-width"); + const haloSize = rn(desired / scale ** 0.8, 2); + statesHalo.attr("stroke-width", haloSize).style("display", haloSize > 0.1 ? "block" : "none"); + } - // rescale map markers - +markers.attr("rescale") && + // rescale map markers + +markers.attr("rescale") && pack.markers?.forEach(marker => { - const {i, x, y, size = 30, hidden} = marker; - const el = !hidden && document.getElementById(`marker${i}`); - if (!el) return; + const {i, x, y, size = 30, hidden} = marker; + const el = !hidden && document.getElementById(`marker${i}`); + if (!el) return; - const zoomedSize = Math.max(rn(size / 5 + 24 / scale, 2), 1); - el.setAttribute("width", zoomedSize); - el.setAttribute("height", zoomedSize); - el.setAttribute("x", rn(x - zoomedSize / 2, 1)); - el.setAttribute("y", rn(y - zoomedSize, 1)); + const zoomedSize = Math.max(rn(size / 5 + 24 / scale, 2), 1); + el.setAttribute("width", zoomedSize); + el.setAttribute("height", zoomedSize); + el.setAttribute("x", rn(x - zoomedSize / 2, 1)); + el.setAttribute("y", rn(y - zoomedSize, 1)); }); - // rescale rulers to have always the same size - if (ruler.style("display") !== "none") { - const size = rn((10 / scale ** 0.3) * 2, 2); - ruler.selectAll("text").attr("font-size", size); - } + // rescale rulers to have always the same size + if (ruler.style("display") !== "none") { + const size = rn((10 / scale ** 0.3) * 2, 2); + ruler.selectAll("text").attr("font-size", size); + } } async function renderGroupCOAs(g) { - const [group, type] = g.id === "burgEmblems" ? [pack.burgs, "burg"] : g.id === "provinceEmblems" ? [pack.provinces, "province"] : [pack.states, "state"]; - for (let use of g.children) { - const i = +use.dataset.i; - const id = type + "COA" + i; - COArenderer.trigger(id, group[i].coa); - use.setAttribute("href", "#" + id); - } + const [group, type] = g.id === "burgEmblems" ? [pack.burgs, "burg"] : g.id === "provinceEmblems" ? [pack.provinces, "province"] : [pack.states, "state"]; + for (let use of g.children) { + const i = +use.dataset.i; + const id = type + "COA" + i; + COArenderer.trigger(id, group[i].coa); + use.setAttribute("href", "#" + id); + } } // add drag to upload logic, pull request from @evyatron void (function addDragToUpload() { - document.addEventListener("dragover", function (e) { - e.stopPropagation(); - e.preventDefault(); - document.getElementById("mapOverlay").style.display = null; - }); - - document.addEventListener("dragleave", function (e) { - document.getElementById("mapOverlay").style.display = "none"; - }); - - document.addEventListener("drop", function (e) { - e.stopPropagation(); - e.preventDefault(); - - const overlay = document.getElementById("mapOverlay"); - overlay.style.display = "none"; - if (e.dataTransfer.items == null || e.dataTransfer.items.length !== 1) return; // no files or more than one - const file = e.dataTransfer.items[0].getAsFile(); - if (file.name.indexOf(".map") == -1) { - // not a .map file - alertMessage.innerHTML = "Please upload a .map file you have previously downloaded"; - $("#alert").dialog({ - resizable: false, - title: "Invalid file format", - position: {my: "center", at: "center", of: "svg"}, - buttons: { - Close: function () { - $(this).dialog("close"); - } - } - }); - return; - } - - // all good - show uploading text and load the map - overlay.style.display = null; - overlay.innerHTML = "Uploading..."; - if (closeDialogs) closeDialogs(); - uploadMap(file, () => { - overlay.style.display = "none"; - overlay.innerHTML = "Drop a .map file to open"; + document.addEventListener("dragover", function (e) { + e.stopPropagation(); + e.preventDefault(); + document.getElementById("mapOverlay").style.display = null; + }); + + document.addEventListener("dragleave", function (e) { + document.getElementById("mapOverlay").style.display = "none"; + }); + + document.addEventListener("drop", function (e) { + e.stopPropagation(); + e.preventDefault(); + + const overlay = document.getElementById("mapOverlay"); + overlay.style.display = "none"; + if (e.dataTransfer.items == null || e.dataTransfer.items.length !== 1) return; // no files or more than one + const file = e.dataTransfer.items[0].getAsFile(); + if (file.name.indexOf(".map") == -1) { + // not a .map file + alertMessage.innerHTML = "Please upload a .map file you have previously downloaded"; + $("#alert").dialog({ + resizable: false, + title: "Invalid file format", + position: {my: "center", at: "center", of: "svg"}, + buttons: { + Close: function () { + $(this).dialog("close"); + } + } + }); + return; + } + + // all good - show uploading text and load the map + overlay.style.display = null; + overlay.innerHTML = "Uploading..."; + if (closeDialogs) closeDialogs(); + uploadMap(file, () => { + overlay.style.display = "none"; + overlay.innerHTML = "Drop a .map file to open"; + }); }); - }); })(); function generate() { - try { - const timeStart = performance.now(); - invokeActiveZooming(); - generateSeed(); - INFO && console.group("Generated Map " + seed); - applyMapSize(); - randomizeOptions(); - placePoints(); - calculateVoronoi(grid, grid.points); - drawScaleBar(); - HeightmapGenerator.generate(); - markFeatures(); - markupGridOcean(); - addLakesInDeepDepressions(); - openNearSeaLakes(); + try { + const timeStart = performance.now(); + invokeActiveZooming(); + generateSeed(); + INFO && console.group("Generated Map " + seed); + applyMapSize(); + randomizeOptions(); + placePoints(); + calculateVoronoi(grid, grid.points); + drawScaleBar(); + HeightmapGenerator.generate(); + markFeatures(); + markupGridOcean(); + addLakesInDeepDepressions(); + openNearSeaLakes(); - OceanLayers(); - defineMapSize(); - calculateMapCoordinates(); - calculateTemperatures(); - generatePrecipitation(); - reGraph(); - drawCoastline(); + OceanLayers(); + defineMapSize(); + calculateMapCoordinates(); + calculateTemperatures(); + generatePrecipitation(); + reGraph(); + drawCoastline(); - Rivers.generate(); - drawRivers(); - Lakes.defineGroup(); - defineBiomes(); + Rivers.generate(); + drawRivers(); + Lakes.defineGroup(); + defineBiomes(); - rankCells(); - Cultures.generate(); - Cultures.expand(); - BurgsAndStates.generate(); - Religions.generate(); - BurgsAndStates.defineStateForms(); - BurgsAndStates.generateProvinces(); - BurgsAndStates.defineBurgFeatures(); + rankCells(); + Cultures.generate(); + Cultures.expand(); + BurgsAndStates.generate(); + Religions.generate(); + BurgsAndStates.defineStateForms(); + BurgsAndStates.generateProvinces(); + BurgsAndStates.defineBurgFeatures(); - drawStates(); - drawBorders(); - BurgsAndStates.drawStateLabels(); + drawStates(); + drawBorders(); + BurgsAndStates.drawStateLabels(); - Rivers.specify(); - Lakes.generateName(); + Rivers.specify(); + Lakes.generateName(); - Military.generate(); - Markers.generate(); - addZones(); - Names.getMapName(); + Military.generate(); + Markers.generate(); + addZones(); + Names.getMapName(); - WARN && console.warn(`TOTAL: ${rn((performance.now() - timeStart) / 1000, 2)}s`); - showStatistics(); - INFO && console.groupEnd("Generated Map " + seed); - } catch (error) { - ERROR && console.error(error); - const parsedError = parseError(error); - clearMainTip(); + WARN && console.warn(`TOTAL: ${rn((performance.now() - timeStart) / 1000, 2)}s`); + showStatistics(); + INFO && console.groupEnd("Generated Map " + seed); + } catch (error) { + ERROR && console.error(error); + const parsedError = parseError(error); + clearMainTip(); - alertMessage.innerHTML = `An error is occured on map generation. Please retry. + alertMessage.innerHTML = `An error is occured on map generation. Please retry.
    If error is critical, clear the stored data and try again.

    ${parsedError}

    `; - $("#alert").dialog({ - resizable: false, - title: "Generation error", - width: "32em", - buttons: { - "Clear data": function () { - localStorage.clear(); - localStorage.setItem("version", version); - }, - Regenerate: function () { - regenerateMap("generation error"); - $(this).dialog("close"); - }, - Ignore: function () { - $(this).dialog("close"); - } - }, - position: {my: "center", at: "center", of: "svg"} - }); - } + $("#alert").dialog({ + resizable: false, + title: "Generation error", + width: "32em", + buttons: { + "Clear data": function () { + localStorage.clear(); + localStorage.setItem("version", version); + }, + Regenerate: function () { + regenerateMap("generation error"); + $(this).dialog("close"); + }, + Ignore: function () { + $(this).dialog("close"); + } + }, + position: {my: "center", at: "center", of: "svg"} + }); + } } // generate map seed (string!) or get it from URL searchParams function generateSeed() { - const first = !mapHistory[0]; - const url = new URL(window.location.href); - const params = url.searchParams; - const urlSeed = url.searchParams.get("seed"); - if (first && params.get("from") === "MFCG" && urlSeed.length === 13) seed = urlSeed.slice(0, -4); - else if (first && urlSeed) seed = urlSeed; - else if (optionsSeed.value && optionsSeed.value != seed) seed = optionsSeed.value; - else seed = Math.floor(Math.random() * 1e9).toString(); - optionsSeed.value = seed; - Math.random = aleaPRNG(seed); + const first = !mapHistory[0]; + const url = new URL(window.location.href); + const params = url.searchParams; + const urlSeed = url.searchParams.get("seed"); + if (first && params.get("from") === "MFCG" && urlSeed.length === 13) seed = urlSeed.slice(0, -4); + else if (first && urlSeed) seed = urlSeed; + else if (optionsSeed.value && optionsSeed.value != seed) seed = optionsSeed.value; + else seed = Math.floor(Math.random() * 1e9).toString(); + optionsSeed.value = seed; + Math.random = aleaPRNG(seed); } // Place points to calculate Voronoi diagram function placePoints() { - TIME && console.time("placePoints"); - Math.random = aleaPRNG(seed); // reset PRNG + TIME && console.time("placePoints"); + Math.random = aleaPRNG(seed); // reset PRNG - const cellsDesired = +pointsInput.dataset.cells; - const spacing = (grid.spacing = rn(Math.sqrt((graphWidth * graphHeight) / cellsDesired), 2)); // spacing between points before jirrering - grid.boundary = getBoundaryPoints(graphWidth, graphHeight, spacing); - grid.points = getJitteredGrid(graphWidth, graphHeight, spacing); // jittered square grid - grid.cellsX = Math.floor((graphWidth + 0.5 * spacing) / spacing); - grid.cellsY = Math.floor((graphHeight + 0.5 * spacing) / spacing); - TIME && console.timeEnd("placePoints"); + const cellsDesired = +pointsInput.dataset.cells; + const spacing = (grid.spacing = rn(Math.sqrt((graphWidth * graphHeight) / cellsDesired), 2)); // spacing between points before jirrering + grid.boundary = getBoundaryPoints(graphWidth, graphHeight, spacing); + grid.points = getJitteredGrid(graphWidth, graphHeight, spacing); // jittered square grid + grid.cellsX = Math.floor((graphWidth + 0.5 * spacing) / spacing); + grid.cellsY = Math.floor((graphHeight + 0.5 * spacing) / spacing); + TIME && console.timeEnd("placePoints"); } // calculate Delaunay and then Voronoi diagram function calculateVoronoi(graph, points) { - TIME && console.time("calculateDelaunay"); - const n = points.length; - const allPoints = points.concat(grid.boundary); - const delaunay = Delaunator.from(allPoints); - TIME && console.timeEnd("calculateDelaunay"); + TIME && console.time("calculateDelaunay"); + const n = points.length; + const allPoints = points.concat(grid.boundary); + const delaunay = Delaunator.from(allPoints); + TIME && console.timeEnd("calculateDelaunay"); - TIME && console.time("calculateVoronoi"); - const voronoi = new Voronoi(delaunay, allPoints, n); - graph.cells = voronoi.cells; - graph.cells.i = n < 65535 ? Uint16Array.from(d3.range(n)) : Uint32Array.from(d3.range(n)); // array of indexes - graph.vertices = voronoi.vertices; - TIME && console.timeEnd("calculateVoronoi"); + TIME && console.time("calculateVoronoi"); + const voronoi = new Voronoi(delaunay, allPoints, n); + graph.cells = voronoi.cells; + graph.cells.i = n < 65535 ? Uint16Array.from(d3.range(n)) : Uint32Array.from(d3.range(n)); // array of indexes + graph.vertices = voronoi.vertices; + TIME && console.timeEnd("calculateVoronoi"); } // Mark features (ocean, lakes, islands) and calculate distance field function markFeatures() { - TIME && console.time("markFeatures"); - Math.random = aleaPRNG(seed); // get the same result on heightmap edit in Erase mode + TIME && console.time("markFeatures"); + Math.random = aleaPRNG(seed); // get the same result on heightmap edit in Erase mode - const cells = grid.cells, - heights = grid.cells.h; - cells.f = new Uint16Array(cells.i.length); // cell feature number - cells.t = new Int8Array(cells.i.length); // cell type: 1 = land coast; -1 = water near coast - grid.features = [0]; + const cells = grid.cells, + heights = grid.cells.h; + cells.f = new Uint16Array(cells.i.length); // cell feature number + cells.t = new Int8Array(cells.i.length); // cell type: 1 = land coast; -1 = water near coast + grid.features = [0]; - for (let i = 1, queue = [0]; queue[0] !== -1; i++) { - cells.f[queue[0]] = i; // feature number - const land = heights[queue[0]] >= 20; - let border = false; // true if feature touches map border + for (let i = 1, queue = [0]; queue[0] !== -1; i++) { + cells.f[queue[0]] = i; // feature number + const land = heights[queue[0]] >= 20; + let border = false; // true if feature touches map border - while (queue.length) { - const q = queue.pop(); - if (cells.b[q]) border = true; + while (queue.length) { + const q = queue.pop(); + if (cells.b[q]) border = true; - cells.c[q].forEach(c => { - const cLand = heights[c] >= 20; - if (land === cLand && !cells.f[c]) { - cells.f[c] = i; - queue.push(c); - } else if (land && !cLand) { - cells.t[q] = 1; - cells.t[c] = -1; + cells.c[q].forEach(c => { + const cLand = heights[c] >= 20; + if (land === cLand && !cells.f[c]) { + cells.f[c] = i; + queue.push(c); + } else if (land && !cLand) { + cells.t[q] = 1; + cells.t[c] = -1; + } + }); } - }); + const type = land ? "island" : border ? "ocean" : "lake"; + grid.features.push({i, land, border, type}); + + queue[0] = cells.f.findIndex(f => !f); // find unmarked cell } - const type = land ? "island" : border ? "ocean" : "lake"; - grid.features.push({i, land, border, type}); - queue[0] = cells.f.findIndex(f => !f); // find unmarked cell - } - - TIME && console.timeEnd("markFeatures"); + TIME && console.timeEnd("markFeatures"); } function markupGridOcean() { - TIME && console.time("markupGridOcean"); - markup(grid.cells, -2, -1, -10); - TIME && console.timeEnd("markupGridOcean"); + TIME && console.time("markupGridOcean"); + markup(grid.cells, -2, -1, -10); + TIME && console.timeEnd("markupGridOcean"); } function markup(cells, start, increment, limit) { - for (let t = start, count = Infinity; count > 0 && t > limit; t += increment) { - count = 0; - const prevT = t - increment; - for (let i = 0; i < cells.i.length; i++) { - if (cells.t[i] !== prevT) continue; + for (let t = start, count = Infinity; count > 0 && t > limit; t += increment) { + count = 0; + const prevT = t - increment; + for (let i = 0; i < cells.i.length; i++) { + if (cells.t[i] !== prevT) continue; - for (const c of cells.c[i]) { - if (cells.t[c]) continue; - cells.t[c] = t; - count++; - } + for (const c of cells.c[i]) { + if (cells.t[c]) continue; + cells.t[c] = t; + count++; + } + } } - } } function addLakesInDeepDepressions() { - TIME && console.time("addLakesInDeepDepressions"); - const {cells, features} = grid; - const {c, h, b} = cells; - const ELEVATION_LIMIT = +document.getElementById("lakeElevationLimitOutput").value; - if (ELEVATION_LIMIT === 80) return; + TIME && console.time("addLakesInDeepDepressions"); + const {cells, features} = grid; + const {c, h, b} = cells; + const ELEVATION_LIMIT = +document.getElementById("lakeElevationLimitOutput").value; + if (ELEVATION_LIMIT === 80) return; - for (const i of cells.i) { - if (b[i] || h[i] < 20) continue; + for (const i of cells.i) { + if (b[i] || h[i] < 20) continue; - const minHeight = d3.min(c[i].map(c => h[c])); - if (h[i] > minHeight) continue; + const minHeight = d3.min(c[i].map(c => h[c])); + if (h[i] > minHeight) continue; - let deep = true; - const threshold = h[i] + ELEVATION_LIMIT; - const queue = [i]; - const checked = []; - checked[i] = true; + let deep = true; + const threshold = h[i] + ELEVATION_LIMIT; + const queue = [i]; + const checked = []; + checked[i] = true; - // check if elevated cell can potentially pour to water - while (deep && queue.length) { - const q = queue.pop(); + // check if elevated cell can potentially pour to water + while (deep && queue.length) { + const q = queue.pop(); - for (const n of c[q]) { - if (checked[n]) continue; - if (h[n] >= threshold) continue; - if (h[n] < 20) { - deep = false; - break; + for (const n of c[q]) { + if (checked[n]) continue; + if (h[n] >= threshold) continue; + if (h[n] < 20) { + deep = false; + break; + } + + checked[n] = true; + queue.push(n); + } } - checked[n] = true; - queue.push(n); - } + // if not, add a lake + if (deep) { + const lakeCells = [i].concat(c[i].filter(n => h[n] === h[i])); + addLake(lakeCells); + } } - // if not, add a lake - if (deep) { - const lakeCells = [i].concat(c[i].filter(n => h[n] === h[i])); - addLake(lakeCells); + function addLake(lakeCells) { + const f = features.length; + + lakeCells.forEach(i => { + cells.h[i] = 19; + cells.t[i] = -1; + cells.f[i] = f; + c[i].forEach(n => !lakeCells.includes(n) && (cells.t[c] = 1)); + }); + + features.push({i: f, land: false, border: false, type: "lake"}); } - } - function addLake(lakeCells) { - const f = features.length; - - lakeCells.forEach(i => { - cells.h[i] = 19; - cells.t[i] = -1; - cells.f[i] = f; - c[i].forEach(n => !lakeCells.includes(n) && (cells.t[c] = 1)); - }); - - features.push({i: f, land: false, border: false, type: "lake"}); - } - - TIME && console.timeEnd("addLakesInDeepDepressions"); + TIME && console.timeEnd("addLakesInDeepDepressions"); } // near sea lakes usually get a lot of water inflow, most of them should brake threshold and flow out to sea (see Ancylus Lake) function openNearSeaLakes() { - if (templateInput.value === "Atoll") return; // no need for Atolls + if (templateInput.value === "Atoll") return; // no need for Atolls - const cells = grid.cells; - const features = grid.features; - if (!features.find(f => f.type === "lake")) return; // no lakes - TIME && console.time("openLakes"); - const LIMIT = 22; // max height that can be breached by water + const cells = grid.cells; + const features = grid.features; + if (!features.find(f => f.type === "lake")) return; // no lakes + TIME && console.time("openLakes"); + const LIMIT = 22; // max height that can be breached by water - for (const i of cells.i) { - const lake = cells.f[i]; - if (features[lake].type !== "lake") continue; // not a lake cell + for (const i of cells.i) { + const lake = cells.f[i]; + if (features[lake].type !== "lake") continue; // not a lake cell - check_neighbours: for (const c of cells.c[i]) { - if (cells.t[c] !== 1 || cells.h[c] > LIMIT) continue; // water cannot brake this + check_neighbours: for (const c of cells.c[i]) { + if (cells.t[c] !== 1 || cells.h[c] > LIMIT) continue; // water cannot brake this - for (const n of cells.c[c]) { - const ocean = cells.f[n]; - if (features[ocean].type !== "ocean") continue; // not an ocean - removeLake(c, lake, ocean); - break check_neighbours; - } + for (const n of cells.c[c]) { + const ocean = cells.f[n]; + if (features[ocean].type !== "ocean") continue; // not an ocean + removeLake(c, lake, ocean); + break check_neighbours; + } + } } - } - function removeLake(threshold, lake, ocean) { - cells.h[threshold] = 19; - cells.t[threshold] = -1; - cells.f[threshold] = ocean; - cells.c[threshold].forEach(function (c) { - if (cells.h[c] >= 20) cells.t[c] = 1; // mark as coastline - }); - features[lake].type = "ocean"; // mark former lake as ocean - } + function removeLake(threshold, lake, ocean) { + cells.h[threshold] = 19; + cells.t[threshold] = -1; + cells.f[threshold] = ocean; + cells.c[threshold].forEach(function (c) { + if (cells.h[c] >= 20) cells.t[c] = 1; // mark as coastline + }); + features[lake].type = "ocean"; // mark former lake as ocean + } - TIME && console.timeEnd("openLakes"); + TIME && console.timeEnd("openLakes"); } // define map size and position based on template and random factor function defineMapSize() { - const [size, latitude] = getSizeAndLatitude(); - const randomize = new URL(window.location.href).searchParams.get("options") === "default"; // ignore stored options - if (randomize || !locked("mapSize")) mapSizeOutput.value = mapSizeInput.value = rn(size); - if (randomize || !locked("latitude")) latitudeOutput.value = latitudeInput.value = rn(latitude); + const [size, latitude] = getSizeAndLatitude(); + const randomize = new URL(window.location.href).searchParams.get("options") === "default"; // ignore stored options + if (randomize || !locked("mapSize")) mapSizeOutput.value = mapSizeInput.value = rn(size); + if (randomize || !locked("latitude")) latitudeOutput.value = latitudeInput.value = rn(latitude); - function getSizeAndLatitude() { - const template = document.getElementById("templateInput").value; // heightmap template - const part = grid.features.some(f => f.land && f.border); // if land goes over map borders - const max = part ? 80 : 100; // max size - const lat = () => gauss(P(0.5) ? 40 : 60, 15, 25, 75); // latiture shift + function getSizeAndLatitude() { + const template = document.getElementById("templateInput").value; // heightmap template + const part = grid.features.some(f => f.land && f.border); // if land goes over map borders + const max = part ? 80 : 100; // max size + const lat = () => gauss(P(0.5) ? 40 : 60, 15, 25, 75); // latiture shift - if (!part) { - if (template === "Pangea") return [100, 50]; - if (template === "Shattered" && P(0.7)) return [100, 50]; - if (template === "Continents" && P(0.5)) return [100, 50]; - if (template === "Archipelago" && P(0.35)) return [100, 50]; - if (template === "High Island" && P(0.25)) return [100, 50]; - if (template === "Low Island" && P(0.1)) return [100, 50]; + if (!part) { + if (template === "Pangea") return [100, 50]; + if (template === "Shattered" && P(0.7)) return [100, 50]; + if (template === "Continents" && P(0.5)) return [100, 50]; + if (template === "Archipelago" && P(0.35)) return [100, 50]; + if (template === "High Island" && P(0.25)) return [100, 50]; + if (template === "Low Island" && P(0.1)) return [100, 50]; + } + + if (template === "Pangea") return [gauss(70, 20, 30, max), lat()]; + if (template === "Volcano") return [gauss(20, 20, 10, max), lat()]; + if (template === "Mediterranean") return [gauss(25, 30, 15, 80), lat()]; + if (template === "Peninsula") return [gauss(15, 15, 5, 80), lat()]; + if (template === "Isthmus") return [gauss(15, 20, 3, 80), lat()]; + if (template === "Atoll") return [gauss(5, 10, 2, max), lat()]; + + return [gauss(30, 20, 15, max), lat()]; // Continents, Archipelago, High Island, Low Island } - - if (template === "Pangea") return [gauss(70, 20, 30, max), lat()]; - if (template === "Volcano") return [gauss(20, 20, 10, max), lat()]; - if (template === "Mediterranean") return [gauss(25, 30, 15, 80), lat()]; - if (template === "Peninsula") return [gauss(15, 15, 5, 80), lat()]; - if (template === "Isthmus") return [gauss(15, 20, 3, 80), lat()]; - if (template === "Atoll") return [gauss(5, 10, 2, max), lat()]; - - return [gauss(30, 20, 15, max), lat()]; // Continents, Archipelago, High Island, Low Island - } } // calculate map position on globe function calculateMapCoordinates() { - const size = +document.getElementById("mapSizeOutput").value; - const latShift = +document.getElementById("latitudeOutput").value; + const size = +document.getElementById("mapSizeOutput").value; + const latShift = +document.getElementById("latitudeOutput").value; - const latT = rn((size / 100) * 180, 1); - const latN = rn(90 - ((180 - latT) * latShift) / 100, 1); - const latS = rn(latN - latT, 1); + const latT = rn((size / 100) * 180, 1); + const latN = rn(90 - ((180 - latT) * latShift) / 100, 1); + const latS = rn(latN - latT, 1); - const lon = rn(Math.min(((graphWidth / graphHeight) * latT) / 2, 180)); - mapCoordinates = {latT, latN, latS, lonT: lon * 2, lonW: -lon, lonE: lon}; + const lon = rn(Math.min(((graphWidth / graphHeight) * latT) / 2, 180)); + mapCoordinates = {latT, latN, latS, lonT: lon * 2, lonW: -lon, lonE: lon}; } // temperature model function calculateTemperatures() { - TIME && console.time("calculateTemperatures"); - const cells = grid.cells; - cells.temp = new Int8Array(cells.i.length); // temperature array + TIME && console.time("calculateTemperatures"); + const cells = grid.cells; + cells.temp = new Int8Array(cells.i.length); // temperature array - const tEq = +temperatureEquatorInput.value; - const tPole = +temperaturePoleInput.value; - const tDelta = tEq - tPole; - const int = d3.easePolyInOut.exponent(0.5); // interpolation function + const tEq = +temperatureEquatorInput.value; + const tPole = +temperaturePoleInput.value; + const tDelta = tEq - tPole; + const int = d3.easePolyInOut.exponent(0.5); // interpolation function - d3.range(0, cells.i.length, grid.cellsX).forEach(function (r) { - const y = grid.points[r][1]; - const lat = Math.abs(mapCoordinates.latN - (y / graphHeight) * mapCoordinates.latT); // [0; 90] - const initTemp = tEq - int(lat / 90) * tDelta; - for (let i = r; i < r + grid.cellsX; i++) { - cells.temp[i] = minmax(initTemp - convertToFriendly(cells.h[i]), -128, 127); + d3.range(0, cells.i.length, grid.cellsX).forEach(function (r) { + const y = grid.points[r][1]; + const lat = Math.abs(mapCoordinates.latN - (y / graphHeight) * mapCoordinates.latT); // [0; 90] + const initTemp = tEq - int(lat / 90) * tDelta; + for (let i = r; i < r + grid.cellsX; i++) { + cells.temp[i] = minmax(initTemp - convertToFriendly(cells.h[i]), -128, 127); + } + }); + + // temperature decreases by 6.5 degree C per 1km + function convertToFriendly(h) { + if (h < 20) return 0; + const exponent = +heightExponentInput.value; + const height = Math.pow(h - 18, exponent); + return rn((height / 1000) * 6.5); } - }); - // temperature decreases by 6.5 degree C per 1km - function convertToFriendly(h) { - if (h < 20) return 0; - const exponent = +heightExponentInput.value; - const height = Math.pow(h - 18, exponent); - return rn((height / 1000) * 6.5); - } - - TIME && console.timeEnd("calculateTemperatures"); + TIME && console.timeEnd("calculateTemperatures"); } // simplest precipitation model function generatePrecipitation() { - TIME && console.time("generatePrecipitation"); - prec.selectAll("*").remove(); - const {cells, cellsX, cellsY} = grid; - cells.prec = new Uint8Array(cells.i.length); // precipitation array - const modifier = precInput.value / 100; // user's input + TIME && console.time("generatePrecipitation"); + prec.selectAll("*").remove(); + const {cells, cellsX, cellsY} = grid; + cells.prec = new Uint8Array(cells.i.length); // precipitation array + const modifier = precInput.value / 100; // user's input - const westerly = []; - const easterly = []; - let southerly = 0; - let northerly = 0; + const westerly = []; + const easterly = []; + let southerly = 0; + let northerly = 0; - // precipitation modifier per latitude band - // x4 = 0-5 latitude: wet through the year (rising zone) - // x2 = 5-20 latitude: wet summer (rising zone), dry winter (sinking zone) - // x1 = 20-30 latitude: dry all year (sinking zone) - // x2 = 30-50 latitude: wet winter (rising zone), dry summer (sinking zone) - // x3 = 50-60 latitude: wet all year (rising zone) - // x2 = 60-70 latitude: wet summer (rising zone), dry winter (sinking zone) - // x1 = 70-85 latitude: dry all year (sinking zone) - // x0.5 = 85-90 latitude: dry all year (sinking zone) - const lalitudeModifier = [4, 2, 2, 2, 1, 1, 2, 2, 2, 2, 3, 3, 2, 2, 1, 1, 1, 0.5]; - const MAX_PASSABLE_ELEVATION = 85; + // precipitation modifier per latitude band + // x4 = 0-5 latitude: wet through the year (rising zone) + // x2 = 5-20 latitude: wet summer (rising zone), dry winter (sinking zone) + // x1 = 20-30 latitude: dry all year (sinking zone) + // x2 = 30-50 latitude: wet winter (rising zone), dry summer (sinking zone) + // x3 = 50-60 latitude: wet all year (rising zone) + // x2 = 60-70 latitude: wet summer (rising zone), dry winter (sinking zone) + // x1 = 70-85 latitude: dry all year (sinking zone) + // x0.5 = 85-90 latitude: dry all year (sinking zone) + const lalitudeModifier = [4, 2, 2, 2, 1, 1, 2, 2, 2, 2, 3, 3, 2, 2, 1, 1, 1, 0.5]; + const MAX_PASSABLE_ELEVATION = 85; - // define wind directions based on cells latitude and prevailing winds there - d3.range(0, cells.i.length, cellsX).forEach(function (c, i) { - const lat = mapCoordinates.latN - (i / cellsY) * mapCoordinates.latT; - const latBand = ((Math.abs(lat) - 1) / 5) | 0; - const latMod = lalitudeModifier[latBand]; - const windTier = (Math.abs(lat - 89) / 30) | 0; // 30d tiers from 0 to 5 from N to S - const {isWest, isEast, isNorth, isSouth} = getWindDirections(windTier); + // define wind directions based on cells latitude and prevailing winds there + d3.range(0, cells.i.length, cellsX).forEach(function (c, i) { + const lat = mapCoordinates.latN - (i / cellsY) * mapCoordinates.latT; + const latBand = ((Math.abs(lat) - 1) / 5) | 0; + const latMod = lalitudeModifier[latBand]; + const windTier = (Math.abs(lat - 89) / 30) | 0; // 30d tiers from 0 to 5 from N to S + const {isWest, isEast, isNorth, isSouth} = getWindDirections(windTier); - if (isWest) westerly.push([c, latMod, windTier]); - if (isEast) easterly.push([c + cellsX - 1, latMod, windTier]); - if (isNorth) northerly++; - if (isSouth) southerly++; - }); - - // distribute winds by direction - if (westerly.length) passWind(westerly, 120 * modifier, 1, cellsX); - if (easterly.length) passWind(easterly, 120 * modifier, -1, cellsX); - - const vertT = southerly + northerly; - if (northerly) { - const bandN = ((Math.abs(mapCoordinates.latN) - 1) / 5) | 0; - const latModN = mapCoordinates.latT > 60 ? d3.mean(lalitudeModifier) : lalitudeModifier[bandN]; - const maxPrecN = (northerly / vertT) * 60 * modifier * latModN; - passWind(d3.range(0, cellsX, 1), maxPrecN, cellsX, cellsY); - } - - if (southerly) { - const bandS = ((Math.abs(mapCoordinates.latS) - 1) / 5) | 0; - const latModS = mapCoordinates.latT > 60 ? d3.mean(lalitudeModifier) : lalitudeModifier[bandS]; - const maxPrecS = (southerly / vertT) * 60 * modifier * latModS; - passWind(d3.range(cells.i.length - cellsX, cells.i.length, 1), maxPrecS, -cellsX, cellsY); - } - - function getWindDirections(tier) { - const angle = options.winds[tier]; - - const isWest = angle > 40 && angle < 140; - const isEast = angle > 220 && angle < 320; - const isNorth = angle > 100 && angle < 260; - const isSouth = angle > 280 || angle < 80; - - return {isWest, isEast, isNorth, isSouth}; - } - - function passWind(source, maxPrec, next, steps) { - const maxPrecInit = maxPrec; - - for (let first of source) { - if (first[0]) { - maxPrec = Math.min(maxPrecInit * first[1], 255); - first = first[0]; - } - - let humidity = maxPrec - cells.h[first]; // initial water amount - if (humidity <= 0) continue; // if first cell in row is too elevated cosdired wind dry - - for (let s = 0, current = first; s < steps; s++, current += next) { - if (cells.temp[current] < -5) continue; // no flux in permafrost - - if (cells.h[current] < 20) { - // water cell - if (cells.h[current + next] >= 20) { - cells.prec[current + next] += Math.max(humidity / rand(10, 20), 1); // coastal precipitation - } else { - humidity = Math.min(humidity + 5 * modifier, maxPrec); // wind gets more humidity passing water cell - cells.prec[current] += 5 * modifier; // water cells precipitation (need to correctly pour water through lakes) - } - continue; - } - - // land cell - const isPassable = cells.h[current + next] <= MAX_PASSABLE_ELEVATION; - const precipitation = isPassable ? getPrecipitation(humidity, current, next) : humidity; - cells.prec[current] += precipitation; - const evaporation = precipitation > 1.5 ? 1 : 0; // some humidity evaporates back to the atmosphere - humidity = isPassable ? minmax(humidity - precipitation + evaporation, 0, maxPrec) : 0; - } - } - } - - function getPrecipitation(humidity, i, n) { - const normalLoss = Math.max(humidity / (10 * modifier), 1); // precipitation in normal conditions - const diff = Math.max(cells.h[i + n] - cells.h[i], 0); // difference in height - const mod = (cells.h[i + n] / 70) ** 2; // 50 stands for hills, 70 for mountains - return minmax(normalLoss + diff * mod, 1, humidity); - } - - void (function drawWindDirection() { - const wind = prec.append("g").attr("id", "wind"); - - d3.range(0, 6).forEach(function (t) { - if (westerly.length > 1) { - const west = westerly.filter(w => w[2] === t); - if (west && west.length > 3) { - const from = west[0][0], - to = west[west.length - 1][0]; - const y = (grid.points[from][1] + grid.points[to][1]) / 2; - wind.append("text").attr("x", 20).attr("y", y).text("\u21C9"); - } - } - if (easterly.length > 1) { - const east = easterly.filter(w => w[2] === t); - if (east && east.length > 3) { - const from = east[0][0], - to = east[east.length - 1][0]; - const y = (grid.points[from][1] + grid.points[to][1]) / 2; - wind - .append("text") - .attr("x", graphWidth - 52) - .attr("y", y) - .text("\u21C7"); - } - } + if (isWest) westerly.push([c, latMod, windTier]); + if (isEast) easterly.push([c + cellsX - 1, latMod, windTier]); + if (isNorth) northerly++; + if (isSouth) southerly++; }); - if (northerly) - wind - .append("text") - .attr("x", graphWidth / 2) - .attr("y", 42) - .text("\u21CA"); - if (southerly) - wind - .append("text") - .attr("x", graphWidth / 2) - .attr("y", graphHeight - 20) - .text("\u21C8"); - })(); + // distribute winds by direction + if (westerly.length) passWind(westerly, 120 * modifier, 1, cellsX); + if (easterly.length) passWind(easterly, 120 * modifier, -1, cellsX); - TIME && console.timeEnd("generatePrecipitation"); + const vertT = southerly + northerly; + if (northerly) { + const bandN = ((Math.abs(mapCoordinates.latN) - 1) / 5) | 0; + const latModN = mapCoordinates.latT > 60 ? d3.mean(lalitudeModifier) : lalitudeModifier[bandN]; + const maxPrecN = (northerly / vertT) * 60 * modifier * latModN; + passWind(d3.range(0, cellsX, 1), maxPrecN, cellsX, cellsY); + } + + if (southerly) { + const bandS = ((Math.abs(mapCoordinates.latS) - 1) / 5) | 0; + const latModS = mapCoordinates.latT > 60 ? d3.mean(lalitudeModifier) : lalitudeModifier[bandS]; + const maxPrecS = (southerly / vertT) * 60 * modifier * latModS; + passWind(d3.range(cells.i.length - cellsX, cells.i.length, 1), maxPrecS, -cellsX, cellsY); + } + + function getWindDirections(tier) { + const angle = options.winds[tier]; + + const isWest = angle > 40 && angle < 140; + const isEast = angle > 220 && angle < 320; + const isNorth = angle > 100 && angle < 260; + const isSouth = angle > 280 || angle < 80; + + return {isWest, isEast, isNorth, isSouth}; + } + + function passWind(source, maxPrec, next, steps) { + const maxPrecInit = maxPrec; + + for (let first of source) { + if (first[0]) { + maxPrec = Math.min(maxPrecInit * first[1], 255); + first = first[0]; + } + + let humidity = maxPrec - cells.h[first]; // initial water amount + if (humidity <= 0) continue; // if first cell in row is too elevated cosdired wind dry + + for (let s = 0, current = first; s < steps; s++, current += next) { + if (cells.temp[current] < -5) continue; // no flux in permafrost + + if (cells.h[current] < 20) { + // water cell + if (cells.h[current + next] >= 20) { + cells.prec[current + next] += Math.max(humidity / rand(10, 20), 1); // coastal precipitation + } else { + humidity = Math.min(humidity + 5 * modifier, maxPrec); // wind gets more humidity passing water cell + cells.prec[current] += 5 * modifier; // water cells precipitation (need to correctly pour water through lakes) + } + continue; + } + + // land cell + const isPassable = cells.h[current + next] <= MAX_PASSABLE_ELEVATION; + const precipitation = isPassable ? getPrecipitation(humidity, current, next) : humidity; + cells.prec[current] += precipitation; + const evaporation = precipitation > 1.5 ? 1 : 0; // some humidity evaporates back to the atmosphere + humidity = isPassable ? minmax(humidity - precipitation + evaporation, 0, maxPrec) : 0; + } + } + } + + function getPrecipitation(humidity, i, n) { + const normalLoss = Math.max(humidity / (10 * modifier), 1); // precipitation in normal conditions + const diff = Math.max(cells.h[i + n] - cells.h[i], 0); // difference in height + const mod = (cells.h[i + n] / 70) ** 2; // 50 stands for hills, 70 for mountains + return minmax(normalLoss + diff * mod, 1, humidity); + } + + void (function drawWindDirection() { + const wind = prec.append("g").attr("id", "wind"); + + d3.range(0, 6).forEach(function (t) { + if (westerly.length > 1) { + const west = westerly.filter(w => w[2] === t); + if (west && west.length > 3) { + const from = west[0][0], + to = west[west.length - 1][0]; + const y = (grid.points[from][1] + grid.points[to][1]) / 2; + wind.append("text").attr("x", 20).attr("y", y).text("\u21C9"); + } + } + if (easterly.length > 1) { + const east = easterly.filter(w => w[2] === t); + if (east && east.length > 3) { + const from = east[0][0], + to = east[east.length - 1][0]; + const y = (grid.points[from][1] + grid.points[to][1]) / 2; + wind + .append("text") + .attr("x", graphWidth - 52) + .attr("y", y) + .text("\u21C7"); + } + } + }); + + if (northerly) + wind + .append("text") + .attr("x", graphWidth / 2) + .attr("y", 42) + .text("\u21CA"); + if (southerly) + wind + .append("text") + .attr("x", graphWidth / 2) + .attr("y", graphHeight - 20) + .text("\u21C8"); + })(); + + TIME && console.timeEnd("generatePrecipitation"); } // recalculate Voronoi Graph to pack cells function reGraph() { - TIME && console.time("reGraph"); - let {cells, points, features} = grid; - const newCells = {p: [], g: [], h: []}; // to store new data - const spacing2 = grid.spacing ** 2; + TIME && console.time("reGraph"); + let {cells, points, features} = grid; + const newCells = {p: [], g: [], h: []}; // to store new data + const spacing2 = grid.spacing ** 2; - for (const i of cells.i) { - const height = cells.h[i]; - const type = cells.t[i]; - if (height < 20 && type !== -1 && type !== -2) continue; // exclude all deep ocean points - if (type === -2 && (i % 4 === 0 || features[cells.f[i]].type === "lake")) continue; // exclude non-coastal lake points - const [x, y] = points[i]; + for (const i of cells.i) { + const height = cells.h[i]; + const type = cells.t[i]; + if (height < 20 && type !== -1 && type !== -2) continue; // exclude all deep ocean points + if (type === -2 && (i % 4 === 0 || features[cells.f[i]].type === "lake")) continue; // exclude non-coastal lake points + const [x, y] = points[i]; - addNewPoint(i, x, y, height); + addNewPoint(i, x, y, height); - // add additional points for cells along coast - if (type === 1 || type === -1) { - if (cells.b[i]) continue; // not for near-border cells - cells.c[i].forEach(function (e) { - if (i > e) return; - if (cells.t[e] === type) { - const dist2 = (y - points[e][1]) ** 2 + (x - points[e][0]) ** 2; - if (dist2 < spacing2) return; // too close to each other - const x1 = rn((x + points[e][0]) / 2, 1); - const y1 = rn((y + points[e][1]) / 2, 1); - addNewPoint(i, x1, y1, height); + // add additional points for cells along coast + if (type === 1 || type === -1) { + if (cells.b[i]) continue; // not for near-border cells + cells.c[i].forEach(function (e) { + if (i > e) return; + if (cells.t[e] === type) { + const dist2 = (y - points[e][1]) ** 2 + (x - points[e][0]) ** 2; + if (dist2 < spacing2) return; // too close to each other + const x1 = rn((x + points[e][0]) / 2, 1); + const y1 = rn((y + points[e][1]) / 2, 1); + addNewPoint(i, x1, y1, height); + } + }); } - }); } - } - function addNewPoint(i, x, y, height) { - newCells.p.push([x, y]); - newCells.g.push(i); - newCells.h.push(height); - } + function addNewPoint(i, x, y, height) { + newCells.p.push([x, y]); + newCells.g.push(i); + newCells.h.push(height); + } - calculateVoronoi(pack, newCells.p); - cells = pack.cells; - cells.p = newCells.p; // points coordinates [x, y] - cells.g = grid.cells.i.length < 65535 ? Uint16Array.from(newCells.g) : Uint32Array.from(newCells.g); // reference to initial grid cell - cells.q = d3.quadtree(cells.p.map((p, d) => [p[0], p[1], d])); // points quadtree for fast search - cells.h = new Uint8Array(newCells.h); // heights - cells.area = new Uint16Array(cells.i.length); // cell area - cells.i.forEach(i => (cells.area[i] = Math.abs(d3.polygonArea(getPackPolygon(i))))); + calculateVoronoi(pack, newCells.p); + cells = pack.cells; + cells.p = newCells.p; // points coordinates [x, y] + cells.g = grid.cells.i.length < 65535 ? Uint16Array.from(newCells.g) : Uint32Array.from(newCells.g); // reference to initial grid cell + cells.q = d3.quadtree(cells.p.map((p, d) => [p[0], p[1], d])); // points quadtree for fast search + cells.h = new Uint8Array(newCells.h); // heights + cells.area = new Uint16Array(cells.i.length); // cell area + cells.i.forEach(i => (cells.area[i] = Math.abs(d3.polygonArea(getPackPolygon(i))))); - TIME && console.timeEnd("reGraph"); + TIME && console.timeEnd("reGraph"); } // Detect and draw the coasline function drawCoastline() { - TIME && console.time("drawCoastline"); - reMarkFeatures(); + TIME && console.time("drawCoastline"); + reMarkFeatures(); - const cells = pack.cells, - vertices = pack.vertices, - n = cells.i.length, - features = pack.features; - const used = new Uint8Array(features.length); // store conneted features - const largestLand = d3.scan( - features.map(f => (f.land ? f.cells : 0)), - (a, b) => b - a - ); - const landMask = defs.select("#land"); - const waterMask = defs.select("#water"); - lineGen.curve(d3.curveBasisClosed); - - for (const i of cells.i) { - const startFromEdge = !i && cells.h[i] >= 20; - if (!startFromEdge && cells.t[i] !== -1 && cells.t[i] !== 1) continue; // non-edge cell - const f = cells.f[i]; - if (used[f]) continue; // already connected - if (features[f].type === "ocean") continue; // ocean cell - - const type = features[f].type === "lake" ? 1 : -1; // type value to search for - const start = findStart(i, type); - if (start === -1) continue; // cannot start here - let vchain = connectVertices(start, type); - if (features[f].type === "lake") relax(vchain, 1.2); - used[f] = 1; - let points = clipPoly( - vchain.map(v => vertices.p[v]), - 1 + const cells = pack.cells, + vertices = pack.vertices, + n = cells.i.length, + features = pack.features; + const used = new Uint8Array(features.length); // store conneted features + const largestLand = d3.scan( + features.map(f => (f.land ? f.cells : 0)), + (a, b) => b - a ); - const area = d3.polygonArea(points); // area with lakes/islands - if (area > 0 && features[f].type === "lake") { - points = points.reverse(); - vchain = vchain.reverse(); + const landMask = defs.select("#land"); + const waterMask = defs.select("#water"); + lineGen.curve(d3.curveBasisClosed); + + for (const i of cells.i) { + const startFromEdge = !i && cells.h[i] >= 20; + if (!startFromEdge && cells.t[i] !== -1 && cells.t[i] !== 1) continue; // non-edge cell + const f = cells.f[i]; + if (used[f]) continue; // already connected + if (features[f].type === "ocean") continue; // ocean cell + + const type = features[f].type === "lake" ? 1 : -1; // type value to search for + const start = findStart(i, type); + if (start === -1) continue; // cannot start here + let vchain = connectVertices(start, type); + if (features[f].type === "lake") relax(vchain, 1.2); + used[f] = 1; + let points = clipPoly( + vchain.map(v => vertices.p[v]), + 1 + ); + const area = d3.polygonArea(points); // area with lakes/islands + if (area > 0 && features[f].type === "lake") { + points = points.reverse(); + vchain = vchain.reverse(); + } + + features[f].area = Math.abs(area); + features[f].vertices = vchain; + + const path = round(lineGen(points)); + if (features[f].type === "lake") { + landMask + .append("path") + .attr("d", path) + .attr("fill", "black") + .attr("id", "land_" + f); + // waterMask.append("path").attr("d", path).attr("fill", "white").attr("id", "water_"+id); // uncomment to show over lakes + lakes + .select("#freshwater") + .append("path") + .attr("d", path) + .attr("id", "lake_" + f) + .attr("data-f", f); // draw the lake + } else { + landMask + .append("path") + .attr("d", path) + .attr("fill", "white") + .attr("id", "land_" + f); + waterMask + .append("path") + .attr("d", path) + .attr("fill", "black") + .attr("id", "water_" + f); + const g = features[f].group === "lake_island" ? "lake_island" : "sea_island"; + coastline + .select("#" + g) + .append("path") + .attr("d", path) + .attr("id", "island_" + f) + .attr("data-f", f); // draw the coastline + } + + // draw ruler to cover the biggest land piece + if (f === largestLand) { + const from = points[d3.scan(points, (a, b) => a[0] - b[0])]; + const to = points[d3.scan(points, (a, b) => b[0] - a[0])]; + rulers.create(Ruler, [from, to]); + } } - features[f].area = Math.abs(area); - features[f].vertices = vchain; - - const path = round(lineGen(points)); - if (features[f].type === "lake") { - landMask - .append("path") - .attr("d", path) - .attr("fill", "black") - .attr("id", "land_" + f); - // waterMask.append("path").attr("d", path).attr("fill", "white").attr("id", "water_"+id); // uncomment to show over lakes - lakes - .select("#freshwater") - .append("path") - .attr("d", path) - .attr("id", "lake_" + f) - .attr("data-f", f); // draw the lake - } else { - landMask - .append("path") - .attr("d", path) - .attr("fill", "white") - .attr("id", "land_" + f); - waterMask - .append("path") - .attr("d", path) - .attr("fill", "black") - .attr("id", "water_" + f); - const g = features[f].group === "lake_island" ? "lake_island" : "sea_island"; - coastline - .select("#" + g) - .append("path") - .attr("d", path) - .attr("id", "island_" + f) - .attr("data-f", f); // draw the coastline + // find cell vertex to start path detection + function findStart(i, t) { + if (t === -1 && cells.b[i]) return cells.v[i].find(v => vertices.c[v].some(c => c >= n)); // map border cell + const filtered = cells.c[i].filter(c => cells.t[c] === t); + const index = cells.c[i].indexOf(d3.min(filtered)); + return index === -1 ? index : cells.v[i][index]; } - // draw ruler to cover the biggest land piece - if (f === largestLand) { - const from = points[d3.scan(points, (a, b) => a[0] - b[0])]; - const to = points[d3.scan(points, (a, b) => b[0] - a[0])]; - rulers.create(Ruler, [from, to]); + // connect vertices to chain + function connectVertices(start, t) { + const chain = []; // vertices chain to form a path + for (let i = 0, current = start; i === 0 || (current !== start && i < 50000); i++) { + const prev = chain[chain.length - 1]; // previous vertex in chain + chain.push(current); // add current vertex to sequence + const c = vertices.c[current]; // cells adjacent to vertex + const v = vertices.v[current]; // neighboring vertices + const c0 = c[0] >= n || cells.t[c[0]] === t; + const c1 = c[1] >= n || cells.t[c[1]] === t; + const c2 = c[2] >= n || cells.t[c[2]] === t; + if (v[0] !== prev && c0 !== c1) current = v[0]; + else if (v[1] !== prev && c1 !== c2) current = v[1]; + else if (v[2] !== prev && c0 !== c2) current = v[2]; + if (current === chain[chain.length - 1]) { + ERROR && console.error("Next vertex is not found"); + break; + } + } + return chain; } - } - // find cell vertex to start path detection - function findStart(i, t) { - if (t === -1 && cells.b[i]) return cells.v[i].find(v => vertices.c[v].some(c => c >= n)); // map border cell - const filtered = cells.c[i].filter(c => cells.t[c] === t); - const index = cells.c[i].indexOf(d3.min(filtered)); - return index === -1 ? index : cells.v[i][index]; - } + // move vertices that are too close to already added ones + function relax(vchain, r) { + const p = vertices.p, + tree = d3.quadtree(); - // connect vertices to chain - function connectVertices(start, t) { - const chain = []; // vertices chain to form a path - for (let i = 0, current = start; i === 0 || (current !== start && i < 50000); i++) { - const prev = chain[chain.length - 1]; // previous vertex in chain - chain.push(current); // add current vertex to sequence - const c = vertices.c[current]; // cells adjacent to vertex - const v = vertices.v[current]; // neighboring vertices - const c0 = c[0] >= n || cells.t[c[0]] === t; - const c1 = c[1] >= n || cells.t[c[1]] === t; - const c2 = c[2] >= n || cells.t[c[2]] === t; - if (v[0] !== prev && c0 !== c1) current = v[0]; - else if (v[1] !== prev && c1 !== c2) current = v[1]; - else if (v[2] !== prev && c0 !== c2) current = v[2]; - if (current === chain[chain.length - 1]) { - ERROR && console.error("Next vertex is not found"); - break; - } + for (let i = 0; i < vchain.length; i++) { + const v = vchain[i]; + let [x, y] = [p[v][0], p[v][1]]; + if (i && vchain[i + 1] && tree.find(x, y, r) !== undefined) { + const v1 = vchain[i - 1], + v2 = vchain[i + 1]; + const [x1, y1] = [p[v1][0], p[v1][1]]; + const [x2, y2] = [p[v2][0], p[v2][1]]; + [x, y] = [(x1 + x2) / 2, (y1 + y2) / 2]; + p[v] = [x, y]; + } + tree.add([x, y]); + } } - return chain; - } - // move vertices that are too close to already added ones - function relax(vchain, r) { - const p = vertices.p, - tree = d3.quadtree(); - - for (let i = 0; i < vchain.length; i++) { - const v = vchain[i]; - let [x, y] = [p[v][0], p[v][1]]; - if (i && vchain[i + 1] && tree.find(x, y, r) !== undefined) { - const v1 = vchain[i - 1], - v2 = vchain[i + 1]; - const [x1, y1] = [p[v1][0], p[v1][1]]; - const [x2, y2] = [p[v2][0], p[v2][1]]; - [x, y] = [(x1 + x2) / 2, (y1 + y2) / 2]; - p[v] = [x, y]; - } - tree.add([x, y]); - } - } - - TIME && console.timeEnd("drawCoastline"); + TIME && console.timeEnd("drawCoastline"); } // Re-mark features (ocean, lakes, islands) function reMarkFeatures() { - TIME && console.time("reMarkFeatures"); - const cells = pack.cells, - features = (pack.features = [0]); - cells.f = new Uint16Array(cells.i.length); // cell feature number - cells.t = new Int8Array(cells.i.length); // cell type: 1 = land along coast; -1 = water along coast; - cells.haven = cells.i.length < 65535 ? new Uint16Array(cells.i.length) : new Uint32Array(cells.i.length); // cell haven (opposite water cell); - cells.harbor = new Uint8Array(cells.i.length); // cell harbor (number of adjacent water cells); + TIME && console.time("reMarkFeatures"); + const cells = pack.cells, + features = (pack.features = [0]); + cells.f = new Uint16Array(cells.i.length); // cell feature number + cells.t = new Int8Array(cells.i.length); // cell type: 1 = land along coast; -1 = water along coast; + cells.haven = cells.i.length < 65535 ? new Uint16Array(cells.i.length) : new Uint32Array(cells.i.length); // cell haven (opposite water cell); + cells.harbor = new Uint8Array(cells.i.length); // cell harbor (number of adjacent water cells); - const defineHaven = i => { - const water = cells.c[i].filter(c => cells.h[c] < 20); - const dist2 = water.map(c => (cells.p[i][0] - cells.p[c][0]) ** 2 + (cells.p[i][1] - cells.p[c][1]) ** 2); - const closest = water[dist2.indexOf(Math.min.apply(Math, dist2))]; + const defineHaven = i => { + const water = cells.c[i].filter(c => cells.h[c] < 20); + const dist2 = water.map(c => (cells.p[i][0] - cells.p[c][0]) ** 2 + (cells.p[i][1] - cells.p[c][1]) ** 2); + const closest = water[dist2.indexOf(Math.min.apply(Math, dist2))]; - cells.haven[i] = closest; - cells.harbor[i] = water.length; - }; + cells.haven[i] = closest; + cells.harbor[i] = water.length; + }; - for (let i = 1, queue = [0]; queue[0] !== -1; i++) { - const start = queue[0]; // first cell - cells.f[start] = i; // assign feature number - const land = cells.h[start] >= 20; - let border = false; // true if feature touches map border - let cellNumber = 1; // to count cells number in a feature + for (let i = 1, queue = [0]; queue[0] !== -1; i++) { + const start = queue[0]; // first cell + cells.f[start] = i; // assign feature number + const land = cells.h[start] >= 20; + let border = false; // true if feature touches map border + let cellNumber = 1; // to count cells number in a feature - while (queue.length) { - const q = queue.pop(); - if (cells.b[q]) border = true; - cells.c[q].forEach(function (e) { - const eLand = cells.h[e] >= 20; - if (land && !eLand) { - cells.t[q] = 1; - cells.t[e] = -1; - if (!cells.haven[q]) defineHaven(q); - } else if (land && eLand) { - if (!cells.t[e] && cells.t[q] === 1) cells.t[e] = 2; - else if (!cells.t[q] && cells.t[e] === 1) cells.t[q] = 2; + while (queue.length) { + const q = queue.pop(); + if (cells.b[q]) border = true; + cells.c[q].forEach(function (e) { + const eLand = cells.h[e] >= 20; + if (land && !eLand) { + cells.t[q] = 1; + cells.t[e] = -1; + if (!cells.haven[q]) defineHaven(q); + } else if (land && eLand) { + if (!cells.t[e] && cells.t[q] === 1) cells.t[e] = 2; + else if (!cells.t[q] && cells.t[e] === 1) cells.t[q] = 2; + } + if (!cells.f[e] && land === eLand) { + queue.push(e); + cells.f[e] = i; + cellNumber++; + } + }); } - if (!cells.f[e] && land === eLand) { - queue.push(e); - cells.f[e] = i; - cellNumber++; - } - }); + + const type = land ? "island" : border ? "ocean" : "lake"; + let group; + if (type === "ocean") group = defineOceanGroup(cellNumber); + else if (type === "island") group = defineIslandGroup(start, cellNumber); + features.push({i, land, border, type, cells: cellNumber, firstCell: start, group}); + queue[0] = cells.f.findIndex(f => !f); // find unmarked cell } - const type = land ? "island" : border ? "ocean" : "lake"; - let group; - if (type === "ocean") group = defineOceanGroup(cellNumber); - else if (type === "island") group = defineIslandGroup(start, cellNumber); - features.push({i, land, border, type, cells: cellNumber, firstCell: start, group}); - queue[0] = cells.f.findIndex(f => !f); // find unmarked cell - } + // markupPackLand + markup(pack.cells, 3, 1, 0); - // markupPackLand - markup(pack.cells, 3, 1, 0); + function defineOceanGroup(number) { + if (number > grid.cells.i.length / 25) return "ocean"; + if (number > grid.cells.i.length / 100) return "sea"; + return "gulf"; + } - function defineOceanGroup(number) { - if (number > grid.cells.i.length / 25) return "ocean"; - if (number > grid.cells.i.length / 100) return "sea"; - return "gulf"; - } + function defineIslandGroup(cell, number) { + if (cell && features[cells.f[cell - 1]].type === "lake") return "lake_island"; + if (number > grid.cells.i.length / 10) return "continent"; + if (number > grid.cells.i.length / 1000) return "island"; + return "isle"; + } - function defineIslandGroup(cell, number) { - if (cell && features[cells.f[cell - 1]].type === "lake") return "lake_island"; - if (number > grid.cells.i.length / 10) return "continent"; - if (number > grid.cells.i.length / 1000) return "island"; - return "isle"; - } - - TIME && console.timeEnd("reMarkFeatures"); + TIME && console.timeEnd("reMarkFeatures"); } // assign biome id for each cell function defineBiomes() { - TIME && console.time("defineBiomes"); - const {cells} = pack; - const {temp, prec} = grid.cells; - cells.biome = new Uint8Array(cells.i.length); // biomes array + TIME && console.time("defineBiomes"); + const {cells} = pack; + const {temp, prec} = grid.cells; + cells.biome = new Uint8Array(cells.i.length); // biomes array - for (const i of cells.i) { - const temperature = temp[cells.g[i]]; - const height = cells.h[i]; - const moisture = height < 20 ? 0 : calculateMoisture(i); - cells.biome[i] = getBiomeId(moisture, temperature, height); - } + for (const i of cells.i) { + const temperature = temp[cells.g[i]]; + const height = cells.h[i]; + const moisture = height < 20 ? 0 : calculateMoisture(i); + cells.biome[i] = getBiomeId(moisture, temperature, height); + } - function calculateMoisture(i) { - let moist = prec[cells.g[i]]; - if (cells.r[i]) moist += Math.max(cells.fl[i] / 20, 2); + function calculateMoisture(i) { + let moist = prec[cells.g[i]]; + if (cells.r[i]) moist += Math.max(cells.fl[i] / 20, 2); - const n = cells.c[i] - .filter(isLand) - .map(c => prec[cells.g[c]]) - .concat([moist]); - return rn(4 + d3.mean(n)); - } + const n = cells.c[i] + .filter(isLand) + .map(c => prec[cells.g[c]]) + .concat([moist]); + return rn(4 + d3.mean(n)); + } - TIME && console.timeEnd("defineBiomes"); + TIME && console.timeEnd("defineBiomes"); } // assign biome id to a cell function getBiomeId(moisture, temperature, height) { - if (height < 20) return 0; // marine biome: all water cells - if (temperature < -5) return 11; // permafrost biome - if (moisture > 40 && temperature > -2 && (height < 25 || (moisture > 24 && height > 24 && height < 60))) return 12; // wetland biome + if (height < 20) return 0; // marine biome: all water cells + if (temperature < -5) return 11; // permafrost biome + if (moisture > 40 && temperature > -2 && (height < 25 || (moisture > 24 && height > 24 && height < 60))) return 12; // wetland biome - const moistureBand = Math.min((moisture / 5) | 0, 4); // [0-4] - const temperatureBand = Math.min(Math.max(20 - temperature, 0), 25); // [0-25] - return biomesData.biomesMartix[moistureBand][temperatureBand]; + const moistureBand = Math.min((moisture / 5) | 0, 4); // [0-4] + const temperatureBand = Math.min(Math.max(20 - temperature, 0), 25); // [0-25] + return biomesData.biomesMartix[moistureBand][temperatureBand]; } // assess cells suitability to calculate population and rand cells for culture center and burgs placement function rankCells() { - TIME && console.time("rankCells"); - const {cells, features} = pack; - cells.s = new Int16Array(cells.i.length); // cell suitability array - cells.pop = new Float32Array(cells.i.length); // cell population array + TIME && console.time("rankCells"); + const {cells, features} = pack; + cells.s = new Int16Array(cells.i.length); // cell suitability array + cells.pop = new Float32Array(cells.i.length); // cell population array - const flMean = d3.median(cells.fl.filter(f => f)) || 0, - flMax = d3.max(cells.fl) + d3.max(cells.conf); // to normalize flux - const areaMean = d3.mean(cells.area); // to adjust population by cell area + const flMean = d3.median(cells.fl.filter(f => f)) || 0, + flMax = d3.max(cells.fl) + d3.max(cells.conf); // to normalize flux + const areaMean = d3.mean(cells.area); // to adjust population by cell area - for (const i of cells.i) { - if (cells.h[i] < 20) continue; // no population in water - let s = +biomesData.habitability[cells.biome[i]]; // base suitability derived from biome habitability - if (!s) continue; // uninhabitable biomes has 0 suitability - if (flMean) s += normalize(cells.fl[i] + cells.conf[i], flMean, flMax) * 250; // big rivers and confluences are valued - s -= (cells.h[i] - 50) / 5; // low elevation is valued, high is not; + for (const i of cells.i) { + if (cells.h[i] < 20) continue; // no population in water + let s = +biomesData.habitability[cells.biome[i]]; // base suitability derived from biome habitability + if (!s) continue; // uninhabitable biomes has 0 suitability + if (flMean) s += normalize(cells.fl[i] + cells.conf[i], flMean, flMax) * 500; // big rivers and confluences are valued + s -= (cells.h[i] - 50) / 5; // low elevation is valued, high is not; - if (cells.t[i] === 1) { - if (cells.r[i]) s += 15; // estuary is valued - const feature = features[cells.f[cells.haven[i]]]; - if (feature.type === "lake") { - if (feature.group === "freshwater") s += 30; - else if (feature.group == "salt") s += 10; - else if (feature.group == "frozen") s += 1; - else if (feature.group == "dry") s -= 5; - else if (feature.group == "sinkhole") s -= 5; - else if (feature.group == "lava") s -= 30; - } else { - s += 5; // ocean coast is valued - if (cells.harbor[i] === 1) s += 20; // safe sea harbor is valued - } + if (cells.t[i] === 1) { // What is t? + if (cells.r[i]) s += 5; // estuary is valued + const feature = features[cells.f[cells.haven[i]]]; + if (feature.type === "lake") { + if (feature.group === "freshwater") s += 400; + else if (feature.group == "salt") s -= 5; + else if (feature.group == "frozen") s += 1; + else if (feature.group == "dry") s -= 2; + else if (feature.group == "sinkhole") s += 3; + else if (feature.group == "lava") s += 30; + } else { + s -= 100; // ocean coast is valued + if (cells.harbor[i] === 1) s -= 10; // safe sea harbor is valued + } + } + + cells.s[i] = s / 50; // general population rate + // cell rural population is suitability adjusted by cell area + cells.pop[i] = cells.s[i] > 0 ? (cells.s[i] * cells.area[i]) / areaMean : 0; } - cells.s[i] = s / 5; // general population rate - // cell rural population is suitability adjusted by cell area - cells.pop[i] = cells.s[i] > 0 ? (cells.s[i] * cells.area[i]) / areaMean : 0; - } - - TIME && console.timeEnd("rankCells"); + TIME && console.timeEnd("rankCells"); } // regenerate some zones function addZones(number = 1) { - TIME && console.time("addZones"); - const data = [], - cells = pack.cells, - states = pack.states, - burgs = pack.burgs; - const used = new Uint8Array(cells.i.length); // to store used cells + TIME && console.time("addZones"); + const data = [], + cells = pack.cells, + states = pack.states, + burgs = pack.burgs; + const used = new Uint8Array(cells.i.length); // to store used cells - for (let i = 0; i < rn(Math.random() * 1.8 * number); i++) addInvasion(); // invasion of enemy lands - for (let i = 0; i < rn(Math.random() * 1.6 * number); i++) addRebels(); // rebels along a state border - for (let i = 0; i < rn(Math.random() * 1.6 * number); i++) addProselytism(); // proselitism of organized religion - for (let i = 0; i < rn(Math.random() * 1.6 * number); i++) addCrusade(); // crusade on heresy lands - for (let i = 0; i < rn(Math.random() * 1.8 * number); i++) addDisease(); // disease starting in a random city - for (let i = 0; i < rn(Math.random() * 1.4 * number); i++) addDisaster(); // disaster starting in a random city - for (let i = 0; i < rn(Math.random() * 1.4 * number); i++) addEruption(); // volcanic eruption aroung volcano - for (let i = 0; i < rn(Math.random() * 1.0 * number); i++) addAvalanche(); // avalanche impacting highland road - for (let i = 0; i < rn(Math.random() * 1.4 * number); i++) addFault(); // fault line in elevated areas - for (let i = 0; i < rn(Math.random() * 1.4 * number); i++) addFlood(); // flood on river banks - for (let i = 0; i < rn(Math.random() * 1.2 * number); i++) addTsunami(); // tsunami starting near coast + for (let i = 0; i < rn(Math.random() * 1.8 * number); i++) addInvasion(); // invasion of enemy lands + for (let i = 0; i < rn(Math.random() * 1.6 * number); i++) addRebels(); // rebels along a state border + for (let i = 0; i < rn(Math.random() * 1.6 * number); i++) addProselytism(); // proselitism of organized religion + for (let i = 0; i < rn(Math.random() * 1.6 * number); i++) addCrusade(); // crusade on heresy lands + for (let i = 0; i < rn(Math.random() * 1.8 * number); i++) addDisease(); // disease starting in a random city + for (let i = 0; i < rn(Math.random() * 1.4 * number); i++) addDisaster(); // disaster starting in a random city + for (let i = 0; i < rn(Math.random() * 1.4 * number); i++) addEruption(); // volcanic eruption aroung volcano + for (let i = 0; i < rn(Math.random() * 1.0 * number); i++) addAvalanche(); // avalanche impacting highland road + for (let i = 0; i < rn(Math.random() * 1.4 * number); i++) addFault(); // fault line in elevated areas + for (let i = 0; i < rn(Math.random() * 1.4 * number); i++) addFlood(); // flood on river banks + for (let i = 0; i < rn(Math.random() * 1.2 * number); i++) addTsunami(); // tsunami starting near coast - function addInvasion() { - const atWar = states.filter(s => s.diplomacy && s.diplomacy.some(d => d === "Enemy")); - if (!atWar.length) return; + function addInvasion() { + const atWar = states.filter(s => s.diplomacy && s.diplomacy.some(d => d === "Enemy")); + if (!atWar.length) return; - const invader = ra(atWar); - const target = invader.diplomacy.findIndex(d => d === "Enemy"); + const invader = ra(atWar); + const target = invader.diplomacy.findIndex(d => d === "Enemy"); - const cell = ra(cells.i.filter(i => cells.state[i] === target && cells.c[i].some(c => cells.state[c] === invader.i))); - if (!cell) return; + const cell = ra(cells.i.filter(i => cells.state[i] === target && cells.c[i].some(c => cells.state[c] === invader.i))); + if (!cell) return; - const cellsArray = [], - queue = [cell], - power = rand(5, 30); + const cellsArray = [], + queue = [cell], + power = rand(5, 30); - while (queue.length) { - const q = P(0.4) ? queue.shift() : queue.pop(); - cellsArray.push(q); - if (cellsArray.length > power) break; + while (queue.length) { + const q = P(0.4) ? queue.shift() : queue.pop(); + cellsArray.push(q); + if (cellsArray.length > power) break; - cells.c[q].forEach(e => { - if (used[e]) return; - if (cells.state[e] !== target) return; - used[e] = 1; - queue.push(e); - }); - } - - const invasion = rw({ - Invasion: 4, - Occupation: 3, - Raid: 2, - Conquest: 2, - Subjugation: 1, - Foray: 1, - Skirmishes: 1, - Incursion: 2, - Pillaging: 1, - Intervention: 1 - }); - const name = getAdjective(invader.name) + " " + invasion; - data.push({name, type: "Invasion", cells: cellsArray, fill: "url(#hatch1)"}); - } - - function addRebels() { - const state = ra(states.filter(s => s.i && s.neighbors.some(n => n))); - if (!state) return; - - const neib = ra(state.neighbors.filter(n => n)); - const cell = cells.i.find(i => cells.state[i] === state.i && cells.c[i].some(c => cells.state[c] === neib)); - const cellsArray = [], - queue = [cell], - power = rand(10, 30); - - while (queue.length) { - const q = queue.shift(); - cellsArray.push(q); - if (cellsArray.length > power) break; - - cells.c[q].forEach(e => { - if (used[e]) return; - if (cells.state[e] !== state.i) return; - used[e] = 1; - if (e % 4 !== 0 && !cells.c[e].some(c => cells.state[c] === neib)) return; - queue.push(e); - }); - } - - const rebels = rw({Rebels: 5, Insurgents: 2, Mutineers: 1, Rioters: 1, Separatists: 1, Secessionists: 1, Insurrection: 2, Rebellion: 1, Conspiracy: 2}); - const name = getAdjective(states[neib].name) + " " + rebels; - data.push({name, type: "Rebels", cells: cellsArray, fill: "url(#hatch3)"}); - } - - function addProselytism() { - const organized = ra(pack.religions.filter(r => r.type === "Organized")); - if (!organized) return; - - const cell = ra(cells.i.filter(i => cells.religion[i] && cells.religion[i] !== organized.i && cells.c[i].some(c => cells.religion[c] === organized.i))); - if (!cell) return; - const target = cells.religion[cell]; - const cellsArray = [], - queue = [cell], - power = rand(10, 30); - - while (queue.length) { - const q = queue.shift(); - cellsArray.push(q); - if (cellsArray.length > power) break; - - cells.c[q].forEach(e => { - if (used[e]) return; - if (cells.religion[e] !== target) return; - if (cells.h[e] < 20) return; - used[e] = 1; - //if (e%2 !== 0 && !cells.c[e].some(c => cells.state[c] === neib)) return; - queue.push(e); - }); - } - - const name = getAdjective(organized.name.split(" ")[0]) + " Proselytism"; - data.push({name, type: "Proselytism", cells: cellsArray, fill: "url(#hatch6)"}); - } - - function addCrusade() { - const heresy = ra(pack.religions.filter(r => r.type === "Heresy")); - if (!heresy) return; - - const cellsArray = cells.i.filter(i => !used[i] && cells.religion[i] === heresy.i); - if (!cellsArray.length) return; - cellsArray.forEach(i => (used[i] = 1)); - - const name = getAdjective(heresy.name.split(" ")[0]) + " Crusade"; - data.push({name, type: "Crusade", cells: cellsArray, fill: "url(#hatch6)"}); - } - - function addDisease() { - const burg = ra(burgs.filter(b => !used[b.cell] && b.i && !b.removed)); // random burg - if (!burg) return; - - const cellsArray = [], - cost = [], - power = rand(20, 37); - const queue = new PriorityQueue({comparator: (a, b) => a.p - b.p}); - queue.queue({e: burg.cell, p: 0}); - - while (queue.length) { - const next = queue.dequeue(); - if (cells.burg[next.e] || cells.pop[next.e]) cellsArray.push(next.e); - used[next.e] = 1; - - cells.c[next.e].forEach(function (e) { - const r = cells.road[next.e]; - const c = r ? Math.max(10 - r, 1) : 100; - const p = next.p + c; - if (p > power) return; - - if (!cost[e] || p < cost[e]) { - cost[e] = p; - queue.queue({e, p}); + cells.c[q].forEach(e => { + if (used[e]) return; + if (cells.state[e] !== target) return; + used[e] = 1; + queue.push(e); + }); } - }); + + const invasion = rw({ + Invasion: 4, + Occupation: 3, + Raid: 2, + Conquest: 2, + Subjugation: 1, + Foray: 1, + Skirmishes: 1, + Incursion: 2, + Pillaging: 1, + Intervention: 1 + }); + const name = getAdjective(invader.name) + " " + invasion; + data.push({name, type: "Invasion", cells: cellsArray, fill: "url(#hatch1)"}); } - const adjective = () => ra(["Great", "Silent", "Severe", "Blind", "Unknown", "Loud", "Deadly", "Burning", "Bloody", "Brutal", "Fatal"]); - const animal = () => ra(["Ape", "Bear", "Boar", "Cat", "Cow", "Dog", "Pig", "Fox", "Bird", "Horse", "Rat", "Raven", "Sheep", "Spider", "Wolf"]); - const color = () => ra(["Golden", "White", "Black", "Red", "Pink", "Purple", "Blue", "Green", "Yellow", "Amber", "Orange", "Brown", "Grey"]); + function addRebels() { + const state = ra(states.filter(s => s.i && s.neighbors.some(n => n))); + if (!state) return; - const type = rw({Fever: 5, Pestilence: 2, Flu: 2, Pox: 2, Smallpox: 2, Plague: 4, Cholera: 2, Dropsy: 1, Leprosy: 2}); - const name = rw({[color()]: 4, [animal()]: 2, [adjective()]: 1}) + " " + type; - data.push({name, type: "Disease", cells: cellsArray, fill: "url(#hatch12)"}); - } + const neib = ra(state.neighbors.filter(n => n)); + const cell = cells.i.find(i => cells.state[i] === state.i && cells.c[i].some(c => cells.state[c] === neib)); + const cellsArray = [], + queue = [cell], + power = rand(10, 30); - function addDisaster() { - const burg = ra(burgs.filter(b => !used[b.cell] && b.i && !b.removed)); // random burg - if (!burg) return; + while (queue.length) { + const q = queue.shift(); + cellsArray.push(q); + if (cellsArray.length > power) break; - const cellsArray = [], - cost = [], - power = rand(5, 25); - const queue = new PriorityQueue({comparator: (a, b) => a.p - b.p}); - queue.queue({e: burg.cell, p: 0}); - - while (queue.length) { - const next = queue.dequeue(); - if (cells.burg[next.e] || cells.pop[next.e]) cellsArray.push(next.e); - used[next.e] = 1; - - cells.c[next.e].forEach(function (e) { - const c = rand(1, 10); - const p = next.p + c; - if (p > power) return; - - if (!cost[e] || p < cost[e]) { - cost[e] = p; - queue.queue({e, p}); + cells.c[q].forEach(e => { + if (used[e]) return; + if (cells.state[e] !== state.i) return; + used[e] = 1; + if (e % 4 !== 0 && !cells.c[e].some(c => cells.state[c] === neib)) return; + queue.push(e); + }); } - }); + + const rebels = rw({ + Rebels: 5, + Insurgents: 2, + Mutineers: 1, + Rioters: 1, + Separatists: 1, + Secessionists: 1, + Insurrection: 2, + Rebellion: 1, + Conspiracy: 2 + }); + const name = getAdjective(states[neib].name) + " " + rebels; + data.push({name, type: "Rebels", cells: cellsArray, fill: "url(#hatch3)"}); } - const type = rw({Famine: 5, Dearth: 1, Drought: 3, Earthquake: 3, Tornadoes: 1, Wildfires: 1}); - const name = getAdjective(burg.name) + " " + type; - data.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch5)"}); - } + function addProselytism() { + const organized = ra(pack.religions.filter(r => r.type === "Organized")); + if (!organized) return; - function addEruption() { - const volcano = document.getElementById("markers").querySelector("use[data-id='#marker_volcano']"); - if (!volcano) return; + const cell = ra(cells.i.filter(i => cells.religion[i] && cells.religion[i] !== organized.i && cells.c[i].some(c => cells.religion[c] === organized.i))); + if (!cell) return; + const target = cells.religion[cell]; + const cellsArray = [], + queue = [cell], + power = rand(10, 30); - const x = +volcano.dataset.x, - y = +volcano.dataset.y, - cell = findCell(x, y); - const id = volcano.id; - const note = notes.filter(n => n.id === id); + while (queue.length) { + const q = queue.shift(); + cellsArray.push(q); + if (cellsArray.length > power) break; - if (note[0]) note[0].legend = note[0].legend.replace("Active volcano", "Erupting volcano"); - const name = note[0] ? note[0].name.replace(" Volcano", "") + " Eruption" : "Volcano Eruption"; + cells.c[q].forEach(e => { + if (used[e]) return; + if (cells.religion[e] !== target) return; + if (cells.h[e] < 20) return; + used[e] = 1; + //if (e%2 !== 0 && !cells.c[e].some(c => cells.state[c] === neib)) return; + queue.push(e); + }); + } - const cellsArray = [], - queue = [cell], - power = rand(10, 30); - - while (queue.length) { - const q = P(0.5) ? queue.shift() : queue.pop(); - cellsArray.push(q); - if (cellsArray.length > power) break; - cells.c[q].forEach(e => { - if (used[e] || cells.h[e] < 20) return; - used[e] = 1; - queue.push(e); - }); + const name = getAdjective(organized.name.split(" ")[0]) + " Proselytism"; + data.push({name, type: "Proselytism", cells: cellsArray, fill: "url(#hatch6)"}); } - data.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch7)"}); - } + function addCrusade() { + const heresy = ra(pack.religions.filter(r => r.type === "Heresy")); + if (!heresy) return; - function addAvalanche() { - const roads = cells.i.filter(i => !used[i] && cells.road[i] && cells.h[i] >= 70); - if (!roads.length) return; + const cellsArray = cells.i.filter(i => !used[i] && cells.religion[i] === heresy.i); + if (!cellsArray.length) return; + cellsArray.forEach(i => (used[i] = 1)); - const cell = +ra(roads); - const cellsArray = [], - queue = [cell], - power = rand(3, 15); - - while (queue.length) { - const q = P(0.3) ? queue.shift() : queue.pop(); - cellsArray.push(q); - if (cellsArray.length > power) break; - cells.c[q].forEach(e => { - if (used[e] || cells.h[e] < 65) return; - used[e] = 1; - queue.push(e); - }); + const name = getAdjective(heresy.name.split(" ")[0]) + " Crusade"; + data.push({name, type: "Crusade", cells: cellsArray, fill: "url(#hatch6)"}); } - const proper = getAdjective(Names.getCultureShort(cells.culture[cell])); - const name = proper + " Avalanche"; - data.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch5)"}); - } + function addDisease() { + const burg = ra(burgs.filter(b => !used[b.cell] && b.i && !b.removed)); // random burg + if (!burg) return; - function addFault() { - const elevated = cells.i.filter(i => !used[i] && cells.h[i] > 50 && cells.h[i] < 70); - if (!elevated.length) return; + const cellsArray = [], + cost = [], + power = rand(20, 37); + const queue = new PriorityQueue({comparator: (a, b) => a.p - b.p}); + queue.queue({e: burg.cell, p: 0}); - const cell = ra(elevated); - const cellsArray = [], - queue = [cell], - power = rand(3, 15); + while (queue.length) { + const next = queue.dequeue(); + if (cells.burg[next.e] || cells.pop[next.e]) cellsArray.push(next.e); + used[next.e] = 1; - while (queue.length) { - const q = queue.pop(); - if (cells.h[q] >= 20) cellsArray.push(q); - if (cellsArray.length > power) break; - cells.c[q].forEach(e => { - if (used[e] || cells.r[e]) return; - used[e] = 1; - queue.push(e); - }); + cells.c[next.e].forEach(function (e) { + const r = cells.road[next.e]; + const c = r ? Math.max(10 - r, 1) : 100; + const p = next.p + c; + if (p > power) return; + + if (!cost[e] || p < cost[e]) { + cost[e] = p; + queue.queue({e, p}); + } + }); + } + + const adjective = () => ra(["Great", "Silent", "Severe", "Blind", "Unknown", "Loud", "Deadly", "Burning", "Bloody", "Brutal", "Fatal"]); + const animal = () => ra(["Ape", "Bear", "Boar", "Cat", "Cow", "Dog", "Pig", "Fox", "Bird", "Horse", "Rat", "Raven", "Sheep", "Spider", "Wolf"]); + const color = () => ra(["Golden", "White", "Black", "Red", "Pink", "Purple", "Blue", "Green", "Yellow", "Amber", "Orange", "Brown", "Grey"]); + + const type = rw({ + Fever: 5, + Pestilence: 2, + Flu: 2, + Pox: 2, + Smallpox: 2, + Plague: 4, + Cholera: 2, + Dropsy: 1, + Leprosy: 2 + }); + const name = rw({[color()]: 4, [animal()]: 2, [adjective()]: 1}) + " " + type; + data.push({name, type: "Disease", cells: cellsArray, fill: "url(#hatch12)"}); } - const proper = getAdjective(Names.getCultureShort(cells.culture[cell])); - const name = proper + " Fault"; - data.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch2)"}); - } + function addDisaster() { + const burg = ra(burgs.filter(b => !used[b.cell] && b.i && !b.removed)); // random burg + if (!burg) return; - function addFlood() { - const fl = cells.fl.filter(fl => fl), - meanFlux = d3.mean(fl), - maxFlux = d3.max(fl), - flux = (maxFlux - meanFlux) / 2 + meanFlux; - const rivers = cells.i.filter(i => !used[i] && cells.h[i] < 50 && cells.r[i] && cells.fl[i] > flux && cells.burg[i]); - if (!rivers.length) return; + const cellsArray = [], + cost = [], + power = rand(5, 25); + const queue = new PriorityQueue({comparator: (a, b) => a.p - b.p}); + queue.queue({e: burg.cell, p: 0}); - const cell = +ra(rivers), - river = cells.r[cell]; - const cellsArray = [], - queue = [cell], - power = rand(5, 30); + while (queue.length) { + const next = queue.dequeue(); + if (cells.burg[next.e] || cells.pop[next.e]) cellsArray.push(next.e); + used[next.e] = 1; - while (queue.length) { - const q = queue.pop(); - cellsArray.push(q); - if (cellsArray.length > power) break; + cells.c[next.e].forEach(function (e) { + const c = rand(1, 10); + const p = next.p + c; + if (p > power) return; - cells.c[q].forEach(e => { - if (used[e] || cells.h[e] < 20 || cells.r[e] !== river || cells.h[e] > 50 || cells.fl[e] < meanFlux) return; - used[e] = 1; - queue.push(e); - }); + if (!cost[e] || p < cost[e]) { + cost[e] = p; + queue.queue({e, p}); + } + }); + } + + const type = rw({Famine: 5, Dearth: 1, Drought: 3, Earthquake: 3, Tornadoes: 1, Wildfires: 1}); + const name = getAdjective(burg.name) + " " + type; + data.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch5)"}); } - const name = getAdjective(burgs[cells.burg[cell]].name) + " Flood"; - data.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch13)"}); - } + function addEruption() { + const volcano = document.getElementById("markers").querySelector("use[data-id='#marker_volcano']"); + if (!volcano) return; - function addTsunami() { - const coastal = cells.i.filter(i => !used[i] && cells.t[i] === -1 && pack.features[cells.f[i]].type !== "lake"); - if (!coastal.length) return; + const x = +volcano.dataset.x, + y = +volcano.dataset.y, + cell = findCell(x, y); + const id = volcano.id; + const note = notes.filter(n => n.id === id); - const cell = +ra(coastal); - const cellsArray = [], - queue = [cell], - power = rand(10, 30); + if (note[0]) note[0].legend = note[0].legend.replace("Active volcano", "Erupting volcano"); + const name = note[0] ? note[0].name.replace(" Volcano", "") + " Eruption" : "Volcano Eruption"; - while (queue.length) { - const q = queue.shift(); - if (cells.t[q] === 1) cellsArray.push(q); - if (cellsArray.length > power) break; + const cellsArray = [], + queue = [cell], + power = rand(10, 30); - cells.c[q].forEach(e => { - if (used[e]) return; - if (cells.t[e] > 2) return; - if (pack.features[cells.f[e]].type === "lake") return; - used[e] = 1; - queue.push(e); - }); + while (queue.length) { + const q = P(0.5) ? queue.shift() : queue.pop(); + cellsArray.push(q); + if (cellsArray.length > power) break; + cells.c[q].forEach(e => { + if (used[e] || cells.h[e] < 20) return; + used[e] = 1; + queue.push(e); + }); + } + + data.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch7)"}); } - const proper = getAdjective(Names.getCultureShort(cells.culture[cell])); - const name = proper + " Tsunami"; - data.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch13)"}); - } + function addAvalanche() { + const roads = cells.i.filter(i => !used[i] && cells.road[i] && cells.h[i] >= 70); + if (!roads.length) return; - void (function drawZones() { - zones - .selectAll("g") - .data(data) - .enter() - .append("g") - .attr("id", (d, i) => "zone" + i) - .attr("data-description", d => d.name) - .attr("data-type", d => d.type) - .attr("data-cells", d => d.cells.join(",")) - .attr("fill", d => d.fill) - .selectAll("polygon") - .data(d => d.cells) - .enter() - .append("polygon") - .attr("points", d => getPackPolygon(d)) - .attr("id", function (d) { - return this.parentNode.id + "_" + d; - }); - })(); + const cell = +ra(roads); + const cellsArray = [], + queue = [cell], + power = rand(3, 15); - TIME && console.timeEnd("addZones"); + while (queue.length) { + const q = P(0.3) ? queue.shift() : queue.pop(); + cellsArray.push(q); + if (cellsArray.length > power) break; + cells.c[q].forEach(e => { + if (used[e] || cells.h[e] < 65) return; + used[e] = 1; + queue.push(e); + }); + } + + const proper = getAdjective(Names.getCultureShort(cells.culture[cell])); + const name = proper + " Avalanche"; + data.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch5)"}); + } + + function addFault() { + const elevated = cells.i.filter(i => !used[i] && cells.h[i] > 50 && cells.h[i] < 70); + if (!elevated.length) return; + + const cell = ra(elevated); + const cellsArray = [], + queue = [cell], + power = rand(3, 15); + + while (queue.length) { + const q = queue.pop(); + if (cells.h[q] >= 20) cellsArray.push(q); + if (cellsArray.length > power) break; + cells.c[q].forEach(e => { + if (used[e] || cells.r[e]) return; + used[e] = 1; + queue.push(e); + }); + } + + const proper = getAdjective(Names.getCultureShort(cells.culture[cell])); + const name = proper + " Fault"; + data.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch2)"}); + } + + function addFlood() { + const fl = cells.fl.filter(fl => fl), + meanFlux = d3.mean(fl), + maxFlux = d3.max(fl), + flux = (maxFlux - meanFlux) / 2 + meanFlux; + const rivers = cells.i.filter(i => !used[i] && cells.h[i] < 50 && cells.r[i] && cells.fl[i] > flux && cells.burg[i]); + if (!rivers.length) return; + + const cell = +ra(rivers), + river = cells.r[cell]; + const cellsArray = [], + queue = [cell], + power = rand(5, 30); + + while (queue.length) { + const q = queue.pop(); + cellsArray.push(q); + if (cellsArray.length > power) break; + + cells.c[q].forEach(e => { + if (used[e] || cells.h[e] < 20 || cells.r[e] !== river || cells.h[e] > 50 || cells.fl[e] < meanFlux) return; + used[e] = 1; + queue.push(e); + }); + } + + const name = getAdjective(burgs[cells.burg[cell]].name) + " Flood"; + data.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch13)"}); + } + + function addTsunami() { + const coastal = cells.i.filter(i => !used[i] && cells.t[i] === -1 && pack.features[cells.f[i]].type !== "lake"); + if (!coastal.length) return; + + const cell = +ra(coastal); + const cellsArray = [], + queue = [cell], + power = rand(10, 30); + + while (queue.length) { + const q = queue.shift(); + if (cells.t[q] === 1) cellsArray.push(q); + if (cellsArray.length > power) break; + + cells.c[q].forEach(e => { + if (used[e]) return; + if (cells.t[e] > 2) return; + if (pack.features[cells.f[e]].type === "lake") return; + used[e] = 1; + queue.push(e); + }); + } + + const proper = getAdjective(Names.getCultureShort(cells.culture[cell])); + const name = proper + " Tsunami"; + data.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch13)"}); + } + + void (function drawZones() { + zones + .selectAll("g") + .data(data) + .enter() + .append("g") + .attr("id", (d, i) => "zone" + i) + .attr("data-description", d => d.name) + .attr("data-type", d => d.type) + .attr("data-cells", d => d.cells.join(",")) + .attr("fill", d => d.fill) + .selectAll("polygon") + .data(d => d.cells) + .enter() + .append("polygon") + .attr("points", d => getPackPolygon(d)) + .attr("id", function (d) { + return this.parentNode.id + "_" + d; + }); + })(); + + TIME && console.timeEnd("addZones"); } // show map stats on generation complete function showStatistics() { - const template = templateInput.options[templateInput.selectedIndex].text; - const templateRandom = locked("template") ? "" : "(random)"; - const stats = ` Seed: ${seed} + const template = templateInput.options[templateInput.selectedIndex].text; + const templateRandom = locked("template") ? "" : "(random)"; + const stats = ` Seed: ${seed} Canvas size: ${graphWidth}x${graphHeight} Template: ${template} ${templateRandom} Points: ${grid.points.length} @@ -1858,32 +1880,32 @@ function showStatistics() { Culture set: ${culturesSet.selectedOptions[0].innerText} Cultures: ${pack.cultures.length - 1}`; - mapId = Date.now(); // unique map id is it's creation date number - mapHistory.push({seed, width: graphWidth, height: graphHeight, template, created: mapId}); - INFO && console.log(stats); + mapId = Date.now(); // unique map id is it's creation date number + mapHistory.push({seed, width: graphWidth, height: graphHeight, template, created: mapId}); + INFO && console.log(stats); } const regenerateMap = debounce(function () { - WARN && console.warn("Generate new random map"); - closeDialogs("#worldConfigurator, #options3d"); - customization = 0; - undraw(); - resetZoom(1000); - generate(); - restoreLayers(); - if (ThreeD.options.isOn) ThreeD.redraw(); - if ($("#worldConfigurator").is(":visible")) editWorld(); + WARN && console.warn("Generate new random map"); + closeDialogs("#worldConfigurator, #options3d"); + customization = 0; + undraw(); + resetZoom(1000); + generate(); + restoreLayers(); + if (ThreeD.options.isOn) ThreeD.redraw(); + if ($("#worldConfigurator").is(":visible")) editWorld(); }, 1000); // clear the map function undraw() { - viewbox.selectAll("path, circle, polygon, line, text, use, #zones > g, #armies > g, #ruler > g").remove(); - document - .getElementById("deftemp") - .querySelectorAll("path, clipPath, svg") - .forEach(el => el.remove()); - document.getElementById("coas").innerHTML = ""; // remove auto-generated emblems - notes = []; - rulers = new Rulers(); - unfog(); + viewbox.selectAll("path, circle, polygon, line, text, use, #zones > g, #armies > g, #ruler > g").remove(); + document + .getElementById("deftemp") + .querySelectorAll("path, clipPath, svg") + .forEach(el => el.remove()); + document.getElementById("coas").innerHTML = ""; // remove auto-generated emblems + notes = []; + rulers = new Rulers(); + unfog(); } diff --git a/map.sh b/map.sh new file mode 100644 index 00000000..f0f61bdc --- /dev/null +++ b/map.sh @@ -0,0 +1,2 @@ +python -m http.server 8000 + diff --git a/modules/burgs-and-states.js b/modules/burgs-and-states.js index 09d70f2d..e33266d4 100644 --- a/modules/burgs-and-states.js +++ b/modules/burgs-and-states.js @@ -118,7 +118,7 @@ window.BurgsAndStates = (function () { let burgsAdded = 0; const burgsTree = burgs[0]; - let spacing = (graphWidth + graphHeight) / 150 / (burgsNumber ** 0.7 / 66); // min distance between towns + let spacing = (graphWidth + graphHeight) / 15 / (burgsNumber ** 0.7 / 24); // min distance between towns while (burgsAdded < burgsNumber && spacing > 1) { for (let i = 0; burgsAdded < burgsNumber && i < sorted.length; i++) { @@ -156,53 +156,53 @@ window.BurgsAndStates = (function () { features = pack.features, temp = grid.cells.temp; - for (const b of pack.burgs) { - if (!b.i || b.lock) continue; - const i = b.cell; + for (const burgs of pack.burgs) { + if (!burgs.i || burgs.lock) continue; + const i = burgs.cell; - // asign port status to some coastline burgs with temp > 0 °C + // assign port status to some coastline burgs with temp > 0 °C const haven = cells.haven[i]; if (haven && temp[cells.g[i]] > 0) { const f = cells.f[haven]; // water body id // port is a capital with any harbor OR town with good harbor - const port = features[f].cells > 1 && ((b.capital && cells.harbor[i]) || cells.harbor[i] === 1); - b.port = port ? f : 0; // port is defined by water body id it lays on - } else b.port = 0; + const port = features[f].cells > 1 && ((burgs.capital && cells.harbor[i]) || cells.harbor[i] === 1); + burgs.port = port ? f : 0; // port is defined by water body id it lays on + } else burgs.port = 0; // define burg population (keep urbanization at about 10% rate) - b.population = rn(Math.max((cells.s[i] + cells.road[i] / 2) / 8 + b.i / 1000 + (i % 100) / 1000, 0.1), 3); - if (b.capital) b.population = rn(b.population * 1.3, 3); // increase capital population + burgs.population = rn(Math.max((cells.s[i] + cells.road[i] / 2) / 8 + burgs.i / 1000 + (i % 100) / 1000, 0.1), 3); + if (burgs.capital) burgs.population = rn(burgs.population * 1.3, 3); // increase capital population - if (b.port) { - b.population = b.population * 1.3; // increase port population + if (burgs.port) { + burgs.population = burgs.population * 1.3; // increase port population const [x, y] = getMiddlePoint(i, haven); - b.x = x; - b.y = y; + burgs.x = x; + burgs.y = y; } // add random factor - b.population = rn(b.population * gauss(2, 3, 0.6, 20, 3), 3); + burgs.population = rn(burgs.population * gauss(2, 3, 0.6, 20, 3), 3); // shift burgs on rivers semi-randomly and just a bit - if (!b.port && cells.r[i]) { + if (!burgs.port && cells.r[i]) { const shift = Math.min(cells.fl[i] / 150, 1); - if (i % 2) b.x = rn(b.x + shift, 2); - else b.x = rn(b.x - shift, 2); - if (cells.r[i] % 2) b.y = rn(b.y + shift, 2); - else b.y = rn(b.y - shift, 2); + if (i % 2) burgs.x = rn(burgs.x + shift, 2); + else burgs.x = rn(burgs.x - shift, 2); + if (cells.r[i] % 2) burgs.y = rn(burgs.y + shift, 2); + else burgs.y = rn(burgs.y - shift, 2); } // define emblem - const state = pack.states[b.state]; + const state = pack.states[burgs.state]; const stateCOA = state.coa; let kinship = 0.25; - if (b.capital) kinship += 0.1; - else if (b.port) kinship -= 0.1; - if (b.culture !== state.culture) kinship -= 0.25; - b.type = getType(i, b.port); - const type = b.capital && P(0.2) ? "Capital" : b.type === "Generic" ? "City" : b.type; - b.coa = COA.generate(stateCOA, kinship, null, type); - b.coa.shield = COA.getShield(b.culture, b.state); + if (burgs.capital) kinship += 0.1; + else if (burgs.port) kinship -= 0.1; + if (burgs.culture !== state.culture) kinship -= 0.25; + burgs.type = getType(i, burgs.port); + const type = burgs.capital && P(0.2) ? "Capital" : burgs.type === "Generic" ? "City" : burgs.type; + burgs.coa = COA.generate(stateCOA, kinship, null, type); + burgs.coa.shield = COA.getShield(burgs.culture, burgs.state); } // de-assign port status if it's the only one on feature diff --git a/modules/cultures-generator.js b/modules/cultures-generator.js index b4733260..a52f28df 100644 --- a/modules/cultures-generator.js +++ b/modules/cultures-generator.js @@ -71,7 +71,7 @@ window.Cultures = (function () { function placeCenter(v) { let c, - spacing = (graphWidth + graphHeight) / 2 / count; + spacing = (graphWidth + graphHeight) / 20 / count; const sorted = [...populated].sort((a, b) => v(b) - v(a)), max = Math.floor(sorted.length / 2); do { @@ -125,13 +125,13 @@ window.Cultures = (function () { } function defineCultureExpansionism(type) { - let base = 1; // Generic - if (type === "Lake") base = 0.8; - else if (type === "Naval") base = 1.5; - else if (type === "River") base = 0.9; - else if (type === "Nomadic") base = 1.5; - else if (type === "Hunting") base = 0.7; - else if (type === "Highland") base = 1.2; + let base = 0.1; // Generic + if (type === "Lake") base = 0.2; + else if (type === "Naval") base = 0.5; + else if (type === "River") base = 0.3; + else if (type === "Nomadic") base = 0.8; + else if (type === "Hunting") base = 0.6; + else if (type === "Highland") base = 0.3; return rn(((Math.random() * powerInput.value) / 2 + 1) * base, 1); } @@ -173,52 +173,87 @@ window.Cultures = (function () { const cells = pack.cells, s = cells.s, sMax = d3.max(s), - t = cells.t, - h = cells.h, + temperature = cells.t, // Temperature + height = cells.h, // Height temp = grid.cells.temp; - const n = cell => Math.ceil((s[cell] / sMax) * 3); // normalized cell score - const td = (cell, goal) => { + const normalizedCellScore = cell => Math.ceil((s[cell] / sMax) * 3); // normalized cell score + const tempDiff = (cell, goal) => { const d = Math.abs(temp[cells.g[cell]] - goal); return d ? d + 1 : 1; }; // temperature difference fee - const bd = (cell, biomes, fee = 4) => (biomes.includes(cells.biome[cell]) ? 1 : fee); // biome difference fee + const biomeGoals = (cell, biomes, fee = 4) => (biomes.includes(cells.biome[cell]) ? 1 : fee); // biome difference fee const sf = (cell, fee = 4) => (cells.haven[cell] && pack.features[cells.f[cells.haven[cell]]].type !== "lake" ? 1 : fee); // not on sea coast fee + if (culturesSet.value === "darkFantasy") { + return [ + {name: "Castien (Elvish)", base: 33, odd: 1, sort: i => (normalizedCellScore(i) / biomeGoals(i, [6, 7, 8, 9], 10)) * temperature[i], shield: "gondor"}, // Elves + {name: "Hagluin (Elvish)", base: 33, odd: 1, sort: i => (normalizedCellScore(i) / biomeGoals(i, [6, 7, 8, 9], 10)) * temperature[i], shield: "noldor"}, // Elves + {name: "Lothian (Elvish)", base: 33, odd: 1, sort: i => (normalizedCellScore(i) / biomeGoals(i, [7, 8, 9, 12], 10)) * temperature[i], shield: "wedged"}, + {name: "Dunirr (Dwarven)", base: 35, odd: 1, sort: i => normalizedCellScore(i) + (height[i]*3), shield: "ironHills"}, // Dwarfs + {name: "Khazadur (Dwarven)", base: 35, odd: 1, sort: i => normalizedCellScore(i) + (height[i]*4), shield: "erebor"}, // Dwarfs + {name: "Dhommeam (Dwarven)", base: 35, odd: 1, sort: i => normalizedCellScore(i) + height[i], shield: "erebor"}, // Dwarfs + {name: "Mudtoe (Dwarven)", base: 35, odd: 1, sort: i => normalizedCellScore(i) + height[i], shield: "erebor"}, // Dwarfs + {name: "Gongrem (Dwarven)", base: 35, odd: 1, sort: i => normalizedCellScore(i) + height[i], shield: "erebor"}, // Dwarfs + {name: "Pabolk (Goblin)", base: 36, odd: 1, sort: i => temperature[i] - s[i], shield: "moriaOrc"}, // Goblin + {name: "Lagakh (Orkish)", base: 37, odd: 1, sort: i => (height[i] * normalizedCellScore(i) * biomeGoals(i,[2], 100)), shield: "urukHai"}, // Orc + {name: "Mogak (Orkish)", base: 37, odd: 1, sort: i => (height[i]* normalizedCellScore(i) * biomeGoals(i,[2], 100)), shield: "urukHai"}, // Orc + {name: "Xugarf (Orkish)", base: 37, odd: 1, sort: i => ((height[i] * normalizedCellScore(i) * temperature[i]) / biomeGoals(i, [2, 10, 11],100)), shield: "moriaOrc"}, // Orc + {name: "Zildud (Orkish)", base: 37, odd: 1, sort: i => ((height[i]* normalizedCellScore(i) * temperature[i]) / biomeGoals(i, [2, 10, 11],100)), shield: "moriaOrc"}, // Orc + {name: "Shazgob (Orkish)", base: 37, odd: 1, sort: i => ((height[i]* normalizedCellScore(i) * temperature[i]) / biomeGoals(i, [2, 10, 11],100)), shield: "moriaOrc"}, // Orc + {name: "Mazoga (Orkish)", base: 37, odd: 1, sort: i => ((height[i] * temperature[i]) / biomeGoals(i, [2, 10, 11],100)), shield: "moriaOrc"}, // Orc + {name: "Gul (Orkish)", base: 37, odd: 1, sort: i => ((height[i] * temperature[i]) / biomeGoals(i, [2, 10, 11],100)), shield: "moriaOrc"}, // Orc + {name: "Goren (Elvish}", base: 33, odd: 0.5, sort: i => (normalizedCellScore(i) / biomeGoals(i, [6, 7, 8, 9], 10)) * temperature[i], shield: "fantasy5"}, // Elves + {name: "Ginikirr {Dwarven)", base: 35, odd: 0.8, sort: i => normalizedCellScore(i) + height[i], shield: "erebor"}, // Dwarven + {name: "Heenzurm (Goblin)", base: 36, odd: 0.8, sort: i => temperature[i] - s[i], shield: "moriaOrc"}, // Goblin + {name: "Yotunn (Giant)", base: 38, odd: 0.8, sort: i => tempDiff(i, -5), shield: "pavise"}, // Giant + {name: "Zakaos (Giant)", base: 38, odd: 0.8, sort: i => tempDiff(i, -5), shield: "pavise"}, // Giant + {name: "Fruthos (Human)", base: 32, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 10), shield: "fantasy5"}, + {name: "Rulor (Human)", base: 32, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 13), shield: "roman"}, + {name: "Gralcek (Human)", base: 16, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 16), shield: "round"}, + {name: "Llekkolk (Human)", base: 31, odd: 1, sort: i => (normalizedCellScore(i) / tempDiff(i, 5) / biomeGoals(i, [2, 4, 10], 7)) * temperature[i], shield: "easterling"} + ]; + + + + + + + if (culturesSet.value === "european") { return [ - {name: "Shwazen", base: 0, odd: 1, sort: i => n(i) / td(i, 10) / bd(i, [6, 8]), shield: "swiss"}, - {name: "Angshire", base: 1, odd: 1, sort: i => n(i) / td(i, 10) / sf(i), shield: "wedged"}, - {name: "Luari", base: 2, odd: 1, sort: i => n(i) / td(i, 12) / bd(i, [6, 8]), shield: "french"}, - {name: "Tallian", base: 3, odd: 1, sort: i => n(i) / td(i, 15), shield: "horsehead"}, - {name: "Astellian", base: 4, odd: 1, sort: i => n(i) / td(i, 16), shield: "spanish"}, - {name: "Slovan", base: 5, odd: 1, sort: i => (n(i) / td(i, 6)) * t[i], shield: "polish"}, - {name: "Norse", base: 6, odd: 1, sort: i => n(i) / td(i, 5), shield: "heater"}, - {name: "Elladan", base: 7, odd: 1, sort: i => (n(i) / td(i, 18)) * h[i], shield: "boeotian"}, - {name: "Romian", base: 8, odd: 0.2, sort: i => n(i) / td(i, 15) / t[i], shield: "roman"}, - {name: "Soumi", base: 9, odd: 1, sort: i => (n(i) / td(i, 5) / bd(i, [9])) * t[i], shield: "pavise"}, - {name: "Portuzian", base: 13, odd: 1, sort: i => n(i) / td(i, 17) / sf(i), shield: "renaissance"}, - {name: "Vengrian", base: 15, odd: 1, sort: i => (n(i) / td(i, 11) / bd(i, [4])) * t[i], shield: "horsehead2"}, - {name: "Turchian", base: 16, odd: 0.05, sort: i => n(i) / td(i, 14), shield: "round"}, - {name: "Euskati", base: 20, odd: 0.05, sort: i => (n(i) / td(i, 15)) * h[i], shield: "oldFrench"}, - {name: "Keltan", base: 22, odd: 0.05, sort: i => (n(i) / td(i, 11) / bd(i, [6, 8])) * t[i], shield: "oval"} + {name: "Shwazen", base: 0, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 10) / biomeGoals(i, [6, 8]), shield: "swiss"}, + {name: "Angshire", base: 1, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 10) / sf(i), shield: "wedged"}, + {name: "Luari", base: 2, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 12) / biomeGoals(i, [6, 8]), shield: "french"}, + {name: "Tallian", base: 3, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 15), shield: "horsehead"}, + {name: "Astellian", base: 4, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 16), shield: "spanish"}, + {name: "Slovan", base: 5, odd: 1, sort: i => (normalizedCellScore(i) / tempDiff(i, 6)) * temperature[i], shield: "polish"}, + {name: "Norse", base: 6, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 5), shield: "heater"}, + {name: "Elladan", base: 7, odd: 1, sort: i => (normalizedCellScore(i) / tempDiff(i, 18)) * height[i], shield: "boeotian"}, + {name: "Romian", base: 8, odd: 0.2, sort: i => normalizedCellScore(i) / tempDiff(i, 15) / temperature[i], shield: "roman"}, + {name: "Soumi", base: 9, odd: 1, sort: i => (normalizedCellScore(i) / tempDiff(i, 5) / biomeGoals(i, [9])) * temperature[i], shield: "pavise"}, + {name: "Portuzian", base: 13, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 17) / sf(i), shield: "renaissance"}, + {name: "Vengrian", base: 15, odd: 1, sort: i => (normalizedCellScore(i) / tempDiff(i, 11) / biomeGoals(i, [4])) * temperature[i], shield: "horsehead2"}, + {name: "Turchian", base: 16, odd: 0.05, sort: i => normalizedCellScore(i) / tempDiff(i, 14), shield: "round"}, + {name: "Euskati", base: 20, odd: 0.05, sort: i => (normalizedCellScore(i) / tempDiff(i, 15)) * height[i], shield: "oldFrench"}, + {name: "Keltan", base: 22, odd: 0.05, sort: i => (normalizedCellScore(i) / tempDiff(i, 11) / biomeGoals(i, [6, 8])) * temperature[i], shield: "oval"} ]; } if (culturesSet.value === "oriental") { return [ - {name: "Koryo", base: 10, odd: 1, sort: i => n(i) / td(i, 12) / t[i], shield: "round"}, - {name: "Hantzu", base: 11, odd: 1, sort: i => n(i) / td(i, 13), shield: "banner"}, - {name: "Yamoto", base: 12, odd: 1, sort: i => n(i) / td(i, 15) / t[i], shield: "round"}, - {name: "Turchian", base: 16, odd: 1, sort: i => n(i) / td(i, 12), shield: "round"}, - {name: "Berberan", base: 17, odd: 0.2, sort: i => (n(i) / td(i, 19) / bd(i, [1, 2, 3], 7)) * t[i], shield: "oval"}, - {name: "Eurabic", base: 18, odd: 1, sort: i => (n(i) / td(i, 26) / bd(i, [1, 2], 7)) * t[i], shield: "oval"}, - {name: "Efratic", base: 23, odd: 0.1, sort: i => (n(i) / td(i, 22)) * t[i], shield: "round"}, - {name: "Tehrani", base: 24, odd: 1, sort: i => (n(i) / td(i, 18)) * h[i], shield: "round"}, - {name: "Maui", base: 25, odd: 0.2, sort: i => n(i) / td(i, 24) / sf(i) / t[i], shield: "vesicaPiscis"}, - {name: "Carnatic", base: 26, odd: 0.5, sort: i => n(i) / td(i, 26), shield: "round"}, - {name: "Vietic", base: 29, odd: 0.8, sort: i => n(i) / td(i, 25) / bd(i, [7], 7) / t[i], shield: "banner"}, - {name: "Guantzu", base: 30, odd: 0.5, sort: i => n(i) / td(i, 17), shield: "banner"}, - {name: "Ulus", base: 31, odd: 1, sort: i => (n(i) / td(i, 5) / bd(i, [2, 4, 10], 7)) * t[i], shield: "banner"} + {name: "Koryo", base: 10, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 12) / temperature[i], shield: "round"}, + {name: "Hantzu", base: 11, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 13), shield: "banner"}, + {name: "Yamoto", base: 12, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 15) / temperature[i], shield: "round"}, + {name: "Turchian", base: 16, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 12), shield: "round"}, + {name: "Berberan", base: 17, odd: 0.2, sort: i => (normalizedCellScore(i) / tempDiff(i, 19) / biomeGoals(i, [1, 2, 3], 7)) * temperature[i], shield: "oval"}, + {name: "Eurabic", base: 18, odd: 1, sort: i => (normalizedCellScore(i) / tempDiff(i, 26) / biomeGoals(i, [1, 2], 7)) * temperature[i], shield: "oval"}, + {name: "Efratic", base: 23, odd: 0.1, sort: i => (normalizedCellScore(i) / tempDiff(i, 22)) * temperature[i], shield: "round"}, + {name: "Tehrani", base: 24, odd: 1, sort: i => (normalizedCellScore(i) / tempDiff(i, 18)) * height[i], shield: "round"}, + {name: "Maui", base: 25, odd: 0.2, sort: i => normalizedCellScore(i) / tempDiff(i, 24) / sf(i) / temperature[i], shield: "vesicaPiscis"}, + {name: "Carnatic", base: 26, odd: 0.5, sort: i => normalizedCellScore(i) / tempDiff(i, 26), shield: "round"}, + {name: "Vietic", base: 29, odd: 0.8, sort: i => normalizedCellScore(i) / tempDiff(i, 25) / biomeGoals(i, [7], 7) / temperature[i], shield: "banner"}, + {name: "Guantzu", base: 30, odd: 0.5, sort: i => normalizedCellScore(i) / tempDiff(i, 17), shield: "banner"}, + {name: "Ulus", base: 31, odd: 1, sort: i => (normalizedCellScore(i) / tempDiff(i, 5) / biomeGoals(i, [2, 4, 10], 7)) * temperature[i], shield: "banner"} ]; } @@ -240,89 +275,51 @@ window.Cultures = (function () { if (culturesSet.value === "antique") { return [ - {name: "Roman", base: 8, odd: 1, sort: i => n(i) / td(i, 14) / t[i], shield: "roman"}, // Roman - {name: "Roman", base: 8, odd: 1, sort: i => n(i) / td(i, 15) / sf(i), shield: "roman"}, // Roman - {name: "Roman", base: 8, odd: 1, sort: i => n(i) / td(i, 16) / sf(i), shield: "roman"}, // Roman - {name: "Roman", base: 8, odd: 1, sort: i => n(i) / td(i, 17) / t[i], shield: "roman"}, // Roman - {name: "Hellenic", base: 7, odd: 1, sort: i => (n(i) / td(i, 18) / sf(i)) * h[i], shield: "boeotian"}, // Greek - {name: "Hellenic", base: 7, odd: 1, sort: i => (n(i) / td(i, 19) / sf(i)) * h[i], shield: "boeotian"}, // Greek - {name: "Macedonian", base: 7, odd: 0.5, sort: i => (n(i) / td(i, 12)) * h[i], shield: "round"}, // Greek - {name: "Celtic", base: 22, odd: 1, sort: i => n(i) / td(i, 11) ** 0.5 / bd(i, [6, 8]), shield: "round"}, - {name: "Germanic", base: 0, odd: 1, sort: i => n(i) / td(i, 10) ** 0.5 / bd(i, [6, 8]), shield: "round"}, - {name: "Persian", base: 24, odd: 0.8, sort: i => (n(i) / td(i, 18)) * h[i], shield: "oval"}, // Iranian - {name: "Scythian", base: 24, odd: 0.5, sort: i => n(i) / td(i, 11) ** 0.5 / bd(i, [4]), shield: "round"}, // Iranian - {name: "Cantabrian", base: 20, odd: 0.5, sort: i => (n(i) / td(i, 16)) * h[i], shield: "oval"}, // Basque - {name: "Estian", base: 9, odd: 0.2, sort: i => (n(i) / td(i, 5)) * t[i], shield: "pavise"}, // Finnic - {name: "Carthaginian", base: 17, odd: 0.3, sort: i => n(i) / td(i, 19) / sf(i), shield: "oval"}, // Berber - {name: "Mesopotamian", base: 23, odd: 0.2, sort: i => n(i) / td(i, 22) / bd(i, [1, 2, 3]), shield: "oval"} // Mesopotamian + {name: "Roman", base: 8, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 14) / temperature[i], shield: "roman"}, // Roman + {name: "Roman", base: 8, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 15) / sf(i), shield: "roman"}, // Roman + {name: "Roman", base: 8, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 16) / sf(i), shield: "roman"}, // Roman + {name: "Roman", base: 8, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 17) / temperature[i], shield: "roman"}, // Roman + {name: "Hellenic", base: 7, odd: 1, sort: i => (normalizedCellScore(i) / tempDiff(i, 18) / sf(i)) * height[i], shield: "boeotian"}, // Greek + {name: "Hellenic", base: 7, odd: 1, sort: i => (normalizedCellScore(i) / tempDiff(i, 19) / sf(i)) * height[i], shield: "boeotian"}, // Greek + {name: "Macedonian", base: 7, odd: 0.5, sort: i => (normalizedCellScore(i) / tempDiff(i, 12)) * height[i], shield: "round"}, // Greek + {name: "Celtic", base: 22, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 11) ** 0.5 / biomeGoals(i, [6, 8]), shield: "round"}, + {name: "Germanic", base: 0, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 10) ** 0.5 / biomeGoals(i, [6, 8]), shield: "round"}, + {name: "Persian", base: 24, odd: 0.8, sort: i => (normalizedCellScore(i) / tempDiff(i, 18)) * height[i], shield: "oval"}, // Iranian + {name: "Scythian", base: 24, odd: 0.5, sort: i => normalizedCellScore(i) / tempDiff(i, 11) ** 0.5 / biomeGoals(i, [4]), shield: "round"}, // Iranian + {name: "Cantabrian", base: 20, odd: 0.5, sort: i => (normalizedCellScore(i) / tempDiff(i, 16)) * height[i], shield: "oval"}, // Basque + {name: "Estian", base: 9, odd: 0.2, sort: i => (normalizedCellScore(i) / tempDiff(i, 5)) * temperature[i], shield: "pavise"}, // Finnic + {name: "Carthaginian", base: 17, odd: 0.3, sort: i => normalizedCellScore(i) / tempDiff(i, 19) / sf(i), shield: "oval"}, // Berber + {name: "Mesopotamian", base: 23, odd: 0.2, sort: i => normalizedCellScore(i) / tempDiff(i, 22) / biomeGoals(i, [1, 2, 3]), shield: "oval"} // Mesopotamian ]; } + /** + * Note the sort is the way the race orders the cell by preference + */ if (culturesSet.value === "highFantasy") { return [ // fantasy races - {name: "Quenian (Elfish)", base: 33, odd: 1, sort: i => (n(i) / bd(i, [6, 7, 8, 9], 10)) * t[i], shield: "gondor"}, // Elves - {name: "Eldar (Elfish)", base: 33, odd: 1, sort: i => (n(i) / bd(i, [6, 7, 8, 9], 10)) * t[i], shield: "noldor"}, // Elves - {name: "Trow (Dark Elfish)", base: 34, odd: 0.9, sort: i => (n(i) / bd(i, [7, 8, 9, 12], 10)) * t[i], shield: "hessen"}, // Dark Elves - {name: "Lothian (Dark Elfish)", base: 34, odd: 0.3, sort: i => (n(i) / bd(i, [7, 8, 9, 12], 10)) * t[i], shield: "wedged"}, // Dark Elves - {name: "Dunirr (Dwarven)", base: 35, odd: 1, sort: i => n(i) + h[i], shield: "ironHills"}, // Dwarfs - {name: "Khazadur (Dwarven)", base: 35, odd: 1, sort: i => n(i) + h[i], shield: "erebor"}, // Dwarfs - {name: "Kobold (Goblin)", base: 36, odd: 1, sort: i => t[i] - s[i], shield: "moriaOrc"}, // Goblin - {name: "Uruk (Orkish)", base: 37, odd: 1, sort: i => h[i] * t[i], shield: "urukHai"}, // Orc - {name: "Ugluk (Orkish)", base: 37, odd: 0.5, sort: i => (h[i] * t[i]) / bd(i, [1, 2, 10, 11]), shield: "moriaOrc"}, // Orc - {name: "Yotunn (Giants)", base: 38, odd: 0.7, sort: i => td(i, -10), shield: "pavise"}, // Giant + {name: "Quenian (Elfish)", base: 33, odd: 1, sort: i => (normalizedCellScore(i) / biomeGoals(i, [6, 7, 8, 9], 10)) * temperature[i], shield: "gondor"}, // Elves + {name: "Eldar (Elfish)", base: 33, odd: 1, sort: i => (normalizedCellScore(i) / biomeGoals(i, [6, 7, 8, 9], 10)) * temperature[i], shield: "noldor"}, // Elves + {name: "Trow (Dark Elfish)", base: 34, odd: 0.9, sort: i => (normalizedCellScore(i) / biomeGoals(i, [7, 8, 9, 12], 10)) * temperature[i], shield: "hessen"}, // Dark Elves + {name: "Lothian (Dark Elfish)", base: 34, odd: 0.3, sort: i => (normalizedCellScore(i) / biomeGoals(i, [7, 8, 9, 12], 10)) * temperature[i], shield: "wedged"}, // Dark Elves + {name: "Dunirr (Dwarven)", base: 35, odd: 1, sort: i => normalizedCellScore(i) + height[i], shield: "ironHills"}, // Dwarfs + {name: "Khazadur (Dwarven)", base: 35, odd: 1, sort: i => normalizedCellScore(i) + height[i], shield: "erebor"}, // Dwarfs + {name: "Kobold (Goblin)", base: 36, odd: 1, sort: i => temperature[i] - s[i], shield: "moriaOrc"}, // Goblin + {name: "Uruk (Orkish)", base: 37, odd: 1, sort: i => height[i] * temperature[i], shield: "urukHai"}, // Orc + {name: "Ugluk (Orkish)", base: 37, odd: 1.5, sort: i => (height[i] * temperature[i]) / biomeGoals(i, [1, 2, 10, 11]), shield: "moriaOrc"}, // Orc + {name: "Yotunn (Giants)", base: 38, odd: 0.7, sort: i => tempDiff(i, -10), shield: "pavise"}, // Giant {name: "Rake (Drakonic)", base: 39, odd: 0.7, sort: i => -s[i], shield: "fantasy2"}, // Draconic - {name: "Arago (Arachnid)", base: 40, odd: 0.7, sort: i => t[i] - s[i], shield: "horsehead2"}, // Arachnid - {name: "Aj'Snaga (Serpents)", base: 41, odd: 0.7, sort: i => n(i) / bd(i, [12], 10), shield: "fantasy1"}, // Serpents + {name: "Arago (Arachnid)", base: 40, odd: 0.7, sort: i => temperature[i] - s[i], shield: "horsehead2"}, // Arachnid + {name: "Aj'Snaga (Serpents)", base: 41, odd: 0.7, sort: i => normalizedCellScore(i) / biomeGoals(i, [12], 10), shield: "fantasy1"}, // Serpents // fantasy human - {name: "Anor (Human)", base: 32, odd: 1, sort: i => n(i) / td(i, 10), shield: "fantasy5"}, - {name: "Dail (Human)", base: 32, odd: 1, sort: i => n(i) / td(i, 13), shield: "roman"}, - {name: "Rohand (Human)", base: 16, odd: 1, sort: i => n(i) / td(i, 16), shield: "round"}, - {name: "Dulandir (Human)", base: 31, odd: 1, sort: i => (n(i) / td(i, 5) / bd(i, [2, 4, 10], 7)) * t[i], shield: "easterling"} + {name: "Anor (Human)", base: 32, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 10), shield: "fantasy5"}, + {name: "Dail (Human)", base: 32, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 13), shield: "roman"}, + {name: "Rohand (Human)", base: 16, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 16), shield: "round"}, + {name: "Dulandir (Human)", base: 31, odd: 1, sort: i => (normalizedCellScore(i) / tempDiff(i, 5) / biomeGoals(i, [2, 4, 10], 7)) * temperature[i], shield: "easterling"} ]; } - if (culturesSet.value === "darkFantasy") { - return [ - // common real-world English - {name: "Angshire", base: 1, odd: 1, sort: i => n(i) / td(i, 10) / sf(i), shield: "heater"}, - {name: "Enlandic", base: 1, odd: 1, sort: i => n(i) / td(i, 12), shield: "heater"}, - {name: "Westen", base: 1, odd: 1, sort: i => n(i) / td(i, 10), shield: "heater"}, - {name: "Nortumbic", base: 1, odd: 1, sort: i => n(i) / td(i, 7), shield: "heater"}, - {name: "Mercian", base: 1, odd: 1, sort: i => n(i) / td(i, 9), shield: "heater"}, - {name: "Kentian", base: 1, odd: 1, sort: i => n(i) / td(i, 12), shield: "heater"}, - // rare real-world western - {name: "Norse", base: 6, odd: 0.7, sort: i => n(i) / td(i, 5) / sf(i), shield: "oldFrench"}, - {name: "Schwarzen", base: 0, odd: 0.3, sort: i => n(i) / td(i, 10) / bd(i, [6, 8]), shield: "gonfalon"}, - {name: "Luarian", base: 2, odd: 0.3, sort: i => n(i) / td(i, 12) / bd(i, [6, 8]), shield: "oldFrench"}, - {name: "Hetallian", base: 3, odd: 0.3, sort: i => n(i) / td(i, 15), shield: "oval"}, - {name: "Astellian", base: 4, odd: 0.3, sort: i => n(i) / td(i, 16), shield: "spanish"}, - // rare real-world exotic - {name: "Kiswaili", base: 28, odd: 0.05, sort: i => n(i) / td(i, 29) / bd(i, [1, 3, 5, 7]), shield: "vesicaPiscis"}, - {name: "Yoruba", base: 21, odd: 0.05, sort: i => n(i) / td(i, 15) / bd(i, [5, 7]), shield: "vesicaPiscis"}, - {name: "Koryo", base: 10, odd: 0.05, sort: i => n(i) / td(i, 12) / t[i], shield: "round"}, - {name: "Hantzu", base: 11, odd: 0.05, sort: i => n(i) / td(i, 13), shield: "banner"}, - {name: "Yamoto", base: 12, odd: 0.05, sort: i => n(i) / td(i, 15) / t[i], shield: "round"}, - {name: "Guantzu", base: 30, odd: 0.05, sort: i => n(i) / td(i, 17), shield: "banner"}, - {name: "Ulus", base: 31, odd: 0.05, sort: i => (n(i) / td(i, 5) / bd(i, [2, 4, 10], 7)) * t[i], shield: "banner"}, - {name: "Turan", base: 16, odd: 0.05, sort: i => n(i) / td(i, 12), shield: "round"}, - {name: "Berberan", base: 17, odd: 0.05, sort: i => (n(i) / td(i, 19) / bd(i, [1, 2, 3], 7)) * t[i], shield: "round"}, - {name: "Eurabic", base: 18, odd: 0.05, sort: i => (n(i) / td(i, 26) / bd(i, [1, 2], 7)) * t[i], shield: "round"}, - {name: "Slovan", base: 5, odd: 0.05, sort: i => (n(i) / td(i, 6)) * t[i], shield: "round"}, - {name: "Keltan", base: 22, odd: 0.1, sort: i => n(i) / td(i, 11) ** 0.5 / bd(i, [6, 8]), shield: "vesicaPiscis"}, - {name: "Elladan", base: 7, odd: 0.2, sort: i => (n(i) / td(i, 18) / sf(i)) * h[i], shield: "boeotian"}, - {name: "Romian", base: 8, odd: 0.2, sort: i => n(i) / td(i, 14) / t[i], shield: "roman"}, - // fantasy races - {name: "Eldar", base: 33, odd: 0.5, sort: i => (n(i) / bd(i, [6, 7, 8, 9], 10)) * t[i], shield: "fantasy5"}, // Elves - {name: "Trow", base: 34, odd: 0.8, sort: i => (n(i) / bd(i, [7, 8, 9, 12], 10)) * t[i], shield: "hessen"}, // Dark Elves - {name: "Durinn", base: 35, odd: 0.8, sort: i => n(i) + h[i], shield: "erebor"}, // Dwarven - {name: "Kobblin", base: 36, odd: 0.8, sort: i => t[i] - s[i], shield: "moriaOrc"}, // Goblin - {name: "Uruk", base: 37, odd: 0.8, sort: i => (h[i] * t[i]) / bd(i, [1, 2, 10, 11]), shield: "urukHai"}, // Orc - {name: "Yotunn", base: 38, odd: 0.8, sort: i => td(i, -10), shield: "pavise"}, // Giant - {name: "Drake", base: 39, odd: 0.9, sort: i => -s[i], shield: "fantasy2"}, // Draconic - {name: "Rakhnid", base: 40, odd: 0.9, sort: i => t[i] - s[i], shield: "horsehead2"}, // Arachnid - {name: "Aj'Snaga", base: 41, odd: 0.9, sort: i => n(i) / bd(i, [12], 10), shield: "fantasy1"} // Serpents - ]; } if (culturesSet.value === "random") { @@ -335,38 +332,38 @@ window.Cultures = (function () { // all-world return [ - {name: "Shwazen", base: 0, odd: 0.7, sort: i => n(i) / td(i, 10) / bd(i, [6, 8]), shield: "hessen"}, - {name: "Angshire", base: 1, odd: 1, sort: i => n(i) / td(i, 10) / sf(i), shield: "heater"}, - {name: "Luari", base: 2, odd: 0.6, sort: i => n(i) / td(i, 12) / bd(i, [6, 8]), shield: "oldFrench"}, - {name: "Tallian", base: 3, odd: 0.6, sort: i => n(i) / td(i, 15), shield: "horsehead2"}, - {name: "Astellian", base: 4, odd: 0.6, sort: i => n(i) / td(i, 16), shield: "spanish"}, - {name: "Slovan", base: 5, odd: 0.7, sort: i => (n(i) / td(i, 6)) * t[i], shield: "round"}, - {name: "Norse", base: 6, odd: 0.7, sort: i => n(i) / td(i, 5), shield: "heater"}, - {name: "Elladan", base: 7, odd: 0.7, sort: i => (n(i) / td(i, 18)) * h[i], shield: "boeotian"}, - {name: "Romian", base: 8, odd: 0.7, sort: i => n(i) / td(i, 15), shield: "roman"}, - {name: "Soumi", base: 9, odd: 0.3, sort: i => (n(i) / td(i, 5) / bd(i, [9])) * t[i], shield: "pavise"}, - {name: "Koryo", base: 10, odd: 0.1, sort: i => n(i) / td(i, 12) / t[i], shield: "round"}, - {name: "Hantzu", base: 11, odd: 0.1, sort: i => n(i) / td(i, 13), shield: "banner"}, - {name: "Yamoto", base: 12, odd: 0.1, sort: i => n(i) / td(i, 15) / t[i], shield: "round"}, - {name: "Portuzian", base: 13, odd: 0.4, sort: i => n(i) / td(i, 17) / sf(i), shield: "spanish"}, - {name: "Nawatli", base: 14, odd: 0.1, sort: i => h[i] / td(i, 18) / bd(i, [7]), shield: "square"}, - {name: "Vengrian", base: 15, odd: 0.2, sort: i => (n(i) / td(i, 11) / bd(i, [4])) * t[i], shield: "wedged"}, - {name: "Turchian", base: 16, odd: 0.2, sort: i => n(i) / td(i, 13), shield: "round"}, - {name: "Berberan", base: 17, odd: 0.1, sort: i => (n(i) / td(i, 19) / bd(i, [1, 2, 3], 7)) * t[i], shield: "round"}, - {name: "Eurabic", base: 18, odd: 0.2, sort: i => (n(i) / td(i, 26) / bd(i, [1, 2], 7)) * t[i], shield: "round"}, - {name: "Inuk", base: 19, odd: 0.05, sort: i => td(i, -1) / bd(i, [10, 11]) / sf(i), shield: "square"}, - {name: "Euskati", base: 20, odd: 0.05, sort: i => (n(i) / td(i, 15)) * h[i], shield: "spanish"}, - {name: "Yoruba", base: 21, odd: 0.05, sort: i => n(i) / td(i, 15) / bd(i, [5, 7]), shield: "vesicaPiscis"}, - {name: "Keltan", base: 22, odd: 0.05, sort: i => (n(i) / td(i, 11) / bd(i, [6, 8])) * t[i], shield: "vesicaPiscis"}, - {name: "Efratic", base: 23, odd: 0.05, sort: i => (n(i) / td(i, 22)) * t[i], shield: "diamond"}, - {name: "Tehrani", base: 24, odd: 0.1, sort: i => (n(i) / td(i, 18)) * h[i], shield: "round"}, - {name: "Maui", base: 25, odd: 0.05, sort: i => n(i) / td(i, 24) / sf(i) / t[i], shield: "round"}, - {name: "Carnatic", base: 26, odd: 0.05, sort: i => n(i) / td(i, 26), shield: "round"}, - {name: "Inqan", base: 27, odd: 0.05, sort: i => h[i] / td(i, 13), shield: "square"}, - {name: "Kiswaili", base: 28, odd: 0.1, sort: i => n(i) / td(i, 29) / bd(i, [1, 3, 5, 7]), shield: "vesicaPiscis"}, - {name: "Vietic", base: 29, odd: 0.1, sort: i => n(i) / td(i, 25) / bd(i, [7], 7) / t[i], shield: "banner"}, - {name: "Guantzu", base: 30, odd: 0.1, sort: i => n(i) / td(i, 17), shield: "banner"}, - {name: "Ulus", base: 31, odd: 0.1, sort: i => (n(i) / td(i, 5) / bd(i, [2, 4, 10], 7)) * t[i], shield: "banner"} + {name: "Shwazen", base: 0, odd: 0.7, sort: i => normalizedCellScore(i) / tempDiff(i, 10) / biomeGoals(i, [6, 8]), shield: "hessen"}, + {name: "Angshire", base: 1, odd: 1, sort: i => normalizedCellScore(i) / tempDiff(i, 10) / sf(i), shield: "heater"}, + {name: "Luari", base: 2, odd: 0.6, sort: i => normalizedCellScore(i) / tempDiff(i, 12) / biomeGoals(i, [6, 8]), shield: "oldFrench"}, + {name: "Tallian", base: 3, odd: 0.6, sort: i => normalizedCellScore(i) / tempDiff(i, 15), shield: "horsehead2"}, + {name: "Astellian", base: 4, odd: 0.6, sort: i => normalizedCellScore(i) / tempDiff(i, 16), shield: "spanish"}, + {name: "Slovan", base: 5, odd: 0.7, sort: i => (normalizedCellScore(i) / tempDiff(i, 6)) * temperature[i], shield: "round"}, + {name: "Norse", base: 6, odd: 0.7, sort: i => normalizedCellScore(i) / tempDiff(i, 5), shield: "heater"}, + {name: "Elladan", base: 7, odd: 0.7, sort: i => (normalizedCellScore(i) / tempDiff(i, 18)) * height[i], shield: "boeotian"}, + {name: "Romian", base: 8, odd: 0.7, sort: i => normalizedCellScore(i) / tempDiff(i, 15), shield: "roman"}, + {name: "Soumi", base: 9, odd: 0.3, sort: i => (normalizedCellScore(i) / tempDiff(i, 5) / biomeGoals(i, [9])) * temperature[i], shield: "pavise"}, + {name: "Koryo", base: 10, odd: 0.1, sort: i => normalizedCellScore(i) / tempDiff(i, 12) / temperature[i], shield: "round"}, + {name: "Hantzu", base: 11, odd: 0.1, sort: i => normalizedCellScore(i) / tempDiff(i, 13), shield: "banner"}, + {name: "Yamoto", base: 12, odd: 0.1, sort: i => normalizedCellScore(i) / tempDiff(i, 15) / temperature[i], shield: "round"}, + {name: "Portuzian", base: 13, odd: 0.4, sort: i => normalizedCellScore(i) / tempDiff(i, 17) / sf(i), shield: "spanish"}, + {name: "Nawatli", base: 14, odd: 0.1, sort: i => height[i] / tempDiff(i, 18) / biomeGoals(i, [7]), shield: "square"}, + {name: "Vengrian", base: 15, odd: 0.2, sort: i => (normalizedCellScore(i) / tempDiff(i, 11) / biomeGoals(i, [4])) * temperature[i], shield: "wedged"}, + {name: "Turchian", base: 16, odd: 0.2, sort: i => normalizedCellScore(i) / tempDiff(i, 13), shield: "round"}, + {name: "Berberan", base: 17, odd: 0.1, sort: i => (normalizedCellScore(i) / tempDiff(i, 19) / biomeGoals(i, [1, 2, 3], 7)) * temperature[i], shield: "round"}, + {name: "Eurabic", base: 18, odd: 0.2, sort: i => (normalizedCellScore(i) / tempDiff(i, 26) / biomeGoals(i, [1, 2], 7)) * temperature[i], shield: "round"}, + {name: "Inuk", base: 19, odd: 0.05, sort: i => tempDiff(i, -1) / biomeGoals(i, [10, 11]) / sf(i), shield: "square"}, + {name: "Euskati", base: 20, odd: 0.05, sort: i => (normalizedCellScore(i) / tempDiff(i, 15)) * height[i], shield: "spanish"}, + {name: "Yoruba", base: 21, odd: 0.05, sort: i => normalizedCellScore(i) / tempDiff(i, 15) / biomeGoals(i, [5, 7]), shield: "vesicaPiscis"}, + {name: "Keltan", base: 22, odd: 0.05, sort: i => (normalizedCellScore(i) / tempDiff(i, 11) / biomeGoals(i, [6, 8])) * temperature[i], shield: "vesicaPiscis"}, + {name: "Efratic", base: 23, odd: 0.05, sort: i => (normalizedCellScore(i) / tempDiff(i, 22)) * temperature[i], shield: "diamond"}, + {name: "Tehrani", base: 24, odd: 0.1, sort: i => (normalizedCellScore(i) / tempDiff(i, 18)) * height[i], shield: "round"}, + {name: "Maui", base: 25, odd: 0.05, sort: i => normalizedCellScore(i) / tempDiff(i, 24) / sf(i) / temperature[i], shield: "round"}, + {name: "Carnatic", base: 26, odd: 0.05, sort: i => normalizedCellScore(i) / tempDiff(i, 26), shield: "round"}, + {name: "Inqan", base: 27, odd: 0.05, sort: i => height[i] / tempDiff(i, 13), shield: "square"}, + {name: "Kiswaili", base: 28, odd: 0.1, sort: i => normalizedCellScore(i) / tempDiff(i, 29) / biomeGoals(i, [1, 3, 5, 7]), shield: "vesicaPiscis"}, + {name: "Vietic", base: 29, odd: 0.1, sort: i => normalizedCellScore(i) / tempDiff(i, 25) / biomeGoals(i, [7], 7) / temperature[i], shield: "banner"}, + {name: "Guantzu", base: 30, odd: 0.1, sort: i => normalizedCellScore(i) / tempDiff(i, 17), shield: "banner"}, + {name: "Ulus", base: 31, odd: 0.1, sort: i => (normalizedCellScore(i) / tempDiff(i, 5) / biomeGoals(i, [2, 4, 10], 7)) * temperature[i], shield: "banner"} ]; }; diff --git a/modules/religions-generator.js b/modules/religions-generator.js index b0b0dae2..c7e3075e 100644 --- a/modules/religions-generator.js +++ b/modules/religions-generator.js @@ -351,6 +351,7 @@ window.Religions = (function () { : cells.i.filter(i => cells.s[i] > 2).sort((a, b) => cells.s[b] - cells.s[a]); const religionsTree = d3.quadtree(); const spacing = (graphWidth + graphHeight) / 6 / religionsInput.value; // base min distance between towns + //const spacing = (graphWidth + graphHeight) / distanceScaleInput.value const cultsCount = Math.floor((rand(10, 40) / 100) * religionsInput.value); const count = +religionsInput.value - cultsCount + religions.length; diff --git a/modules/river-generator.js b/modules/river-generator.js index 173f5626..59e39b14 100644 --- a/modules/river-generator.js +++ b/modules/river-generator.js @@ -160,8 +160,12 @@ window.Rivers = (function () { // mark real confluences and assign river to cells if (cells.r[cell]) cells.conf[cell] = 1; else cells.r[cell] = riverId; + if (cells.s && cells.s[cell]) { + cells.s[cell] = cells.s[cell] * 1.25; // Increase value of rivers + } } + const source = riverCells[0]; const mouth = riverCells[riverCells.length - 2]; const parent = riverParents[key] || 0; diff --git a/modules/ui/burg-editor.js b/modules/ui/burg-editor.js index 1fcdf434..70b8968a 100644 --- a/modules/ui/burg-editor.js +++ b/modules/ui/burg-editor.js @@ -416,8 +416,8 @@ function editBurg(id) { const {cells} = pack; const {name, population, cell} = burg; const burgSeed = getBurgSeed(burg); - const sizeRaw = 2.13 * Math.pow((population * populationRate) / urbanDensity, 0.385); - const size = minmax(Math.ceil(sizeRaw), 6, 100); + const sizeRaw = 0.43 * Math.pow((population * populationRate) / urbanDensity, 0.385); + const size = minmax(Math.ceil(sizeRaw), 2, 40); const people = rn(population * populationRate * urbanization); const hub = +cells.road[cell] > 50;