app/assets/javascripts/d3.v7.js in d3-rails-7.0.0 vs app/assets/javascripts/d3.v7.js in d3-rails-7.8.5

- old
+ new

@@ -1,65 +1,78 @@ -// https://d3js.org v7.0.0 Copyright 2010-2021 Mike Bostock +// https://d3js.org v7.8.5 Copyright 2010-2023 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'; +})(this, (function (exports) { 'use strict'; -var version = "7.0.0"; +var version = "7.8.5"; function ascending$3(a, b) { + return a == null || b == null ? NaN : a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; +} + +function descending$2(a, b) { return a == null || b == null ? NaN - : a < b ? -1 - : a > b ? 1 - : a >= b ? 0 + : b < a ? -1 + : b > a ? 1 + : b >= a ? 0 : NaN; } function bisector(f) { - let delta = f; - let compare = f; + let compare1, compare2, delta; - if (f.length === 1) { + // If an accessor is specified, promote it to a comparator. In this case we + // can test whether the search value is (self-) comparable. We can’t do this + // for a comparator (except for specific, known comparators) because we can’t + // tell if the comparator is symmetric, and an asymmetric comparator can’t be + // used to test whether a single value is comparable. + if (f.length !== 2) { + compare1 = ascending$3; + compare2 = (d, x) => ascending$3(f(d), x); delta = (d, x) => f(d) - x; - compare = ascendingComparator(f); + } else { + compare1 = f === ascending$3 || f === descending$2 ? f : zero$1; + compare2 = f; + delta = f; } - function left(a, x, lo, hi) { - if (lo == null) lo = 0; - if (hi == null) hi = a.length; - while (lo < hi) { - const mid = (lo + hi) >>> 1; - if (compare(a[mid], x) < 0) lo = mid + 1; - else hi = mid; + 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, hi) { - if (lo == null) lo = 0; - if (hi == null) hi = a.length; - while (lo < hi) { - const mid = (lo + hi) >>> 1; - if (compare(a[mid], x) > 0) hi = mid; - else lo = mid + 1; + 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, hi) { - if (lo == null) lo = 0; - if (hi == null) hi = a.length; + 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 ascendingComparator(f) { - return (d, x) => ascending$3(f(d), x); +function zero$1() { + return 0; } function number$3(x) { return x === null ? NaN : +x; } @@ -83,11 +96,128 @@ const ascendingBisect = bisector(ascending$3); const bisectRight = ascendingBisect.right; const bisectLeft = ascendingBisect.left; const bisectCenter = bisector(number$3).center; +var bisect = bisectRight; +function blur(values, r) { + if (!((r = +r) >= 0)) throw new RangeError("invalid r"); + let length = values.length; + if (!((length = Math.floor(length)) >= 0)) throw new RangeError("invalid length"); + if (!length || !r) return values; + const blur = blurf(r); + const temp = values.slice(); + blur(values, temp, 0, length, 1); + blur(temp, values, 0, length, 1); + blur(values, temp, 0, length, 1); + return values; +} + +const blur2 = Blur2(blurf); + +const blurImage = Blur2(blurfImage); + +function Blur2(blur) { + return function(data, rx, ry = rx) { + if (!((rx = +rx) >= 0)) throw new RangeError("invalid rx"); + if (!((ry = +ry) >= 0)) throw new RangeError("invalid ry"); + let {data: values, width, height} = data; + if (!((width = Math.floor(width)) >= 0)) throw new RangeError("invalid width"); + if (!((height = Math.floor(height !== undefined ? height : values.length / width)) >= 0)) throw new RangeError("invalid height"); + if (!width || !height || (!rx && !ry)) return data; + const blurx = rx && blur(rx); + const blury = ry && blur(ry); + const temp = values.slice(); + if (blurx && blury) { + blurh(blurx, temp, values, width, height); + blurh(blurx, values, temp, width, height); + blurh(blurx, temp, values, width, height); + blurv(blury, values, temp, width, height); + blurv(blury, temp, values, width, height); + blurv(blury, values, temp, width, height); + } else if (blurx) { + blurh(blurx, values, temp, width, height); + blurh(blurx, temp, values, width, height); + blurh(blurx, values, temp, width, height); + } else if (blury) { + blurv(blury, values, temp, width, height); + blurv(blury, temp, values, width, height); + blurv(blury, values, temp, width, height); + } + return data; + }; +} + +function blurh(blur, T, S, w, h) { + for (let y = 0, n = w * h; y < n;) { + blur(T, S, y, y += w, 1); + } +} + +function blurv(blur, T, S, w, h) { + for (let x = 0, n = w * h; x < w; ++x) { + blur(T, S, x, x + n, w); + } +} + +function blurfImage(radius) { + const blur = blurf(radius); + return (T, S, start, stop, step) => { + start <<= 2, stop <<= 2, step <<= 2; + blur(T, S, start + 0, stop + 0, step); + blur(T, S, start + 1, stop + 1, step); + blur(T, S, start + 2, stop + 2, step); + blur(T, S, start + 3, stop + 3, step); + }; +} + +// Given a target array T, a source array S, sets each value T[i] to the average +// of {S[i - r], …, S[i], …, S[i + r]}, where r = ⌊radius⌋, start <= i < stop, +// for each i, i + step, i + 2 * step, etc., and where S[j] is clamped between +// S[start] (inclusive) and S[stop] (exclusive). If the given radius is not an +// integer, S[i - r - 1] and S[i + r + 1] are added to the sum, each weighted +// according to r - ⌊radius⌋. +function blurf(radius) { + const radius0 = Math.floor(radius); + if (radius0 === radius) return bluri(radius); + const t = radius - radius0; + const w = 2 * radius + 1; + return (T, S, start, stop, step) => { // stop must be aligned! + if (!((stop -= step) >= start)) return; // inclusive stop + let sum = radius0 * S[start]; + const s0 = step * radius0; + const s1 = s0 + step; + for (let i = start, j = start + s0; i < j; i += step) { + sum += S[Math.min(stop, i)]; + } + for (let i = start, j = stop; i <= j; i += step) { + sum += S[Math.min(stop, i + s0)]; + T[i] = (sum + t * (S[Math.max(start, i - s1)] + S[Math.min(stop, i + s1)])) / w; + sum -= S[Math.max(start, i - s0)]; + } + }; +} + +// Like blurf, but optimized for integer radius. +function bluri(radius) { + const w = 2 * radius + 1; + return (T, S, start, stop, step) => { // stop must be aligned! + if (!((stop -= step) >= start)) return; // inclusive stop + let sum = radius * S[start]; + const s = step * radius; + for (let i = start, j = start + s; i < j; i += step) { + sum += S[Math.min(stop, i)]; + } + for (let i = start, j = stop; i <= j; i += step) { + sum += S[Math.min(stop, i + s)]; + T[i] = sum / w; + sum -= S[Math.max(start, i - s)]; + } + }; +} + function count$1(values, valueof) { let count = 0; if (valueof === undefined) { for (let value of values) { if (value != null && (value = +value) >= value) { @@ -144,18 +274,10 @@ 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; @@ -335,11 +457,11 @@ } function intern_delete({_intern, _key}, value) { const key = _key(value); if (_intern.has(key)) { - value = _intern.get(value); + value = _intern.get(key); _intern.delete(key); } return value; } @@ -419,100 +541,113 @@ } function sort(values, ...F) { if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable"); values = Array.from(values); - let [f = ascending$3] = F; - if (f.length === 1 || F.length > 1) { + 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 = ascending$3(f[i], f[j]); + const c = ascendingDefined(f[i], f[j]); if (c) return c; } }); } else { f = values.map(f); - index.sort((i, j) => ascending$3(f[i], f[j])); + index.sort((i, j) => ascendingDefined(f[i], f[j])); } return permute(values, index); } - return values.sort(f); + 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 === 1 + 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 function() { - return x; - }; + return () => x; } -var e10 = Math.sqrt(50), +const e10 = Math.sqrt(50), e5 = Math.sqrt(10), e2 = Math.sqrt(2); -function ticks(start, stop, count) { - var reverse, - i = -1, - n, - ticks, - step; +function tickSpec(start, stop, count) { + const step = (stop - start) / Math.max(0, count), + power = Math.floor(Math.log10(step)), + error = step / Math.pow(10, power), + factor = error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1; + let i1, i2, inc; + if (power < 0) { + inc = Math.pow(10, -power) / factor; + i1 = Math.round(start * inc); + i2 = Math.round(stop * inc); + if (i1 / inc < start) ++i1; + if (i2 / inc > stop) --i2; + inc = -inc; + } else { + inc = Math.pow(10, power) * factor; + i1 = Math.round(start / inc); + i2 = Math.round(stop / inc); + if (i1 * inc < start) ++i1; + if (i2 * inc > stop) --i2; + } + if (i2 < i1 && 0.5 <= count && count < 2) return tickSpec(start, stop, count * 2); + return [i1, i2, inc]; +} +function ticks(start, stop, count) { 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; + if (!(count > 0)) return []; + if (start === stop) return [start]; + const reverse = stop < start, [i1, i2, inc] = reverse ? tickSpec(stop, start, count) : tickSpec(start, stop, count); + if (!(i2 >= i1)) return []; + const n = i2 - i1 + 1, ticks = new Array(n); + if (reverse) { + if (inc < 0) for (let i = 0; i < n; ++i) ticks[i] = (i2 - i) / -inc; + else for (let i = 0; i < n; ++i) ticks[i] = (i2 - i) * inc; } 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 (inc < 0) for (let i = 0; i < n; ++i) ticks[i] = (i1 + i) / -inc; + else for (let i = 0; i < n; ++i) ticks[i] = (i1 + i) * inc; } - - 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); + stop = +stop, start = +start, count = +count; + return tickSpec(start, stop, count)[2]; } 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; + stop = +stop, start = +start, count = +count; + const reverse = stop < start, inc = reverse ? tickIncrement(stop, start, count) : tickIncrement(start, stop, count); + return (reverse ? -1 : 1) * (inc < 0 ? 1 / -inc : inc); } function nice$1(start, stop, count) { let prestep; while (true) { @@ -529,11 +664,11 @@ prestep = step; } } function thresholdSturges(values) { - return Math.ceil(Math.log(count$1(values)) / Math.LN2) + 1; + return Math.max(1, Math.ceil(Math.log(count$1(values)) / Math.LN2) + 1); } function bin() { var value = identity$9, domain = extent$1, @@ -543,10 +678,11 @@ if (!Array.isArray(data)) data = Array.from(data); var i, n = data.length, x, + step, values = new Array(n); for (i = 0; i < n; ++i) { values[i] = value(data[i], i, data); } @@ -561,10 +697,15 @@ 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 domain is aligned with the first tick (which it will by + // default), then we can use quantization rather than bisection to bin + // values, which is substantially faster. + if (tz[0] <= x0) step = tickIncrement(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 @@ -585,13 +726,15 @@ } } } // 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; + // Be careful not to mutate an array owned by the user! + var m = tz.length, a = 0, b = m; + while (tz[a] <= x0) ++a; + while (tz[b - 1] > x1) --b; + if (a || b < m) tz = tz.slice(a, b), m = b - a; var bins = new Array(m + 1), bin; // Initialize bins. @@ -600,15 +743,31 @@ 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[bisectRight(tz, x, 0, m)].push(data[i]); + if (isFinite(step)) { + if (step > 0) { + for (i = 0; i < n; ++i) { + if ((x = values[i]) != null && x0 <= x && x <= x1) { + bins[Math.min(m, Math.floor((x - x0) / step))].push(data[i]); + } + } + } else if (step < 0) { + for (i = 0; i < n; ++i) { + if ((x = values[i]) != null && x0 <= x && x <= x1) { + const j = Math.floor((x0 - x) * step); + bins[Math.min(m, j + (tz[j] <= x))].push(data[i]); // handle off-by-one due to rounding + } + } } + } else { + for (i = 0; i < n; ++i) { + if ((x = values[i]) != null && x0 <= x && x <= x1) { + bins[bisect(tz, x, 0, m)].push(data[i]); + } + } } return bins; } @@ -619,11 +778,11 @@ 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 arguments.length ? (threshold = typeof _ === "function" ? _ : constant$b(Array.isArray(_) ? slice$3.call(_) : _), histogram) : threshold; }; return histogram; } @@ -646,10 +805,33 @@ } } return max; } +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 min$2(values, valueof) { let min; if (valueof === undefined) { for (const value of values) { if (value != null @@ -667,13 +849,44 @@ } } return min; } +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; +} + // Based on https://github.com/mourner/quickselect // ISC license, Copyright 2018 Vladimir Agafonkin. -function quickselect(array, k, left = 0, right = array.length - 1, compare = ascending$3) { +function quickselect(array, k, left = 0, right = Infinity, compare) { + k = Math.floor(k); + left = Math.floor(Math.max(0, left)); + right = Math.floor(Math.min(array.length - 1, right)); + + if (!(left <= k && k <= right)) return array; + + 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); @@ -701,73 +914,95 @@ 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 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 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 (!(n = values.length) || isNaN(p = +p)) return; + if (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 (!(n = values.length) || isNaN(p = +p)) return; + if (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 freedmanDiaconis(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 quantileIndex(values, p, valueof = number$3) { + if (isNaN(p = +p)) return; + numbers = Float64Array.from(values, (_, i) => number$3(valueof(values[i], i, values))); + if (p <= 0) return minIndex(numbers); + if (p >= 1) return maxIndex(numbers); + var numbers, + index = Uint32Array.from(values, (_, i) => i), + j = numbers.length - 1, + i = Math.floor(j * p); + quickselect(index, i, 0, j, (i, j) => ascendingDefined(numbers[i], numbers[j])); + i = greatest(index.subarray(0, i + 1), (i) => numbers[i]); + return i >= 0 ? i : -1; } -function scott(values, min, max) { - return Math.ceil((max - min) / (3.5 * deviation(values) * Math.pow(count$1(values), -1 / 3))); +function thresholdFreedmanDiaconis(values, min, max) { + const c = count$1(values), d = quantile$1(values, 0.75) - quantile$1(values, 0.25); + return c && d ? Math.ceil((max - min) / (2 * d * Math.pow(c, -1 / 3))) : 1; } -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 thresholdScott(values, min, max) { + const c = count$1(values), d = deviation(values); + return c && d ? Math.ceil((max - min) * Math.cbrt(c) / (3.49 * d)) : 1; } function mean(values, valueof) { let count = 0; let sum = 0; @@ -790,43 +1025,24 @@ function median(values, valueof) { return quantile$1(values, 0.5, valueof); } +function medianIndex(values, valueof) { + return quantileIndex(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) { @@ -866,11 +1082,11 @@ function pair(a, b) { return [a, b]; } -function sequence(start, stop, step) { +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); @@ -880,10 +1096,32 @@ } 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; + values = Uint32Array.from(V, (_, i) => i); + // Risky chaining due to Safari 14 https://github.com/d3/d3-array/issues/123 + values.sort(valueof === ascending$3 ? (i, j) => ascendingDefined(V[i], V[j]) : compareDefined(compareIndex)); + values.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; @@ -925,38 +1163,10 @@ } } 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; @@ -1087,21 +1297,21 @@ if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable"); return Array.from(values).reverse(); } function difference(values, ...others) { - values = new Set(values); + 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 Set(); + 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; @@ -1110,16 +1320,12 @@ } } return true; } -function set$2(values) { - return values instanceof Set ? values : new Set(values); -} - function intersection(values, ...others) { - values = new Set(values); + 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); @@ -1128,30 +1334,40 @@ } } 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) { - if (set.has(o)) continue; + const io = intern(o); + if (set.has(io)) continue; let value, done; while (({value, done} = iterator.next())) { if (done) return false; - set.add(value); - if (Object.is(o, value)) break; + 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 Set(); + const set = new InternSet(); for (const other of others) { for (const o of other) { set.add(o); } } @@ -2688,19 +2904,19 @@ 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*", + 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] + "\\)$"); + 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, @@ -2850,27 +3066,32 @@ yellow: 0xffff00, yellowgreen: 0x9acd32 }; define(Color, color, { - copy: function(channels) { + copy(channels) { return Object.assign(new this.constructor, this, channels); }, - displayable: function() { + displayable() { return this.rgb().displayable(); }, hex: color_formatHex, // Deprecated! Use color.formatHex. formatHex: color_formatHex, + formatHex8: color_formatHex8, formatHsl: color_formatHsl, formatRgb: color_formatRgb, toString: color_formatRgb }); function color_formatHex() { return this.rgb().formatHex(); } +function color_formatHex8() { + return this.rgb().formatHex8(); +} + function color_formatHsl() { return hslConvert(this).formatHsl(); } function color_formatRgb() { @@ -2922,48 +3143,60 @@ this.b = +b; this.opacity = +opacity; } define(Rgb, rgb, extend(Color, { - brighter: function(k) { + brighter(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) { + darker(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() { + rgb() { return this; }, - displayable: function() { + clamp() { + return new Rgb(clampi(this.r), clampi(this.g), clampi(this.b), clampa(this.opacity)); + }, + displayable() { 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, + formatHex8: rgb_formatHex8, formatRgb: rgb_formatRgb, toString: rgb_formatRgb })); function rgb_formatHex() { - return "#" + hex(this.r) + hex(this.g) + hex(this.b); + return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}`; } +function rgb_formatHex8() { + return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}${hex((isNaN(this.opacity) ? 1 : this.opacity) * 255)}`; +} + 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 + ")"); + const a = clampa(this.opacity); + return `${a === 1 ? "rgb(" : "rgba("}${clampi(this.r)}, ${clampi(this.g)}, ${clampi(this.b)}${a === 1 ? ")" : `, ${a})`}`; } +function clampa(opacity) { + return isNaN(opacity) ? 1 : Math.max(0, Math.min(1, opacity)); +} + +function clampi(value) { + return Math.max(0, Math.min(255, Math.round(value) || 0)); +} + function hex(value) { - value = Math.max(0, Math.min(255, Math.round(value) || 0)); + value = clampi(value); return (value < 16 ? "0" : "") + value.toString(16); } function hsla(h, s, l, a) { if (a <= 0) h = s = l = NaN; @@ -3008,19 +3241,19 @@ this.l = +l; this.opacity = +opacity; } define(Hsl, hsl$2, extend(Color, { - brighter: function(k) { + brighter(k) { k = k == null ? brighter : Math.pow(brighter, k); return new Hsl(this.h, this.s, this.l * k, this.opacity); }, - darker: function(k) { + darker(k) { k = k == null ? darker : Math.pow(darker, k); return new Hsl(this.h, this.s, this.l * k, this.opacity); }, - rgb: function() { + rgb() { 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; @@ -3029,25 +3262,33 @@ hsl2rgb(h, m1, m2), hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2), this.opacity ); }, - displayable: function() { + clamp() { + return new Hsl(clamph(this.h), clampt(this.s), clampt(this.l), clampa(this.opacity)); + }, + displayable() { 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 + ")"); + formatHsl() { + const a = clampa(this.opacity); + return `${a === 1 ? "hsl(" : "hsla("}${clamph(this.h)}, ${clampt(this.s) * 100}%, ${clampt(this.l) * 100}%${a === 1 ? ")" : `, ${a})`}`; } })); +function clamph(value) { + value = (value || 0) % 360; + return value < 0 ? value + 360 : value; +} + +function clampt(value) { + return Math.max(0, Math.min(1, value || 0)); +} + /* 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 @@ -3096,17 +3337,17 @@ this.b = +b; this.opacity = +opacity; } define(Lab, lab$1, extend(Color, { - brighter: function(k) { + brighter(k) { return new Lab(this.l + K * (k == null ? 1 : k), this.a, this.b, this.opacity); }, - darker: function(k) { + darker(k) { return new Lab(this.l - K * (k == null ? 1 : k), this.a, this.b, this.opacity); }, - rgb: function() { + rgb() { var y = (this.l + 16) / 116, x = isNaN(this.a) ? y : y + this.a / 500, z = isNaN(this.b) ? y : y - this.b / 200; x = Xn * lab2xyz(x); y = Yn * lab2xyz(y); @@ -3164,17 +3405,17 @@ 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) { + brighter(k) { return new Hcl(this.h, this.c, this.l + K * (k == null ? 1 : k), this.opacity); }, - darker: function(k) { + darker(k) { return new Hcl(this.h, this.c, this.l - K * (k == null ? 1 : k), this.opacity); }, - rgb: function() { + rgb() { return hcl2lab(this).rgb(); } })); var A = -0.14861, @@ -3210,19 +3451,19 @@ this.l = +l; this.opacity = +opacity; } define(Cubehelix, cubehelix$3, extend(Color, { - brighter: function(k) { + brighter(k) { k = k == null ? brighter : Math.pow(brighter, k); return new Cubehelix(this.h, this.s, this.l * k, this.opacity); }, - darker: function(k) { + darker(k) { k = k == null ? darker : Math.pow(darker, k); return new Cubehelix(this.h, this.s, this.l * k, this.opacity); }, - rgb: function() { + rgb() { 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); @@ -5798,71 +6039,87 @@ 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 append$1(strings) { + this._ += strings[0]; + for (let i = 1, n = strings.length; i < n; ++i) { + this._ += arguments[i] + strings[i]; + } } -function path() { - return new Path$1; +function appendRound$1(digits) { + let d = Math.floor(digits); + if (!(d >= 0)) throw new Error(`invalid digits: ${digits}`); + if (d > 15) return append$1; + const k = 10 ** d; + return function(strings) { + this._ += strings[0]; + for (let i = 1, n = strings.length; i < n; ++i) { + this._ += Math.round(arguments[i] * k) / k + strings[i]; + } + }; } -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() { +let Path$1 = class Path { + constructor(digits) { + this._x0 = this._y0 = // start of current subpath + this._x1 = this._y1 = null; // end of current subpath + this._ = ""; + this._append = digits == null ? append$1 : appendRound$1(digits); + } + moveTo(x, y) { + this._append`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"; + this._append`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) { + } + lineTo(x, y) { + this._append`L${this._x1 = +x},${this._y1 = +y}`; + } + quadraticCurveTo(x1, y1, x, y) { + this._append`Q${+x1},${+y1},${this._x1 = +x},${this._y1 = +y}`; + } + bezierCurveTo(x1, y1, x2, y2, x, y) { + this._append`C${+x1},${+y1},${+x2},${+y2},${this._x1 = +x},${this._y1 = +y}`; + } + arcTo(x1, y1, x2, y2, r) { x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r; - var x0 = this._x1, + + // Is the radius negative? Error. + if (r < 0) throw new Error(`negative radius: ${r}`); + + let 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); + this._append`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); + this._append`L${this._x1 = x1},${this._y1 = y1}`; } // Otherwise, draw an arc! else { - var x20 = x2 - x0, + let 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), @@ -5870,62 +6127,74 @@ 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._append`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); + this._append`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) { + } + arc(x, y, r, a0, a1, ccw) { x = +x, y = +y, r = +r, ccw = !!ccw; - var dx = r * Math.cos(a0), + + // Is the radius negative? Error. + if (r < 0) throw new Error(`negative radius: ${r}`); + + let 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; + this._append`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; + this._append`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); + this._append`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)); + this._append`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() { + } + rect(x, y, w, h) { + this._append`M${this._x0 = this._x1 = +x},${this._y0 = this._y1 = +y}h${w = +w}v${+h}h${-w}Z`; + } + toString() { return this._; } }; +function path() { + return new Path$1; +} + +// Allow instanceof d3.path +path.prototype = Path$1.prototype; + +function pathRound(digits = 3) { + return new Path$1(+digits); +} + var slice$2 = Array.prototype.slice; function constant$6(x) { return function() { return x; @@ -6125,38 +6394,43 @@ [[[1.0, 1.5], [1.5, 1.0]]], [[[0.5, 1.0], [1.0, 1.5]]], [] ]; -function contours() { +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); + const e = extent$1(values, finite); + tz = ticks(...nice$1(e[0], e[1], tz), tz); + while (tz[tz.length - 1] >= e[1]) tz.pop(); + while (tz[1] < e[0]) tz.shift(); } 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) { + const v = value == null ? NaN : +value; + if (isNaN(v)) throw new Error(`invalid value: ${value}`); + var polygons = [], holes = []; - isorings(values, value, function(ring) { - smooth(ring, values, value); + isorings(values, v, function(ring) { + smooth(ring, values, v); if (area$3(ring) > 0) polygons.push([ring]); else holes.push(ring); }); holes.forEach(function(hole) { @@ -6182,38 +6456,38 @@ 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; + t1 = above(values[0], value); cases[t1 << 1].forEach(stitch); while (++x < dx - 1) { - t0 = t1, t1 = values[x + 1] >= value; + t0 = t1, t1 = above(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; + t1 = above(values[y * dx + dx], value); + t2 = above(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; + t0 = t1, t1 = above(values[y * dx + dx + x + 1], value); + t3 = t2, t2 = above(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; + t3 = t2, t2 = above(values[y * dx + x + 1], value); cases[t2 << 2 | t3 << 3].forEach(stitch); } cases[t2 << 3].forEach(stitch); function stitch(line) { @@ -6266,19 +6540,16 @@ ring.forEach(function(point) { var x = point[0], y = point[1], xt = x | 0, yt = y | 0, - v0, - v1 = values[yt * dx + xt]; + v1 = valid(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; + point[0] = smooth1(x, valid(values[yt * dx + xt - 1]), v1, value); } if (y > 0 && y < dy && yt === y) { - v0 = values[(yt - 1) * dx + xt]; - point[1] = y + (value - v0) / (v1 - v0) - 0.5; + point[1] = smooth1(y, valid(values[(yt - 1) * dx + xt]), v1, value); } }); } contours.contour = contour; @@ -6299,54 +6570,33 @@ }; 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); - } - } - } +// When computing the extent, ignore infinite values (as well as invalid ones). +function finite(x) { + return isFinite(x) ? x : NaN; } -// 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); - } - } - } +// Is the (possibly invalid) x greater than or equal to the (known valid) value? +// Treat any invalid value as below negative infinity. +function above(x, value) { + return x == null ? false : +x >= value; } +// During smoothing, treat any invalid value as negative infinity. +function valid(v) { + return v == null || isNaN(v = +v) ? -Infinity : v; +} + +function smooth1(x, v0, v1, value) { + const a = value - v0; + const b = v1 - v0; + const d = isFinite(a) || isFinite(b) ? a / b : Math.sign(a) / Math.sign(b); + return isNaN(d) ? x : x + d - 0.5; +} + function defaultX$1(d) { return d[0]; } function defaultY$1(d) { @@ -6368,58 +6618,67 @@ 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); + function grid(data) { + var values = new Float32Array(n * m), + pow2k = Math.pow(2, -k), + i = -1; - data.forEach(function(d, i, data) { - var xi = (x(d, i, data) + o) * pow2k, + for (const d of 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) { + if (wi && 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; + values[x0 + y0 * n] += (1 - xt) * (1 - yt) * wi; + values[x0 + 1 + y0 * n] += xt * (1 - yt) * wi; + values[x0 + 1 + (y0 + 1) * n] += xt * yt * wi; + values[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); + blur2({data: values, width: n, height: m}, r * pow2k); + return values; + } - var tz = threshold(values0); + function density(data) { + var values = grid(data), + tz = threshold(values), + pow4k = Math.pow(2, 2 * k); // Convert number of thresholds into uniform thresholds. if (!Array.isArray(tz)) { - var stop = max$3(values0); - tz = tickStep(0, stop, tz); - tz = sequence(0, Math.floor(stop / tz) * tz, tz); - tz.shift(); + tz = ticks(Number.MIN_VALUE, max$3(values) / pow4k, tz); } - return contours() - .thresholds(tz) + return Contours() .size([n, m]) - (values0) - .map(transform); + .thresholds(tz.map(d => d * pow4k)) + (values) + .map((c, i) => (c.value = +tz[i], transform(c))); } + density.contours = function(data) { + var values = grid(data), + contours = Contours().size([n, m]), + pow4k = Math.pow(2, 2 * k), + contour = value => { + value = +value; + var c = transform(contours.contour(values, value * pow4k)); + c.value = value; // preserve exact threshold value + return c; + }; + Object.defineProperty(contour, "max", {get: () => max$3(values) / pow4k}); + return contour; + }; + 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) { @@ -6473,11 +6732,11 @@ }; 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 r = (Math.sqrt(4 * _ * _ + 1) - 1) / 2, resize(); }; return density; } @@ -6739,12 +6998,10 @@ 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); } @@ -7300,10 +7557,11 @@ this._init(); return this; } _init() { const {delaunay: {points, hull, triangles}, vectors} = this; + let bx, by; // lazily computed barycenter of the hull // 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; @@ -7321,21 +7579,19 @@ 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); + // For a degenerate triangle, the circumcenter is at the infinity, in a + // direction orthogonal to the halfedge and away from the “center” of + // the diagram <bx, by>, defined as the hull’s barycenter. + if (bx === undefined) { + bx = by = 0; + for (const i of hull) bx += points[i * 2], by += points[i * 2 + 1]; + bx /= hull.length, by /= hull.length; + } + const a = 1e9 * Math.sign((bx - x1) * ey - (by - 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; @@ -7440,15 +7696,14 @@ 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] - ) { + 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; } } } @@ -7476,13 +7731,13 @@ } const points = this._cell(i); if (points === null) return null; const {vectors: V} = this; const v = i * 4; - return V[v] || V[v + 1] + return this._simplify(V[v] || V[v + 1] ? this._clipInfinite(i, points, V[v], V[v + 1], V[v + 2], V[v + 3]) - : this._clipFinite(i, points); + : 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]; @@ -7521,12 +7776,15 @@ 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) { + // for more robustness, always consider the segment in the same order + const flip = c0 < c1; + if (flip) [x0, y0, x1, y1, c0, c1] = [x1, y1, x0, y0, c1, c0]; while (true) { - if (c0 === 0 && c1 === 0) return [x0, y0, x1, y1]; + if (c0 === 0 && c1 === 0) return flip ? [x1, y1, x0, y0] : [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; @@ -7566,18 +7824,10 @@ // 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 @@ -7606,10 +7856,22 @@ return (x < this.xmin ? 0b0001 : x > this.xmax ? 0b0010 : 0b0000) | (y < this.ymin ? 0b0100 : y > this.ymax ? 0b1000 : 0b0000); } + _simplify(P) { + if (P && 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; + } + } + if (!P.length) P = null; + } + return P; + } } const tau$2 = 2 * Math.PI, pow$2 = Math.pow; function pointX(p) { @@ -8807,17 +9069,17 @@ 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 +const a$2 = 1664525; +const c$4 = 1013904223; +const m$1 = 4294967296; // 2^32 -function lcg$1() { +function lcg$2() { let s = 1; - return () => (s = (a$1 * s + c$3) % m) / m; + return () => (s = (a$2 * s + c$4) % m$1) / m$1; } function x$2(d) { return d.x; } @@ -8837,11 +9099,11 @@ alphaTarget = 0, velocityDecay = 0.6, forces = new Map(), stepper = timer(step), event = dispatch("tick", "end"), - random = lcg$1(); + random = lcg$2(); if (nodes == null) nodes = []; function step() { tick(); @@ -9375,20 +9637,20 @@ 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"]; + prefixes = ["y","z","a","f","p","n","µ","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 + "", + minus = locale.minus === undefined ? "−" : locale.minus + "", nan = locale.nan === undefined ? "NaN" : locale.nan + ""; function newFormat(specifier) { specifier = formatSpecifier(specifier); @@ -9764,26 +10026,26 @@ p0, // previous 3D point deltaSum, ranges, range; -var boundsStream$1 = { +var boundsStream$2 = { point: boundsPoint$1, lineStart: boundsLineStart, lineEnd: boundsLineEnd, polygonStart: function() { - boundsStream$1.point = boundsRingPoint; - boundsStream$1.lineStart = boundsRingStart; - boundsStream$1.lineEnd = boundsRingEnd; + boundsStream$2.point = boundsRingPoint; + boundsStream$2.lineStart = boundsRingStart; + boundsStream$2.lineEnd = boundsRingEnd; deltaSum = new Adder(); areaStream$1.polygonStart(); }, polygonEnd: function() { areaStream$1.polygonEnd(); - boundsStream$1.point = boundsPoint$1; - boundsStream$1.lineStart = boundsLineStart; - boundsStream$1.lineEnd = boundsLineEnd; + 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; }, @@ -9846,16 +10108,16 @@ if (phi > phi1) phi1 = phi; p0 = p, lambda2 = lambda; } function boundsLineStart() { - boundsStream$1.point = linePoint; + boundsStream$2.point = linePoint; } function boundsLineEnd() { range[0] = lambda0$1, range[1] = lambda1; - boundsStream$1.point = boundsPoint$1; + boundsStream$2.point = boundsPoint$1; p0 = null; } function boundsRingPoint(lambda, phi) { if (p0) { @@ -9898,11 +10160,11 @@ function bounds(feature) { var i, n, a, b, merged, deltaMax, delta; phi1 = lambda1 = -(lambda0$1 = phi0 = Infinity); ranges = []; - geoStream(feature, boundsStream$1); + geoStream(feature, boundsStream$2); // First, sort ranges by their minimum longitudes. if (n = ranges.length) { ranges.sort(rangeCompare); @@ -10089,11 +10351,12 @@ return compose; } function rotationIdentity(lambda, phi) { - return [abs$1(lambda) > pi$1 ? lambda + Math.round(-lambda / tau$1) * tau$1 : lambda, phi]; + if (abs$1(lambda) > pi$1) lambda -= Math.round(lambda / tau$1) * tau$1; + return [lambda, phi]; } rotationIdentity.invert = rotationIdentity; function rotateRadians(deltaLambda, deltaPhi, deltaGamma) { @@ -10103,11 +10366,13 @@ : 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]; + lambda += deltaLambda; + if (abs$1(lambda) > pi$1) lambda -= Math.round(lambda / tau$1) * tau$1; + return [lambda, phi]; }; } function rotationLambda(deltaLambda) { var rotation = forwardRotationLambda(deltaLambda); @@ -10190,11 +10455,11 @@ cartesianNormalizeInPlace(point); var radius = acos$1(-point[1]); return ((-point[2] < 0 ? -radius : radius) + tau$1 - epsilon$1) % tau$1; } -function circle$2() { +function circle$1() { var center = constant$3([0, 0]), radius = constant$3(90), precision = constant$3(6), ring, rotate, @@ -11212,16 +11477,16 @@ ? containsObjectType[object.type] : containsGeometry)(object, point); } function graticuleX(y0, y1, dy) { - var y = sequence(y0, y1 - epsilon$1, dy).concat(y1); + 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 = sequence(x0, x1 - epsilon$1, dx).concat(x1); + 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, @@ -11233,14 +11498,14 @@ function graticule() { return {type: "MultiLineString", coordinates: lines()}; } function lines() { - return sequence(ceil(X0 / DX) * DX, X1, DX).map(X) - .concat(sequence(ceil(Y0 / DY) * DY, Y1, DY).map(Y)) - .concat(sequence(ceil(x0 / dx) * dx, x1, dx).filter(function(x) { return abs$1(x % DX) > epsilon$1; }).map(x)) - .concat(sequence(ceil(y0 / dy) * dy, y1, dy).filter(function(y) { return abs$1(y % DY) > epsilon$1; }).map(y)); + 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}; }); }; @@ -11396,10 +11661,12 @@ function areaRingEnd() { areaPoint(x00$2, y00$2); } +var pathArea = areaStream; + var x0$2 = Infinity, y0$2 = x0$2, x1 = -x0$2, y1 = x1; @@ -11421,10 +11688,12 @@ 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, @@ -11518,10 +11787,12 @@ 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 = { @@ -11601,72 +11872,102 @@ x0 -= x, y0 -= y; lengthSum.add(sqrt$2(x0 * x0 + y0 * y0)); x0 = x, y0 = y; } -function PathString() { - this._string = []; -} +var pathMeasure = lengthStream; -PathString.prototype = { - _radius: 4.5, - _circle: circle$1(4.5), - pointRadius: function(_) { - if ((_ = +_) !== this._radius) this._radius = _, this._circle = null; +// Simple caching for constant-radius points. +let cacheDigits, cacheAppend, cacheRadius, cacheCircle; + +class PathString { + constructor(digits) { + this._append = digits == null ? append : appendRound(digits); + this._radius = 4.5; + this._ = ""; + } + pointRadius(_) { + this._radius = +_; return this; - }, - polygonStart: function() { + } + polygonStart() { this._line = 0; - }, - polygonEnd: function() { + } + polygonEnd() { this._line = NaN; - }, - lineStart: function() { + } + lineStart() { this._point = 0; - }, - lineEnd: function() { - if (this._line === 0) this._string.push("Z"); + } + lineEnd() { + if (this._line === 0) this._ += "Z"; this._point = NaN; - }, - point: function(x, y) { + } + point(x, y) { switch (this._point) { case 0: { - this._string.push("M", x, ",", y); + this._append`M${x},${y}`; this._point = 1; break; } case 1: { - this._string.push("L", x, ",", y); + this._append`L${x},${y}`; break; } default: { - if (this._circle == null) this._circle = circle$1(this._radius); - this._string.push("M", x, ",", y, this._circle); + this._append`M${x},${y}`; + if (this._radius !== cacheRadius || this._append !== cacheAppend) { + const r = this._radius; + const s = this._; + this._ = ""; // stash the old string so we can cache the circle path fragment + this._append`m0,${r}a${r},${r} 0 1,1 0,${-2 * r}a${r},${r} 0 1,1 0,${2 * r}z`; + cacheRadius = r; + cacheAppend = this._append; + cacheCircle = this._; + this._ = s; + } + this._ += cacheCircle; break; } } - }, - result: function() { - if (this._string.length) { - var result = this._string.join(""); - this._string = []; - return result; - } else { - return null; - } } -}; + result() { + const result = this._; + this._ = ""; + return result.length ? result : 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 append(strings) { + let i = 1; + this._ += strings[0]; + for (const j = strings.length; i < j; ++i) { + this._ += arguments[i] + strings[i]; + } } +function appendRound(digits) { + const d = Math.floor(digits); + if (!(d >= 0)) throw new RangeError(`invalid digits: ${digits}`); + if (d > 15) return append; + if (d !== cacheDigits) { + const k = 10 ** d; + cacheDigits = d; + cacheAppend = function append(strings) { + let i = 1; + this._ += strings[0]; + for (const j = strings.length; i < j; ++i) { + this._ += Math.round(arguments[i] * k) / k + strings[i]; + } + }; + } + return cacheAppend; +} + function index$2(projection, context) { - var pointRadius = 4.5, + let digits = 3, + pointRadius = 4.5, projectionStream, contextStream; function path(object) { if (object) { @@ -11675,47 +11976,61 @@ } return contextStream.result(); } path.area = function(object) { - geoStream(object, projectionStream(areaStream)); - return areaStream.result(); + geoStream(object, projectionStream(pathArea)); + return pathArea.result(); }; path.measure = function(object) { - geoStream(object, projectionStream(lengthStream)); - return lengthStream.result(); + geoStream(object, projectionStream(pathMeasure)); + return pathMeasure.result(); }; path.bounds = function(object) { - geoStream(object, projectionStream(boundsStream)); - return boundsStream.result(); + geoStream(object, projectionStream(boundsStream$1)); + return boundsStream$1.result(); }; path.centroid = function(object) { - geoStream(object, projectionStream(centroidStream)); - return centroidStream.result(); + geoStream(object, projectionStream(pathCentroid)); + return pathCentroid.result(); }; path.projection = function(_) { - return arguments.length ? (projectionStream = _ == null ? (projection = null, identity$5) : (projection = _).stream, path) : projection; + if (!arguments.length) return projection; + projectionStream = _ == null ? (projection = null, identity$5) : (projection = _).stream; + return path; }; path.context = function(_) { if (!arguments.length) return context; - contextStream = _ == null ? (context = null, new PathString) : new PathContext(context = _); + contextStream = _ == null ? (context = null, new PathString(digits)) : 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); + path.digits = function(_) { + if (!arguments.length) return digits; + if (_ == null) digits = null; + else { + const d = Math.floor(_); + if (!(d >= 0)) throw new RangeError(`invalid digits: ${_}`); + digits = d; + } + if (context === null) contextStream = new PathString(digits); + return path; + }; + + return path.projection(projection).digits(digits).context(context); } function transform$1(methods) { return { stream: transformer$3(methods) @@ -11745,12 +12060,12 @@ 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)); - fitBounds(boundsStream.result()); + geoStream(object, projection.stream(boundsStream$1)); + fitBounds(boundsStream$1.result()); if (clip != null) projection.clipExtent(clip); return projection; } function fitExtent(projection, extent, object) { @@ -12926,34 +13241,67 @@ links: node_links, copy: node_copy, [Symbol.iterator]: node_iterator }; +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; + }; +} + +// 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 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, +function shuffle(array, random) { + let m = array.length, t, i; while (m) { - i = Math.random() * m-- | 0; + i = 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; + return packEncloseRandom(circles, lcg$1()); +} +function packEncloseRandom(circles, random) { + var i = 0, n = (circles = shuffle(Array.from(circles), random)).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; } @@ -13056,11 +13404,11 @@ 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); + r = -(Math.abs(A) > 1e-6 ? (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 }; @@ -13108,11 +13456,11 @@ this._ = circle; this.next = null; this.previous = null; } -function packEnclose(circles) { +function packSiblingsRandom(circles, random) { 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. @@ -13168,42 +13516,23 @@ } 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); + a = [b._], c = b; while ((c = c.next) !== b) a.push(c._); c = packEncloseRandom(a, random); // 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); + packSiblingsRandom(circles, lcg$1()); 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() { @@ -13211,19 +13540,20 @@ dx = 1, dy = 1, padding = constantZero; function pack(root) { + const random = lcg$1(); root.x = dx / 2, root.y = dy / 2; if (radius) { root.eachBefore(radiusLeaf(radius)) - .eachAfter(packChildren(padding, 0.5)) + .eachAfter(packChildrenRandom(padding, 0.5, random)) .eachBefore(translateChild(1)); } else { root.eachBefore(radiusLeaf(defaultRadius)) - .eachAfter(packChildren(constantZero, 1)) - .eachAfter(packChildren(padding, root.r / Math.min(dx, dy))) + .eachAfter(packChildrenRandom(constantZero, 1, random)) + .eachAfter(packChildrenRandom(padding, root.r / Math.min(dx, dy), random)) .eachBefore(translateChild(Math.min(dx, dy) / (2 * root.r))); } return root; } @@ -13248,21 +13578,21 @@ node.r = Math.max(0, +radius(node) || 0); } }; } -function packChildren(padding, k) { +function packChildrenRandom(padding, k, random) { 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); + e = packSiblingsRandom(children, random); if (r) for (i = 0; i < n; ++i) children[i].r -= r; node.r = e + r; } }; } @@ -13347,11 +13677,12 @@ return partition; } var preroot = {depth: -1}, - ambiguous = {}; + ambiguous = {}, + imputed = {}; function defaultId(d) { return d.id; } @@ -13359,31 +13690,50 @@ return d.parentId; } function stratify() { var id = defaultId, - parentId = defaultParentId; + parentId = defaultParentId, + path; function stratify(data) { var nodes = Array.from(data), - n = nodes.length, + currentId = id, + currentParentId = parentId, + n, d, i, root, parent, node, nodeId, nodeKey, nodeByKey = new Map; - for (i = 0; i < n; ++i) { + if (path != null) { + const I = nodes.map((d, i) => normalize$1(path(d, i, data))); + const P = I.map(parentof); + const S = new Set(I).add(""); + for (const i of P) { + if (!S.has(i)) { + S.add(i); + I.push(i); + P.push(parentof(i)); + nodes.push(imputed); + } + } + currentId = (_, i) => I[i]; + currentParentId = (_, i) => P[i]; + } + + for (i = 0, n = nodes.length; i < n; ++i) { d = nodes[i], node = nodes[i] = new Node$1(d); - if ((nodeId = id(d, i, data)) != null && (nodeId += "")) { + if ((nodeId = currentId(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 += "")) { + if ((nodeId = currentParentId(d, i, data)) != null && (nodeId += "")) { node.parent = nodeId; } } for (i = 0; i < n; ++i) { @@ -13400,29 +13750,79 @@ root = node; } } if (!root) throw new Error("no root"); + + // When imputing internal nodes, only introduce roots if needed. + // Then replace the imputed marker data with null. + if (path != null) { + while (root.data === imputed && root.children.length === 1) { + root = root.children[0], --n; + } + for (let i = nodes.length - 1; i >= 0; --i) { + node = nodes[i]; + if (node.data !== imputed) break; + node.data = null; + } + } + 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; + return arguments.length ? (id = optional(x), stratify) : id; }; stratify.parentId = function(x) { - return arguments.length ? (parentId = required(x), stratify) : parentId; + return arguments.length ? (parentId = optional(x), stratify) : parentId; }; + stratify.path = function(x) { + return arguments.length ? (path = optional(x), stratify) : path; + }; + return stratify; } +// To normalize a path, we coerce to a string, strip the trailing slash if any +// (as long as the trailing slash is not immediately preceded by another slash), +// and add leading slash if missing. +function normalize$1(path) { + path = `${path}`; + let i = path.length; + if (slash(path, i - 1) && !slash(path, i - 2)) path = path.slice(0, -1); + return path[0] === "/" ? path : `/${path}`; +} + +// Walk backwards to find the first slash that is not the leading slash, e.g.: +// "/foo/bar" ⇥ "/foo", "/foo" ⇥ "/", "/" ↦ "". (The root is special-cased +// because the id of the root must be a truthy value.) +function parentof(path) { + let i = path.length; + if (i < 2) return ""; + while (--i > 1) if (slash(path, i)) break; + return path.slice(0, i); +} + +// Slashes can be escaped; to determine whether a slash is a path delimiter, we +// count the number of preceding backslashes escaping the forward slash: an odd +// number indicates an escaped forward slash. +function slash(path, i) { + if (path[i] === "/") { + let k = 0; + while (i > 0 && path[--i] === "\\") ++k; + if ((k & 1) === 0) return true; + } + return false; +} + function defaultSeparation(a, b) { return a.parent === b.parent ? 1 : 2; } // function radialSeparation(a, b) { @@ -14465,11 +14865,11 @@ 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 = sequence(n).map(function(i) { return start + step * i; }); + 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(); @@ -14593,11 +14993,11 @@ d[i] = normalize(domain[i], domain[i + 1]); r[i] = interpolate(range[i], range[i + 1]); } return function(x) { - var i = bisectRight(domain, x, 1, j) - 1; + var i = bisect(domain, x, 1, j) - 1; return r[i](d[i](x)); }; } function copy$1(source, target) { @@ -14830,32 +15230,30 @@ } function powp(base) { return base === 10 ? pow10 : base === Math.E ? Math.exp - : function(x) { return Math.pow(base, x); }; + : 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), function(x) { return Math.log(x) / base; }); + || (base = Math.log(base), x => Math.log(x) / base); } function reflect(f) { - return function(x) { - return -f(-x); - }; + return (x, k) => -f(-x, k); } function loggish(transform) { - var scale = transform(transformLog, transformExp), - domain = scale.domain, - base = 10, - logs, - pows; + 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); @@ -14872,83 +15270,79 @@ scale.domain = function(_) { return arguments.length ? (domain(_), rescale()) : domain(); }; - scale.ticks = function(count) { - var d = domain(), - u = d[0], - v = d[d.length - 1], - r; + scale.ticks = count => { + const d = domain(); + let u = d[0]; + let v = d[d.length - 1]; + const r = v < u; - if (r = v < u) i = u, u = v, v = i; + if (r) ([u, v] = [v, u]); - var i = logs(u), - j = logs(v), - p, - k, - t, - n = count == null ? 10 : +count, - z = []; + 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, p = pows(i); k < base; ++k) { - t = p * k; + 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, p = pows(i); k >= 1; --k) { - t = p * k; + 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 = function(count, specifier) { - if (specifier == null) specifier = base === 10 ? ".0e" : ","; - if (typeof specifier !== "function") specifier = exports.format(specifier); - if (count === Infinity) return specifier; + scale.tickFormat = (count, specifier) => { if (count == null) count = 10; - var k = Math.max(1, base * count / scale.ticks().length); // TODO fast estimate? - return function(d) { - var i = d / pows(Math.round(logs(d))); + 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 = function() { + scale.nice = () => { return domain(nice(domain(), { - floor: function(x) { return pows(Math.floor(logs(x))); }, - ceil: function(x) { return pows(Math.ceil(logs(x))); } + floor: x => pows(Math.floor(logs(x))), + ceil: x => pows(Math.ceil(logs(x))) })); }; return scale; } function log() { - var scale = loggish(transformer$2()).domain([1, 10]); - - scale.copy = function() { - return copy$1(scale, log()).base(scale.base()); - }; - + 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) { @@ -15100,11 +15494,11 @@ while (++i < n) thresholds[i - 1] = quantileSorted(domain, i / n); return scale; } function scale(x) { - return x == null || isNaN(x = +x) ? unknown : range[bisectRight(thresholds, 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] : [ @@ -15150,11 +15544,11 @@ domain = [0.5], range = [0, 1], unknown; function scale(x) { - return x != null && x <= x ? range[bisectRight(domain, x, 0, n)] : unknown; + return x != null && x <= x ? range[bisect(domain, x, 0, n)] : unknown; } function rescale() { var i = -1; domain = new Array(n); @@ -15201,11 +15595,11 @@ range = [0, 1], unknown, n = 1; function scale(x) { - return x != null && x <= x ? range[bisectRight(domain, x, 0, n)] : unknown; + 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(); }; @@ -15231,51 +15625,50 @@ }; return initRange.apply(scale, arguments); } -var t0 = new Date, - t1 = new Date; +const t0 = new Date, t1 = new Date; -function newInterval(floori, offseti, count, field) { +function timeInterval(floori, offseti, count, field) { function interval(date) { return floori(date = arguments.length === 0 ? new Date : new Date(+date)), date; } - interval.floor = function(date) { + interval.floor = (date) => { return floori(date = new Date(+date)), date; }; - interval.ceil = function(date) { + interval.ceil = (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); + interval.round = (date) => { + const d0 = interval(date), d1 = interval.ceil(date); return date - d0 < d1 - date ? d0 : d1; }; - interval.offset = function(date, step) { + interval.offset = (date, step) => { return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date; }; - interval.range = function(start, stop, step) { - var range = [], previous; + interval.range = (start, stop, step) => { + const range = []; start = interval.ceil(start); step = step == null ? 1 : Math.floor(step); if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date + let previous; do range.push(previous = new Date(+start)), offseti(start, step), floori(start); while (previous < start && start < stop); return range; }; - interval.filter = function(test) { - return newInterval(function(date) { + interval.filter = (test) => { + return timeInterval((date) => { if (date >= date) while (floori(date), !test(date)) date.setTime(date - 1); - }, function(date, step) { + }, (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 @@ -15283,258 +15676,282 @@ } }); }; if (count) { - interval.count = function(start, end) { + interval.count = (start, end) => { t0.setTime(+start), t1.setTime(+end); floori(t0), floori(t1); return Math.floor(count(t0, t1)); }; - interval.every = function(step) { + interval.every = (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; }); + ? (d) => field(d) % step === 0 + : (d) => interval.count(0, d) % step === 0); }; } return interval; } -var millisecond = newInterval(function() { +const millisecond = timeInterval(() => { // noop -}, function(date, step) { +}, (date, step) => { date.setTime(+date + step); -}, function(start, end) { +}, (start, end) => { return end - start; }); // An optimized implementation for this simple case. -millisecond.every = function(k) { +millisecond.every = (k) => { k = Math.floor(k); if (!isFinite(k) || !(k > 0)) return null; if (!(k > 1)) return millisecond; - return newInterval(function(date) { + return timeInterval((date) => { date.setTime(Math.floor(date / k) * k); - }, function(date, step) { + }, (date, step) => { date.setTime(+date + step * k); - }, function(start, end) { + }, (start, end) => { return (end - start) / k; }); }; -var milliseconds = millisecond.range; +const milliseconds = millisecond.range; + const durationSecond = 1000; const durationMinute = durationSecond * 60; const durationHour = durationMinute * 60; const durationDay = durationHour * 24; const durationWeek = durationDay * 7; const durationMonth = durationDay * 30; const durationYear = durationDay * 365; -var second = newInterval(function(date) { +const second = timeInterval((date) => { date.setTime(date - date.getMilliseconds()); -}, function(date, step) { +}, (date, step) => { date.setTime(+date + step * durationSecond); -}, function(start, end) { +}, (start, end) => { return (end - start) / durationSecond; -}, function(date) { +}, (date) => { return date.getUTCSeconds(); }); -var seconds = second.range; -var minute = newInterval(function(date) { +const seconds = second.range; + +const timeMinute = timeInterval((date) => { date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond); -}, function(date, step) { +}, (date, step) => { date.setTime(+date + step * durationMinute); -}, function(start, end) { +}, (start, end) => { return (end - start) / durationMinute; -}, function(date) { +}, (date) => { return date.getMinutes(); }); -var minutes = minute.range; -var hour = newInterval(function(date) { +const timeMinutes = timeMinute.range; + +const utcMinute = timeInterval((date) => { + date.setUTCSeconds(0, 0); +}, (date, step) => { + date.setTime(+date + step * durationMinute); +}, (start, end) => { + return (end - start) / durationMinute; +}, (date) => { + return date.getUTCMinutes(); +}); + +const utcMinutes = utcMinute.range; + +const timeHour = timeInterval((date) => { date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond - date.getMinutes() * durationMinute); -}, function(date, step) { +}, (date, step) => { date.setTime(+date + step * durationHour); -}, function(start, end) { +}, (start, end) => { return (end - start) / durationHour; -}, function(date) { +}, (date) => { return date.getHours(); }); -var hours = hour.range; -var day = newInterval( +const timeHours = timeHour.range; + +const utcHour = timeInterval((date) => { + date.setUTCMinutes(0, 0, 0); +}, (date, step) => { + date.setTime(+date + step * durationHour); +}, (start, end) => { + return (end - start) / durationHour; +}, (date) => { + return date.getUTCHours(); +}); + +const utcHours = utcHour.range; + +const timeDay = timeInterval( date => date.setHours(0, 0, 0, 0), (date, step) => date.setDate(date.getDate() + step), (start, end) => (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationDay, date => date.getDate() - 1 ); -var days = day.range; -function weekday(i) { - return newInterval(function(date) { +const timeDays = timeDay.range; + +const utcDay = timeInterval((date) => { + date.setUTCHours(0, 0, 0, 0); +}, (date, step) => { + date.setUTCDate(date.getUTCDate() + step); +}, (start, end) => { + return (end - start) / durationDay; +}, (date) => { + return date.getUTCDate() - 1; +}); + +const utcDays = utcDay.range; + +const unixDay = timeInterval((date) => { + date.setUTCHours(0, 0, 0, 0); +}, (date, step) => { + date.setUTCDate(date.getUTCDate() + step); +}, (start, end) => { + return (end - start) / durationDay; +}, (date) => { + return Math.floor(date / durationDay); +}); + +const unixDays = unixDay.range; + +function timeWeekday(i) { + return timeInterval((date) => { date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7); date.setHours(0, 0, 0, 0); - }, function(date, step) { + }, (date, step) => { date.setDate(date.getDate() + step * 7); - }, function(start, end) { + }, (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); +const timeSunday = timeWeekday(0); +const timeMonday = timeWeekday(1); +const timeTuesday = timeWeekday(2); +const timeWednesday = timeWeekday(3); +const timeThursday = timeWeekday(4); +const timeFriday = timeWeekday(5); +const timeSaturday = timeWeekday(6); -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; +const timeSundays = timeSunday.range; +const timeMondays = timeMonday.range; +const timeTuesdays = timeTuesday.range; +const timeWednesdays = timeWednesday.range; +const timeThursdays = timeThursday.range; +const timeFridays = timeFriday.range; +const timeSaturdays = timeSaturday.range; -var month = newInterval(function(date) { +function utcWeekday(i) { + return timeInterval((date) => { + date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7); + date.setUTCHours(0, 0, 0, 0); + }, (date, step) => { + date.setUTCDate(date.getUTCDate() + step * 7); + }, (start, end) => { + return (end - start) / durationWeek; + }); +} + +const utcSunday = utcWeekday(0); +const utcMonday = utcWeekday(1); +const utcTuesday = utcWeekday(2); +const utcWednesday = utcWeekday(3); +const utcThursday = utcWeekday(4); +const utcFriday = utcWeekday(5); +const utcSaturday = utcWeekday(6); + +const utcSundays = utcSunday.range; +const utcMondays = utcMonday.range; +const utcTuesdays = utcTuesday.range; +const utcWednesdays = utcWednesday.range; +const utcThursdays = utcThursday.range; +const utcFridays = utcFriday.range; +const utcSaturdays = utcSaturday.range; + +const timeMonth = timeInterval((date) => { date.setDate(1); date.setHours(0, 0, 0, 0); -}, function(date, step) { +}, (date, step) => { date.setMonth(date.getMonth() + step); -}, function(start, end) { +}, (start, end) => { return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12; -}, function(date) { +}, (date) => { return date.getMonth(); }); -var months = month.range; -var year = newInterval(function(date) { +const timeMonths = timeMonth.range; + +const utcMonth = timeInterval((date) => { + date.setUTCDate(1); + date.setUTCHours(0, 0, 0, 0); +}, (date, step) => { + date.setUTCMonth(date.getUTCMonth() + step); +}, (start, end) => { + return end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12; +}, (date) => { + return date.getUTCMonth(); +}); + +const utcMonths = utcMonth.range; + +const timeYear = timeInterval((date) => { date.setMonth(0, 1); date.setHours(0, 0, 0, 0); -}, function(date, step) { +}, (date, step) => { date.setFullYear(date.getFullYear() + step); -}, function(start, end) { +}, (start, end) => { return end.getFullYear() - start.getFullYear(); -}, function(date) { +}, (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) { +timeYear.every = (k) => { + return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : timeInterval((date) => { date.setFullYear(Math.floor(date.getFullYear() / k) * k); date.setMonth(0, 1); date.setHours(0, 0, 0, 0); - }, function(date, step) { + }, (date, step) => { date.setFullYear(date.getFullYear() + step * k); }); }; -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 utcMinutes = utcMinute.range; +const timeYears = timeYear.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 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 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 utcMonths = utcMonth.range; - -var utcYear = newInterval(function(date) { +const utcYear = timeInterval((date) => { date.setUTCMonth(0, 1); date.setUTCHours(0, 0, 0, 0); -}, function(date, step) { +}, (date, step) => { date.setUTCFullYear(date.getUTCFullYear() + step); -}, function(start, end) { +}, (start, end) => { return end.getUTCFullYear() - start.getUTCFullYear(); -}, function(date) { +}, (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) { +utcYear.every = (k) => { + return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : timeInterval((date) => { date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k); date.setUTCMonth(0, 1); date.setUTCHours(0, 0, 0, 0); - }, function(date, step) { + }, (date, step) => { date.setUTCFullYear(date.getUTCFullYear() + step * k); }); }; -var utcYears = utcYear.range; +const utcYears = utcYear.range; + function ticker(year, month, week, day, hour, minute) { const tickIntervals = [ [second, 1, durationSecond], [second, 5, 5 * durationSecond], @@ -15574,12 +15991,12 @@ } return [ticks, tickInterval]; } -const [utcTicks, utcTickInterval] = ticker(utcYear, utcMonth, utcSunday, utcDay, utcHour, utcMinute); -const [timeTicks, timeTickInterval] = ticker(year, month, sunday, day, hour, minute); +const [utcTicks, utcTickInterval] = ticker(utcYear, utcMonth, utcSunday, unixDay, utcHour, utcMinute); +const [timeTicks, timeTickInterval] = ticker(timeYear, timeMonth, timeSunday, 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); @@ -15765,11 +16182,11 @@ function newParse(specifier, Z) { return function(string) { var d = newDate(1900, undefined, 1), i = parseSpecifier(d, specifier, string += "", 0), - week, day$1; + 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)); @@ -15786,29 +16203,29 @@ // 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$1 = week.getUTCDay(); - week = day$1 > 4 || day$1 === 0 ? utcMonday.ceil(week) : utcMonday(week); + week = utcDate(newDate(d.y, 0, 1)), day = week.getUTCDay(); + week = day > 4 || day === 0 ? utcMonday.ceil(week) : utcMonday(week); week = utcDay.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$1 = week.getDay(); - week = day$1 > 4 || day$1 === 0 ? monday.ceil(week) : monday(week); - week = day.offset(week, (d.V - 1) * 7); + week = localDate(newDate(d.y, 0, 1)), day = week.getDay(); + week = day > 4 || day === 0 ? timeMonday.ceil(week) : timeMonday(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$1 = "Z" in d ? utcDate(newDate(d.y, 0, 1)).getUTCDay() : localDate(newDate(d.y, 0, 1)).getDay(); + 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$1 + 5) % 7 : d.w + d.U * 7 - (day$1 + 6) % 7; + 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) { @@ -16088,11 +16505,11 @@ function formatHour12(d, p) { return pad(d.getHours() % 12 || 12, p, 2); } function formatDayOfYear(d, p) { - return pad(1 + day.count(year(d), d), p, 3); + return pad(1 + timeDay.count(timeYear(d), d), p, 3); } function formatMilliseconds(d, p) { return pad(d.getMilliseconds(), p, 3); } @@ -16117,29 +16534,29 @@ var day = d.getDay(); return day === 0 ? 7 : day; } function formatWeekNumberSunday(d, p) { - return pad(sunday.count(year(d) - 1, d), p, 2); + return pad(timeSunday.count(timeYear(d) - 1, d), p, 2); } function dISO(d) { var day = d.getDay(); - return (day >= 4 || day === 0) ? thursday(d) : thursday.ceil(d); + return (day >= 4 || day === 0) ? timeThursday(d) : timeThursday.ceil(d); } function formatWeekNumberISO(d, p) { d = dISO(d); - return pad(thursday.count(year(d), d) + (year(d).getDay() === 4), p, 2); + return pad(timeThursday.count(timeYear(d), d) + (timeYear(d).getDay() === 4), p, 2); } function formatWeekdayNumberSunday(d) { return d.getDay(); } function formatWeekNumberMonday(d, p) { - return pad(monday.count(year(d) - 1, d), p, 2); + return pad(timeMonday.count(timeYear(d) - 1, d), p, 2); } function formatYear(d, p) { return pad(d.getFullYear() % 100, p, 2); } @@ -16153,11 +16570,11 @@ 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); + d = (day >= 4 || day === 0) ? timeThursday(d) : timeThursday.ceil(d); return pad(d.getFullYear() % 10000, p, 4); } function formatZone(d) { var z = d.getTimezoneOffset(); @@ -16298,19 +16715,23 @@ 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) { @@ -16370,11 +16791,11 @@ return scale; } function time() { - return initRange.apply(calendar(timeTicks, timeTickInterval, year, month, sunday, day, hour, minute, second, exports.timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]), arguments); + return initRange.apply(calendar(timeTicks, timeTickInterval, timeYear, timeMonth, timeSunday, timeDay, timeHour, timeMinute, second, exports.timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]), arguments); } function utcTime() { return initRange.apply(calendar(utcTicks, utcTickInterval, utcYear, utcMonth, utcSunday, utcDay, utcHour, utcMinute, second, exports.utcFormat).domain([Date.UTC(2000, 0, 1), Date.UTC(2000, 0, 2)]), arguments); } @@ -16482,11 +16903,11 @@ function sequentialQuantile() { var domain = [], interpolator = identity$3; function scale(x) { - if (x != null && !isNaN(x = +x)) return interpolator((bisectRight(domain, x, 1) - 1) / (domain.length - 1)); + 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 = []; @@ -17047,31 +17468,49 @@ 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; +const abs = Math.abs; +const atan2 = Math.atan2; +const cos = Math.cos; +const max = Math.max; +const min = Math.min; +const sin = Math.sin; +const sqrt = Math.sqrt; -var epsilon = 1e-12; -var pi = Math.PI; -var halfPi = pi / 2; -var tau = 2 * pi; +const epsilon = 1e-12; +const pi = Math.PI; +const halfPi = pi / 2; +const tau = 2 * pi; function acos(x) { return x > 1 ? 0 : x < -1 ? pi : Math.acos(x); } function asin(x) { return x >= 1 ? halfPi : x <= -1 ? -halfPi : Math.asin(x); } +function withPath(shape) { + let digits = 3; + + shape.digits = function(_) { + if (!arguments.length) return digits; + if (_ == null) { + digits = null; + } else { + const d = Math.floor(_); + if (!(d >= 0)) throw new RangeError(`invalid digits: ${_}`); + digits = d; + } + return shape; + }; + + return () => new Path$1(digits); +} + function arcInnerRadius(d) { return d.innerRadius; } function arcOuterRadius(d) { @@ -17148,11 +17587,12 @@ cornerRadius = constant$1(0), padRadius = null, startAngle = arcStartAngle, endAngle = arcEndAngle, padAngle = arcPadAngle, - context = null; + context = null, + path = withPath(arc); function arc() { var buffer, r, r0 = +innerRadius.apply(this, arguments), @@ -17217,20 +17657,26 @@ 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)); + // Restrict the corner radius according to the sector angle. If this + // intersection fails, it’s probably because the arc is too small, so + // disable the corner radius entirely. + if (da < pi) { + if (oc = intersect(x01, y01, x00, y00, x11, y11, x10, y10)) { + var ax = x01 - oc[0], + ay = y01 - oc[1], + bx = x11 - oc[0], + by = y11 - oc[1], + kc = 1 / sin(acos((ax * bx + ay * by) / (sqrt(ax * ax + ay * ay) * sqrt(bx * bx + by * by))) / 2), + lc = sqrt(oc[0] * oc[0] + oc[1] * oc[1]); + rc0 = min(rc, (r0 - lc) / (kc - 1)); + rc1 = min(rc, (r1 - lc) / (kc + 1)); + } else { + rc0 = rc1 = 0; + } } } // Is the sector collapsed to a line? if (!(da1 > epsilon)) context.moveTo(x01, y01); @@ -17378,11 +17824,12 @@ function line(x$1, y$1) { var defined = constant$1(true), context = null, curve = curveLinear, - output = null; + output = null, + path = withPath(line); 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) { @@ -17431,11 +17878,12 @@ function area(x0, y0, y1) { var x1 = null, defined = constant$1(true), context = null, curve = curveLinear, - output = null; + output = null, + path = withPath(area); 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); @@ -17614,11 +18062,11 @@ }; return pie; } -var curveRadialLinear = curveRadial$1(curveLinear); +var curveRadialLinear = curveRadial(curveLinear); function Radial(curve) { this._curve = curve; } @@ -17638,11 +18086,11 @@ point: function(a, r) { this._curve.point(r * Math.sin(a), r * -Math.cos(a)); } }; -function curveRadial$1(curve) { +function curveRadial(curve) { function radial(context) { return new Radial(curve(context)); } @@ -17656,11 +18104,11 @@ 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 arguments.length ? c(curveRadial(_)) : c()._curve; }; return l; } @@ -17686,40 +18134,122 @@ 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 arguments.length ? c(curveRadial(_)) : c()._curve; }; return a; } function pointRadial(x, y) { return [(y = +y) * Math.cos(x -= Math.PI / 2), y * Math.sin(x)]; } +class Bump { + constructor(context, x) { + this._context = context; + this._x = x; + } + areaStart() { + this._line = 0; + } + areaEnd() { + this._line = NaN; + } + lineStart() { + this._point = 0; + } + lineEnd() { + if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath(); + this._line = 1 - this._line; + } + point(x, y) { + x = +x, y = +y; + switch (this._point) { + case 0: { + this._point = 1; + if (this._line) this._context.lineTo(x, y); + else this._context.moveTo(x, y); + break; + } + case 1: this._point = 2; // falls through + default: { + if (this._x) this._context.bezierCurveTo(this._x0 = (this._x0 + x) / 2, this._y0, this._x0, y, x, y); + else this._context.bezierCurveTo(this._x0, this._y0 = (this._y0 + y) / 2, x, this._y0, x, y); + break; + } + } + this._x0 = x, this._y0 = y; + } +} + +class BumpRadial { + constructor(context) { + this._context = context; + } + lineStart() { + this._point = 0; + } + lineEnd() {} + point(x, y) { + x = +x, y = +y; + if (this._point === 0) { + this._point = 1; + } else { + const p0 = pointRadial(this._x0, this._y0); + const p1 = pointRadial(this._x0, this._y0 = (this._y0 + y) / 2); + const p2 = pointRadial(x, this._y0); + const p3 = pointRadial(x, y); + this._context.moveTo(...p0); + this._context.bezierCurveTo(...p1, ...p2, ...p3); + } + this._x0 = x, this._y0 = y; + } +} + +function bumpX(context) { + return new Bump(context, true); +} + +function bumpY(context) { + return new Bump(context, false); +} + +function bumpRadial(context) { + return new BumpRadial(context); +} + function linkSource(d) { return d.source; } function linkTarget(d) { return d.target; } function link(curve) { - var source = linkSource, + let source = linkSource, target = linkTarget, x$1 = x, y$1 = y, - context = null; + context = null, + output = null, + path = withPath(link); 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; + let buffer; + const argv = slice.call(arguments); + const s = source.apply(this, argv); + const t = target.apply(this, argv); + if (context == null) output = curve(buffer = path()); + output.lineStart(); + argv[0] = s, output.point(+x$1.apply(this, argv), +y$1.apply(this, argv)); + argv[0] = t, output.point(+x$1.apply(this, argv), +y$1.apply(this, argv)); + output.lineEnd(); + if (buffer) return output = null, buffer + "" || null; } link.source = function(_) { return arguments.length ? (source = _, link) : source; }; @@ -17735,61 +18265,58 @@ 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 arguments.length ? (_ == null ? context = output = null : output = curve(context = _), 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); + return link(bumpX); } function linkVertical() { - return link(curveVertical); + return link(bumpY); } function linkRadial() { - var l = link(curveRadial); + const l = link(bumpRadial); l.angle = l.x, delete l.x; l.radius = l.y, delete l.y; return l; } +const sqrt3$2 = sqrt(3); + +var asterisk = { + draw(context, size) { + const r = sqrt(size + min(size / 28, 0.75)) * 0.59436; + const t = r / 2; + const u = t * sqrt3$2; + context.moveTo(0, r); + context.lineTo(0, -r); + context.moveTo(-u, -t); + context.lineTo(u, t); + context.moveTo(-u, t); + context.lineTo(u, -t); + } +}; + var circle = { - draw: function(context, size) { - var r = Math.sqrt(size / pi); + draw(context, size) { + const r = 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; + draw(context, size) { + const r = sqrt(size / 5) / 2; context.moveTo(-3 * r, -r); context.lineTo(-r, -r); context.lineTo(-r, -3 * r); context.lineTo(r, -3 * r); context.lineTo(r, -r); @@ -17802,82 +18329,125 @@ context.lineTo(-3 * r, r); context.closePath(); } }; -var tan30 = Math.sqrt(1 / 3), - tan30_2 = tan30 * 2; +const tan30 = sqrt(1 / 3); +const tan30_2 = tan30 * 2; var diamond = { - draw: function(context, size) { - var y = Math.sqrt(size / tan30_2), - x = y * tan30; + draw(context, size) { + const y = sqrt(size / tan30_2); + const x = y * tan30; context.moveTo(0, -y); context.lineTo(x, 0); context.lineTo(0, y); context.lineTo(-x, 0); context.closePath(); } }; -var 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 diamond2 = { + draw(context, size) { + const r = sqrt(size) * 0.62625; + context.moveTo(0, -r); + context.lineTo(r, 0); + context.lineTo(0, r); + context.lineTo(-r, 0); + context.closePath(); + } +}; +var plus = { + draw(context, size) { + const r = sqrt(size - min(size / 7, 2)) * 0.87559; + context.moveTo(-r, 0); + context.lineTo(r, 0); + context.moveTo(0, r); + context.lineTo(0, -r); + } +}; + +var square = { + draw(context, size) { + const w = sqrt(size); + const x = -w / 2; + context.rect(x, x, w, w); + } +}; + +var square2 = { + draw(context, size) { + const r = sqrt(size) * 0.4431; + context.moveTo(r, r); + context.lineTo(r, -r); + context.lineTo(-r, -r); + context.lineTo(-r, r); + context.closePath(); + } +}; + +const ka = 0.89081309152928522810; +const kr = sin(pi / 10) / sin(7 * pi / 10); +const kx = sin(tau / 10) * kr; +const ky = -cos(tau / 10) * kr; + var star = { - draw: function(context, size) { - var r = Math.sqrt(size * ka), - x = kx * r, - y = ky * r; + draw(context, size) { + const r = sqrt(size * ka); + const x = kx * r; + const y = ky * r; context.moveTo(0, -r); context.lineTo(x, y); - for (var i = 1; i < 5; ++i) { - var a = tau * i / 5, - c = Math.cos(a), - s = Math.sin(a); + for (let i = 1; i < 5; ++i) { + const a = tau * i / 5; + const c = cos(a); + const s = sin(a); context.lineTo(s * r, -c * r); context.lineTo(c * x - s * y, s * x + c * y); } context.closePath(); } }; -var square = { - draw: function(context, size) { - var w = Math.sqrt(size), - x = -w / 2; - context.rect(x, x, w, w); +const sqrt3$1 = sqrt(3); + +var triangle = { + draw(context, size) { + const y = -sqrt(size / (sqrt3$1 * 3)); + context.moveTo(0, y * 2); + context.lineTo(-sqrt3$1 * y, -y); + context.lineTo(sqrt3$1 * y, -y); + context.closePath(); } }; -var sqrt3 = Math.sqrt(3); +const sqrt3 = 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); +var triangle2 = { + draw(context, size) { + const s = sqrt(size) * 0.6824; + const t = s / 2; + const u = (s * sqrt3) / 2; // cos(Math.PI / 6) + context.moveTo(0, -s); + context.lineTo(u, t); + context.lineTo(-u, t); context.closePath(); } }; -var c = -0.5, - s = Math.sqrt(3) / 2, - k = 1 / Math.sqrt(12), - a = (k / 2 + 1) * 3; +const c = -0.5; +const s = sqrt(3) / 2; +const k = 1 / sqrt(12); +const 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; + draw(context, size) { + const r = sqrt(size / a); + const x0 = r / 2, y0 = r * k; + const x1 = x0, y1 = r * k + r; + const x2 = -x1, y2 = y1; context.moveTo(x0, y0); context.lineTo(x1, y1); context.lineTo(x2, y2); context.lineTo(c * x0 - s * y0, s * x0 + c * y0); context.lineTo(c * x1 - s * y1, s * x1 + c * y1); @@ -17887,27 +18457,51 @@ context.lineTo(c * x2 + s * y2, c * y2 - s * x2); context.closePath(); } }; -var symbols = [ +var times = { + draw(context, size) { + const r = sqrt(size - min(size / 6, 1.7)) * 0.6189; + context.moveTo(-r, -r); + context.lineTo(r, r); + context.moveTo(-r, r); + context.lineTo(r, -r); + } +}; + +// These symbols are designed to be filled. +const symbolsFill = [ circle, cross, diamond, square, star, triangle, wye ]; -function symbol(type, size) { - var context = null; +// These symbols are designed to be stroked (with a width of 1.5px and round caps). +const symbolsStroke = [ + circle, + plus, + times, + triangle2, + asterisk, + square2, + diamond2 +]; + +function Symbol$1(type, size) { + let context = null, + path = withPath(symbol); + type = typeof type === "function" ? type : constant$1(type || circle); size = typeof size === "function" ? size : constant$1(size === undefined ? 64 : +size); function symbol() { - var buffer; + let buffer; if (!context) context = buffer = path(); type.apply(this, arguments).draw(context, +size.apply(this, arguments)); if (buffer) return context = null, buffer + "" || null; } @@ -18066,56 +18660,10 @@ 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; } @@ -19505,10 +20053,11 @@ exports.Delaunay = Delaunay; exports.FormatSpecifier = FormatSpecifier; exports.InternMap = InternMap; exports.InternSet = InternSet; exports.Node = Node$1; +exports.Path = Path$1; exports.Voronoi = Voronoi; exports.ZoomTransform = Transform; exports.active = active; exports.arc = arc; exports.area = area; @@ -19518,16 +20067,19 @@ exports.axisBottom = axisBottom; exports.axisLeft = axisLeft; exports.axisRight = axisRight; exports.axisTop = axisTop; exports.bin = bin; -exports.bisect = bisectRight; +exports.bisect = bisect; exports.bisectCenter = bisectCenter; exports.bisectLeft = bisectLeft; exports.bisectRight = bisectRight; exports.bisector = bisector; exports.blob = blob; +exports.blur = blur; +exports.blur2 = blur2; +exports.blurImage = blurImage; exports.brush = brush; exports.brushSelection = brushSelection; exports.brushX = brushX; exports.brushY = brushY; exports.buffer = buffer; @@ -19535,11 +20087,11 @@ exports.chordDirected = chordDirected; exports.chordTranspose = chordTranspose; exports.cluster = cluster; exports.color = color; exports.contourDensity = density; -exports.contours = contours; +exports.contours = Contours; exports.count = count$1; exports.create = create$1; exports.creator = creator; exports.cross = cross$2; exports.csv = csv; @@ -19644,11 +20196,11 @@ exports.geoAzimuthalEqualAreaRaw = azimuthalEqualAreaRaw; exports.geoAzimuthalEquidistant = azimuthalEquidistant; exports.geoAzimuthalEquidistantRaw = azimuthalEquidistantRaw; exports.geoBounds = bounds; exports.geoCentroid = centroid$1; -exports.geoCircle = circle$2; +exports.geoCircle = circle$1; exports.geoClipAntimeridian = clipAntimeridian; exports.geoClipCircle = clipCircle; exports.geoClipExtent = extent; exports.geoClipRectangle = clipRectangle; exports.geoConicConformal = conicConformal; @@ -19764,29 +20316,31 @@ exports.interpolateYlOrRd = YlOrRd; exports.interpolateZoom = interpolateZoom; exports.interrupt = interrupt; exports.intersection = intersection; exports.interval = interval; -exports.isoFormat = formatIso; -exports.isoParse = parseIso; +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.link = link; 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.medianIndex = medianIndex; exports.merge = merge; exports.min = min$2; exports.minIndex = minIndex; exports.mode = mode; exports.namespace = namespace; @@ -19797,10 +20351,11 @@ exports.packEnclose = enclose; exports.packSiblings = siblings; exports.pairs = pairs; exports.partition = partition; exports.path = path; +exports.pathRound = pathRound; exports.permute = permute; exports.pie = pie; exports.piecewise = piecewise; exports.pointRadial = pointRadial; exports.pointer = pointer; @@ -19813,10 +20368,11 @@ exports.precisionFixed = precisionFixed; exports.precisionPrefix = precisionPrefix; exports.precisionRound = precisionRound; exports.quadtree = quadtree; exports.quantile = quantile$1; +exports.quantileIndex = quantileIndex; exports.quantileSorted = quantileSorted; exports.quantize = quantize$1; exports.quickselect = quickselect; exports.radialArea = areaRadial; exports.radialLine = lineRadial$1; @@ -19836,11 +20392,12 @@ exports.randomNormal = normal; exports.randomPareto = pareto; exports.randomPoisson = poisson; exports.randomUniform = uniform; exports.randomWeibull = weibull; -exports.range = sequence; +exports.range = range$2; +exports.rank = rank; exports.reduce = reduce; exports.reverse = reverse$1; exports.rgb = rgb; exports.ribbon = ribbon$1; exports.ribbonArrow = ribbonArrow; @@ -19936,62 +20493,71 @@ exports.style = styleValue; exports.subset = subset; exports.sum = sum$2; exports.superset = superset; exports.svg = svg; -exports.symbol = symbol; +exports.symbol = Symbol$1; +exports.symbolAsterisk = asterisk; exports.symbolCircle = circle; exports.symbolCross = cross; exports.symbolDiamond = diamond; +exports.symbolDiamond2 = diamond2; +exports.symbolPlus = plus; exports.symbolSquare = square; +exports.symbolSquare2 = square2; exports.symbolStar = star; +exports.symbolTimes = times; exports.symbolTriangle = triangle; +exports.symbolTriangle2 = triangle2; exports.symbolWye = wye; -exports.symbols = symbols; +exports.symbolX = times; +exports.symbols = symbolsFill; +exports.symbolsFill = symbolsFill; +exports.symbolsStroke = symbolsStroke; exports.text = text; -exports.thresholdFreedmanDiaconis = freedmanDiaconis; -exports.thresholdScott = scott; +exports.thresholdFreedmanDiaconis = thresholdFreedmanDiaconis; +exports.thresholdScott = thresholdScott; exports.thresholdSturges = thresholdSturges; exports.tickFormat = tickFormat; exports.tickIncrement = tickIncrement; exports.tickStep = tickStep; exports.ticks = ticks; -exports.timeDay = day; -exports.timeDays = days; +exports.timeDay = timeDay; +exports.timeDays = timeDays; exports.timeFormatDefaultLocale = defaultLocale; exports.timeFormatLocale = formatLocale; -exports.timeFriday = friday; -exports.timeFridays = fridays; -exports.timeHour = hour; -exports.timeHours = hours; -exports.timeInterval = newInterval; +exports.timeFriday = timeFriday; +exports.timeFridays = timeFridays; +exports.timeHour = timeHour; +exports.timeHours = timeHours; +exports.timeInterval = timeInterval; exports.timeMillisecond = millisecond; exports.timeMilliseconds = milliseconds; -exports.timeMinute = minute; -exports.timeMinutes = minutes; -exports.timeMonday = monday; -exports.timeMondays = mondays; -exports.timeMonth = month; -exports.timeMonths = months; -exports.timeSaturday = saturday; -exports.timeSaturdays = saturdays; +exports.timeMinute = timeMinute; +exports.timeMinutes = timeMinutes; +exports.timeMonday = timeMonday; +exports.timeMondays = timeMondays; +exports.timeMonth = timeMonth; +exports.timeMonths = timeMonths; +exports.timeSaturday = timeSaturday; +exports.timeSaturdays = timeSaturdays; exports.timeSecond = second; exports.timeSeconds = seconds; -exports.timeSunday = sunday; -exports.timeSundays = sundays; -exports.timeThursday = thursday; -exports.timeThursdays = thursdays; +exports.timeSunday = timeSunday; +exports.timeSundays = timeSundays; +exports.timeThursday = timeThursday; +exports.timeThursdays = timeThursdays; 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 = year; -exports.timeYears = years; +exports.timeTuesday = timeTuesday; +exports.timeTuesdays = timeTuesdays; +exports.timeWednesday = timeWednesday; +exports.timeWednesdays = timeWednesdays; +exports.timeWeek = timeSunday; +exports.timeWeeks = timeSundays; +exports.timeYear = timeYear; +exports.timeYears = timeYears; exports.timeout = timeout; exports.timer = timer; exports.timerFlush = timerFlush; exports.transition = transition; exports.transpose = transpose; @@ -20010,10 +20576,12 @@ exports.tsvFormatRows = tsvFormatRows; exports.tsvFormatValue = tsvFormatValue; exports.tsvParse = tsvParse; exports.tsvParseRows = tsvParseRows; exports.union = union; +exports.unixDay = unixDay; +exports.unixDays = unixDays; exports.utcDay = utcDay; exports.utcDays = utcDays; exports.utcFriday = utcFriday; exports.utcFridays = utcFridays; exports.utcHour = utcHour; @@ -20051,8 +20619,6 @@ exports.zip = zip; exports.zoom = zoom; exports.zoomIdentity = identity; exports.zoomTransform = transform; -Object.defineProperty(exports, '__esModule', { value: true }); - -}))); +}));