vega
Version:
The Vega visualization grammar.
1,695 lines (1,637 loc) • 1.3 MB
JavaScript
(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.vega = {}));
})(this, (function (exports) { 'use strict';
function accessor(fn, fields, name) {
fn.fields = fields || [];
fn.fname = name;
return fn;
}
function accessorName(fn) {
return fn == null ? null : fn.fname;
}
function accessorFields(fn) {
return fn == null ? null : fn.fields;
}
function getter$1(path) {
return path.length === 1 ? get1(path[0]) : getN(path);
}
const get1 = field => function (obj) {
return obj[field];
};
const getN = path => {
const len = path.length;
return function (obj) {
for (let i = 0; i < len; ++i) {
obj = obj[path[i]];
}
return obj;
};
};
function error(message) {
throw Error(message);
}
function splitAccessPath(p) {
const path = [],
n = p.length;
let q = null,
b = 0,
s = '',
i,
j,
c;
p = p + '';
function push() {
path.push(s + p.substring(i, j));
s = '';
i = j + 1;
}
for (i = j = 0; j < n; ++j) {
c = p[j];
if (c === '\\') {
s += p.substring(i, j++);
i = j;
} else if (c === q) {
push();
q = null;
b = -1;
} else if (q) {
continue;
} else if (i === b && c === '"') {
i = j + 1;
q = c;
} else if (i === b && c === "'") {
i = j + 1;
q = c;
} else if (c === '.' && !b) {
if (j > i) {
push();
} else {
i = j + 1;
}
} else if (c === '[') {
if (j > i) push();
b = i = j + 1;
} else if (c === ']') {
if (!b) error('Access path missing open bracket: ' + p);
if (b > 0) push();
b = 0;
i = j + 1;
}
}
if (b) error('Access path missing closing bracket: ' + p);
if (q) error('Access path missing closing quote: ' + p);
if (j > i) {
j++;
push();
}
return path;
}
function field$1(field, name, opt) {
const path = splitAccessPath(field);
field = path.length === 1 ? path[0] : field;
return accessor((opt && opt.get || getter$1)(path), [field], name || field);
}
const id = field$1('id');
const identity$6 = accessor(_ => _, [], 'identity');
const zero$3 = accessor(() => 0, [], 'zero');
const one$2 = accessor(() => 1, [], 'one');
const truthy = accessor(() => true, [], 'true');
const falsy = accessor(() => false, [], 'false');
/** Utilities common to vega-interpreter and vega-expression for evaluating expresions */
/** JSON authors are not allowed to set these properties, as these are built-in to the JS Object Prototype and should not be overridden. */
const DisallowedObjectProperties = new Set([...Object.getOwnPropertyNames(Object.prototype).filter(name => typeof Object.prototype[name] === 'function'), '__proto__']);
function log$1$1(method, level, input) {
const args = [level].concat([].slice.call(input));
console[method].apply(console, args); // eslint-disable-line no-console
}
const None$2 = 0;
const Error$1 = 1;
const Warn = 2;
const Info = 3;
const Debug = 4;
function logger(_, method, handler = log$1$1) {
let level = _ || None$2;
return {
level(_) {
if (arguments.length) {
level = +_;
return this;
} else {
return level;
}
},
error() {
if (level >= Error$1) handler(method || 'error', 'ERROR', arguments);
return this;
},
warn() {
if (level >= Warn) handler(method || 'warn', 'WARN', arguments);
return this;
},
info() {
if (level >= Info) handler(method || 'log', 'INFO', arguments);
return this;
},
debug() {
if (level >= Debug) handler(method || 'log', 'DEBUG', arguments);
return this;
}
};
}
var isArray = Array.isArray;
function isObject(_) {
return _ === Object(_);
}
const isLegalKey = key => key !== '__proto__';
function mergeConfig(...configs) {
return configs.reduce((out, source) => {
for (const key in source) {
if (key === 'signals') {
// for signals, we merge the signals arrays
// source signals take precedence over
// existing signals with the same name
out.signals = mergeNamed(out.signals, source.signals);
} else {
// otherwise, merge objects subject to recursion constraints
// for legend block, recurse for the layout entry only
// for style block, recurse for all properties
// otherwise, no recursion: objects overwrite, no merging
const r = key === 'legend' ? {
layout: 1
} : key === 'style' ? true : null;
writeConfig(out, key, source[key], r);
}
}
return out;
}, {});
}
function writeConfig(output, key, value, recurse) {
if (!isLegalKey(key)) return;
let k, o;
if (isObject(value) && !isArray(value)) {
o = isObject(output[key]) ? output[key] : output[key] = {};
for (k in value) {
if (recurse && (recurse === true || recurse[k])) {
writeConfig(o, k, value[k]);
} else if (isLegalKey(k)) {
o[k] = value[k];
}
}
} else {
output[key] = value;
}
}
function mergeNamed(a, b) {
if (a == null) return b;
const map = {},
out = [];
function add(_) {
if (!map[_.name]) {
map[_.name] = 1;
out.push(_);
}
}
b.forEach(add);
a.forEach(add);
return out;
}
function peek$1(array) {
return array[array.length - 1];
}
function toNumber(_) {
return _ == null || _ === '' ? null : +_;
}
const exp$2 = sign => x => sign * Math.exp(x);
const log$4 = sign => x => Math.log(sign * x);
const symlog$1 = c => x => Math.sign(x) * Math.log1p(Math.abs(x / c));
const symexp = c => x => Math.sign(x) * Math.expm1(Math.abs(x)) * c;
const pow$4 = exponent => x => x < 0 ? -Math.pow(-x, exponent) : Math.pow(x, exponent);
function pan(domain, delta, lift, ground) {
const d0 = lift(domain[0]),
d1 = lift(peek$1(domain)),
dd = (d1 - d0) * delta;
return [ground(d0 - dd), ground(d1 - dd)];
}
function panLinear(domain, delta) {
return pan(domain, delta, toNumber, identity$6);
}
function panLog(domain, delta) {
var sign = Math.sign(domain[0]);
return pan(domain, delta, log$4(sign), exp$2(sign));
}
function panPow(domain, delta, exponent) {
return pan(domain, delta, pow$4(exponent), pow$4(1 / exponent));
}
function panSymlog(domain, delta, constant) {
return pan(domain, delta, symlog$1(constant), symexp(constant));
}
function zoom$1(domain, anchor, scale, lift, ground) {
const d0 = lift(domain[0]),
d1 = lift(peek$1(domain)),
da = anchor != null ? lift(anchor) : (d0 + d1) / 2;
return [ground(da + (d0 - da) * scale), ground(da + (d1 - da) * scale)];
}
function zoomLinear(domain, anchor, scale) {
return zoom$1(domain, anchor, scale, toNumber, identity$6);
}
function zoomLog(domain, anchor, scale) {
const sign = Math.sign(domain[0]);
return zoom$1(domain, anchor, scale, log$4(sign), exp$2(sign));
}
function zoomPow(domain, anchor, scale, exponent) {
return zoom$1(domain, anchor, scale, pow$4(exponent), pow$4(1 / exponent));
}
function zoomSymlog(domain, anchor, scale, constant) {
return zoom$1(domain, anchor, scale, symlog$1(constant), symexp(constant));
}
function quarter(date) {
return 1 + ~~(new Date(date).getMonth() / 3);
}
function utcquarter(date) {
return 1 + ~~(new Date(date).getUTCMonth() / 3);
}
function array$5(_) {
return _ != null ? isArray(_) ? _ : [_] : [];
}
/**
* Span-preserving range clamp. If the span of the input range is less
* than (max - min) and an endpoint exceeds either the min or max value,
* the range is translated such that the span is preserved and one
* endpoint touches the boundary of the min/max range.
* If the span exceeds (max - min), the range [min, max] is returned.
*/
function clampRange(range, min, max) {
let lo = range[0],
hi = range[1],
span;
if (hi < lo) {
span = hi;
hi = lo;
lo = span;
}
span = hi - lo;
return span >= max - min ? [min, max] : [lo = Math.min(Math.max(lo, min), max - span), lo + span];
}
function isFunction(_) {
return typeof _ === 'function';
}
const DESCENDING = 'descending';
function compare$1(fields, orders, opt) {
opt = opt || {};
orders = array$5(orders) || [];
const ord = [],
get = [],
fmap = {},
gen = opt.comparator || comparator;
array$5(fields).forEach((f, i) => {
if (f == null) return;
ord.push(orders[i] === DESCENDING ? -1 : 1);
get.push(f = isFunction(f) ? f : field$1(f, null, opt));
(accessorFields(f) || []).forEach(_ => fmap[_] = 1);
});
return get.length === 0 ? null : accessor(gen(get, ord), Object.keys(fmap));
}
const ascending$2 = (u, v) => (u < v || u == null) && v != null ? -1 : (u > v || v == null) && u != null ? 1 : (v = v instanceof Date ? +v : v, u = u instanceof Date ? +u : u) !== u && v === v ? -1 : v !== v && u === u ? 1 : 0;
const comparator = (fields, orders) => fields.length === 1 ? compare1(fields[0], orders[0]) : compareN(fields, orders, fields.length);
const compare1 = (field, order) => function (a, b) {
return ascending$2(field(a), field(b)) * order;
};
const compareN = (fields, orders, n) => {
orders.push(0); // pad zero for convenient lookup
return function (a, b) {
let f,
c = 0,
i = -1;
while (c === 0 && ++i < n) {
f = fields[i];
c = ascending$2(f(a), f(b));
}
return c * orders[i];
};
};
function constant$5(_) {
return isFunction(_) ? _ : () => _;
}
function debounce(delay, handler) {
let tid;
return e => {
if (tid) clearTimeout(tid);
tid = setTimeout(() => (handler(e), tid = null), delay);
};
}
function extend$1(_) {
for (let x, k, i = 1, len = arguments.length; i < len; ++i) {
x = arguments[i];
for (k in x) {
_[k] = x[k];
}
}
return _;
}
/**
* Return an array with minimum and maximum values, in the
* form [min, max]. Ignores null, undefined, and NaN values.
*/
function extent(array, f) {
let i = 0,
n,
v,
min,
max;
if (array && (n = array.length)) {
if (f == null) {
// find first valid value
for (v = array[i]; i < n && (v == null || v !== v); v = array[++i]);
min = max = v;
// visit all other values
for (; i < n; ++i) {
v = array[i];
// skip null/undefined; NaN will fail all comparisons
if (v != null) {
if (v < min) min = v;
if (v > max) max = v;
}
}
} else {
// find first valid value
for (v = f(array[i]); i < n && (v == null || v !== v); v = f(array[++i]));
min = max = v;
// visit all other values
for (; i < n; ++i) {
v = f(array[i]);
// skip null/undefined; NaN will fail all comparisons
if (v != null) {
if (v < min) min = v;
if (v > max) max = v;
}
}
}
}
return [min, max];
}
function extentIndex(array, f) {
const n = array.length;
let i = -1,
a,
b,
c,
u,
v;
if (f == null) {
while (++i < n) {
b = array[i];
if (b != null && b >= b) {
a = c = b;
break;
}
}
if (i === n) return [-1, -1];
u = v = i;
while (++i < n) {
b = array[i];
if (b != null) {
if (a > b) {
a = b;
u = i;
}
if (c < b) {
c = b;
v = i;
}
}
}
} else {
while (++i < n) {
b = f(array[i], i, array);
if (b != null && b >= b) {
a = c = b;
break;
}
}
if (i === n) return [-1, -1];
u = v = i;
while (++i < n) {
b = f(array[i], i, array);
if (b != null) {
if (a > b) {
a = b;
u = i;
}
if (c < b) {
c = b;
v = i;
}
}
}
}
return [u, v];
}
function has$1(object, property) {
return Object.hasOwn(object, property);
}
const NULL = {};
function fastmap(input) {
let obj = {},
test;
function has$1$1(key) {
return has$1(obj, key) && obj[key] !== NULL;
}
const map = {
size: 0,
empty: 0,
object: obj,
has: has$1$1,
get(key) {
return has$1$1(key) ? obj[key] : undefined;
},
set(key, value) {
if (!has$1$1(key)) {
++map.size;
if (obj[key] === NULL) --map.empty;
}
obj[key] = value;
return this;
},
delete(key) {
if (has$1$1(key)) {
--map.size;
++map.empty;
obj[key] = NULL;
}
return this;
},
clear() {
map.size = map.empty = 0;
map.object = obj = {};
},
test(_) {
if (arguments.length) {
test = _;
return map;
} else {
return test;
}
},
clean() {
const next = {};
let size = 0;
for (const key in obj) {
const value = obj[key];
if (value !== NULL && (!test || !test(value))) {
next[key] = value;
++size;
}
}
map.size = size;
map.empty = 0;
map.object = obj = next;
}
};
if (input) Object.keys(input).forEach(key => {
map.set(key, input[key]);
});
return map;
}
function flush(range, value, threshold, left, right, center) {
if (!threshold && threshold !== 0) return center;
const t = +threshold;
let a = range[0],
b = peek$1(range),
l;
// swap endpoints if range is reversed
if (b < a) {
l = a;
a = b;
b = l;
}
// compare value to endpoints
l = Math.abs(value - a);
const r = Math.abs(b - value);
// adjust if value is within threshold distance of endpoint
return l < r && l <= t ? left : r <= t ? right : center;
}
function inherits(child, parent, members) {
const proto = child.prototype = Object.create(parent.prototype);
Object.defineProperty(proto, 'constructor', {
value: child,
writable: true,
enumerable: true,
configurable: true
});
return extend$1(proto, members);
}
/**
* Predicate that returns true if the value lies within the span
* of the given range. The left and right flags control the use
* of inclusive (true) or exclusive (false) comparisons.
*/
function inrange(value, range, left, right) {
let r0 = range[0],
r1 = range[range.length - 1],
t;
if (r0 > r1) {
t = r0;
r0 = r1;
r1 = t;
}
left = left === undefined || left;
right = right === undefined || right;
return (left ? r0 <= value : r0 < value) && (right ? value <= r1 : value < r1);
}
function isBoolean$1(_) {
return typeof _ === 'boolean';
}
function isDate$1(_) {
return Object.prototype.toString.call(_) === '[object Date]';
}
function isIterable(_) {
return _ && isFunction(_[Symbol.iterator]);
}
function isNumber$1(_) {
return typeof _ === 'number';
}
function isRegExp(_) {
return Object.prototype.toString.call(_) === '[object RegExp]';
}
function isString(_) {
return typeof _ === 'string';
}
function key(fields, flat, opt) {
if (fields) {
fields = flat ? array$5(fields).map(f => f.replace(/\\(.)/g, '$1')) : array$5(fields);
}
const len = fields && fields.length,
gen = opt && opt.get || getter$1,
map = f => gen(flat ? [f] : splitAccessPath(f));
let fn;
if (!len) {
fn = function () {
return '';
};
} else if (len === 1) {
const get = map(fields[0]);
fn = function (_) {
return '' + get(_);
};
} else {
const get = fields.map(map);
fn = function (_) {
let s = '' + get[0](_),
i = 0;
while (++i < len) s += '|' + get[i](_);
return s;
};
}
return accessor(fn, fields, 'key');
}
function lerp(array, frac) {
const lo = array[0],
hi = peek$1(array),
f = +frac;
return !f ? lo : f === 1 ? hi : lo + f * (hi - lo);
}
const DEFAULT_MAX_SIZE = 10000;
// adapted from https://github.com/dominictarr/hashlru/ (MIT License)
function lruCache(maxsize) {
maxsize = +maxsize || DEFAULT_MAX_SIZE;
let curr, prev, size;
const clear = () => {
curr = {};
prev = {};
size = 0;
};
const update = (key, value) => {
if (++size > maxsize) {
prev = curr;
curr = {};
size = 1;
}
return curr[key] = value;
};
clear();
return {
clear,
has: key => has$1(curr, key) || has$1(prev, key),
get: key => has$1(curr, key) ? curr[key] : has$1(prev, key) ? update(key, prev[key]) : undefined,
set: (key, value) => has$1(curr, key) ? curr[key] = value : update(key, value)
};
}
function merge$3(compare, array0, array1, output) {
const n0 = array0.length,
n1 = array1.length;
if (!n1) return array0;
if (!n0) return array1;
const merged = output || new array0.constructor(n0 + n1);
let i0 = 0,
i1 = 0,
i = 0;
for (; i0 < n0 && i1 < n1; ++i) {
merged[i] = compare(array0[i0], array1[i1]) > 0 ? array1[i1++] : array0[i0++];
}
for (; i0 < n0; ++i0, ++i) {
merged[i] = array0[i0];
}
for (; i1 < n1; ++i1, ++i) {
merged[i] = array1[i1];
}
return merged;
}
function repeat(str, reps) {
let s = '';
while (--reps >= 0) s += str;
return s;
}
function pad$2(str, length, padchar, align) {
const c = padchar || ' ',
s = str + '',
n = length - s.length;
return n <= 0 ? s : align === 'left' ? repeat(c, n) + s : align === 'center' ? repeat(c, ~~(n / 2)) + s + repeat(c, Math.ceil(n / 2)) : s + repeat(c, n);
}
/**
* Return the numerical span of an array: the difference between
* the last and first values.
*/
function span(array) {
return array && peek$1(array) - array[0] || 0;
}
function $(x) {
return isArray(x) ? `[${x.map(v => v === null ? 'null' : $(v))}]` : isObject(x) || isString(x) ?
// Output valid JSON and JS source strings.
// See https://github.com/judofyr/timeless/blob/master/posts/json-isnt-a-javascript-subset.md
JSON.stringify(x).replaceAll('\u2028', '\\u2028').replaceAll('\u2029', '\\u2029') : x;
}
function toBoolean(_) {
return _ == null || _ === '' ? null : !_ || _ === 'false' || _ === '0' ? false : !!_;
}
const defaultParser = _ => isNumber$1(_) ? _ : isDate$1(_) ? _ : Date.parse(_);
function toDate(_, parser) {
parser = parser || defaultParser;
return _ == null || _ === '' ? null : parser(_);
}
function toString(_) {
return _ == null || _ === '' ? null : _ + '';
}
function toSet(_) {
const s = {},
n = _.length;
for (let i = 0; i < n; ++i) s[_[i]] = true;
return s;
}
function truncate$1(str, length, align, ellipsis) {
const e = ellipsis != null ? ellipsis : '\u2026',
s = str + '',
n = s.length,
l = Math.max(0, length - e.length);
return n <= length ? s : align === 'left' ? e + s.slice(n - l) : align === 'center' ? s.slice(0, Math.ceil(l / 2)) + e + s.slice(n - ~~(l / 2)) : s.slice(0, l) + e;
}
function visitArray(array, filter, visitor) {
if (array) {
if (filter) {
const n = array.length;
for (let i = 0; i < n; ++i) {
const t = filter(array[i]);
if (t) visitor(t, i, array);
}
} else {
array.forEach(visitor);
}
}
}
var EOL = {},
EOF = {},
QUOTE = 34,
NEWLINE = 10,
RETURN = 13;
function objectConverter(columns) {
return new Function("d", "return {" + columns.map(function (name, i) {
return JSON.stringify(name) + ": d[" + i + "] || \"\"";
}).join(",") + "}");
}
function customConverter(columns, f) {
var object = objectConverter(columns);
return function (row, i) {
return f(object(row), i, columns);
};
}
// Compute unique columns in order of discovery.
function inferColumns(rows) {
var columnSet = Object.create(null),
columns = [];
rows.forEach(function (row) {
for (var column in row) {
if (!(column in columnSet)) {
columns.push(columnSet[column] = column);
}
}
});
return columns;
}
function pad$1(value, width) {
var s = value + "",
length = s.length;
return length < width ? new Array(width - length + 1).join(0) + s : s;
}
function formatYear$1(year) {
return year < 0 ? "-" + pad$1(-year, 6) : year > 9999 ? "+" + pad$1(year, 6) : pad$1(year, 4);
}
function formatDate(date) {
var hours = date.getUTCHours(),
minutes = date.getUTCMinutes(),
seconds = date.getUTCSeconds(),
milliseconds = date.getUTCMilliseconds();
return isNaN(date) ? "Invalid Date" : formatYear$1(date.getUTCFullYear()) + "-" + pad$1(date.getUTCMonth() + 1, 2) + "-" + pad$1(date.getUTCDate(), 2) + (milliseconds ? "T" + pad$1(hours, 2) + ":" + pad$1(minutes, 2) + ":" + pad$1(seconds, 2) + "." + pad$1(milliseconds, 3) + "Z" : seconds ? "T" + pad$1(hours, 2) + ":" + pad$1(minutes, 2) + ":" + pad$1(seconds, 2) + "Z" : minutes || hours ? "T" + pad$1(hours, 2) + ":" + pad$1(minutes, 2) + "Z" : "");
}
function dsvFormat (delimiter) {
var reFormat = new RegExp("[\"" + delimiter + "\n\r]"),
DELIMITER = delimiter.charCodeAt(0);
function parse(text, f) {
var convert,
columns,
rows = parseRows(text, function (row, i) {
if (convert) return convert(row, i - 1);
columns = row, convert = f ? customConverter(row, f) : objectConverter(row);
});
rows.columns = columns || [];
return rows;
}
function parseRows(text, f) {
var rows = [],
// output rows
N = text.length,
I = 0,
// current character index
n = 0,
// current line number
t,
// current token
eof = N <= 0,
// current token followed by EOF?
eol = false; // current token followed by EOL?
// Strip the trailing newline.
if (text.charCodeAt(N - 1) === NEWLINE) --N;
if (text.charCodeAt(N - 1) === RETURN) --N;
function token() {
if (eof) return EOF;
if (eol) return eol = false, EOL;
// Unescape quotes.
var i,
j = I,
c;
if (text.charCodeAt(j) === QUOTE) {
while (I++ < N && text.charCodeAt(I) !== QUOTE || text.charCodeAt(++I) === QUOTE);
if ((i = I) >= N) eof = true;else if ((c = text.charCodeAt(I++)) === NEWLINE) eol = true;else if (c === RETURN) {
eol = true;
if (text.charCodeAt(I) === NEWLINE) ++I;
}
return text.slice(j + 1, i - 1).replace(/""/g, "\"");
}
// Find next delimiter or newline.
while (I < N) {
if ((c = text.charCodeAt(i = I++)) === NEWLINE) eol = true;else if (c === RETURN) {
eol = true;
if (text.charCodeAt(I) === NEWLINE) ++I;
} else if (c !== DELIMITER) continue;
return text.slice(j, i);
}
// Return last token before EOF.
return eof = true, text.slice(j, N);
}
while ((t = token()) !== EOF) {
var row = [];
while (t !== EOL && t !== EOF) row.push(t), t = token();
if (f && (row = f(row, n++)) == null) continue;
rows.push(row);
}
return rows;
}
function preformatBody(rows, columns) {
return rows.map(function (row) {
return columns.map(function (column) {
return formatValue(row[column]);
}).join(delimiter);
});
}
function format(rows, columns) {
if (columns == null) columns = inferColumns(rows);
return [columns.map(formatValue).join(delimiter)].concat(preformatBody(rows, columns)).join("\n");
}
function formatBody(rows, columns) {
if (columns == null) columns = inferColumns(rows);
return preformatBody(rows, columns).join("\n");
}
function formatRows(rows) {
return rows.map(formatRow).join("\n");
}
function formatRow(row) {
return row.map(formatValue).join(delimiter);
}
function formatValue(value) {
return value == null ? "" : value instanceof Date ? formatDate(value) : reFormat.test(value += "") ? "\"" + value.replace(/"/g, "\"\"") + "\"" : value;
}
return {
parse: parse,
parseRows: parseRows,
format: format,
formatBody: formatBody,
formatRows: formatRows,
formatRow: formatRow,
formatValue: formatValue
};
}
function identity$5 (x) {
return x;
}
function transform$3 (transform) {
if (transform == null) return identity$5;
var x0,
y0,
kx = transform.scale[0],
ky = transform.scale[1],
dx = transform.translate[0],
dy = transform.translate[1];
return function (input, i) {
if (!i) x0 = y0 = 0;
var j = 2,
n = input.length,
output = new Array(n);
output[0] = (x0 += input[0]) * kx + dx;
output[1] = (y0 += input[1]) * ky + dy;
while (j < n) output[j] = input[j], ++j;
return output;
};
}
function reverse$1 (array, n) {
var t,
j = array.length,
i = j - n;
while (i < --j) t = array[i], array[i++] = array[j], array[j] = t;
}
function feature (topology, o) {
if (typeof o === "string") o = topology.objects[o];
return o.type === "GeometryCollection" ? {
type: "FeatureCollection",
features: o.geometries.map(function (o) {
return feature$1(topology, o);
})
} : feature$1(topology, o);
}
function feature$1(topology, o) {
var id = o.id,
bbox = o.bbox,
properties = o.properties == null ? {} : o.properties,
geometry = object$1(topology, o);
return id == null && bbox == null ? {
type: "Feature",
properties: properties,
geometry: geometry
} : bbox == null ? {
type: "Feature",
id: id,
properties: properties,
geometry: geometry
} : {
type: "Feature",
id: id,
bbox: bbox,
properties: properties,
geometry: geometry
};
}
function object$1(topology, o) {
var transformPoint = transform$3(topology.transform),
arcs = topology.arcs;
function arc(i, points) {
if (points.length) points.pop();
for (var a = arcs[i < 0 ? ~i : i], k = 0, n = a.length; k < n; ++k) {
points.push(transformPoint(a[k], k));
}
if (i < 0) reverse$1(points, n);
}
function point(p) {
return transformPoint(p);
}
function line(arcs) {
var points = [];
for (var i = 0, n = arcs.length; i < n; ++i) arc(arcs[i], points);
if (points.length < 2) points.push(points[0]); // This should never happen per the specification.
return points;
}
function ring(arcs) {
var points = line(arcs);
while (points.length < 4) points.push(points[0]); // This may happen if an arc has only two points.
return points;
}
function polygon(arcs) {
return arcs.map(ring);
}
function geometry(o) {
var type = o.type,
coordinates;
switch (type) {
case "GeometryCollection":
return {
type: type,
geometries: o.geometries.map(geometry)
};
case "Point":
coordinates = point(o.coordinates);
break;
case "MultiPoint":
coordinates = o.coordinates.map(point);
break;
case "LineString":
coordinates = line(o.arcs);
break;
case "MultiLineString":
coordinates = o.arcs.map(line);
break;
case "Polygon":
coordinates = polygon(o.arcs);
break;
case "MultiPolygon":
coordinates = o.arcs.map(polygon);
break;
default:
return null;
}
return {
type: type,
coordinates: coordinates
};
}
return geometry(o);
}
function stitch (topology, arcs) {
var stitchedArcs = {},
fragmentByStart = {},
fragmentByEnd = {},
fragments = [],
emptyIndex = -1;
// Stitch empty arcs first, since they may be subsumed by other arcs.
arcs.forEach(function (i, j) {
var arc = topology.arcs[i < 0 ? ~i : i],
t;
if (arc.length < 3 && !arc[1][0] && !arc[1][1]) {
t = arcs[++emptyIndex], arcs[emptyIndex] = i, arcs[j] = t;
}
});
arcs.forEach(function (i) {
var e = ends(i),
start = e[0],
end = e[1],
f,
g;
if (f = fragmentByEnd[start]) {
delete fragmentByEnd[f.end];
f.push(i);
f.end = end;
if (g = fragmentByStart[end]) {
delete fragmentByStart[g.start];
var fg = g === f ? f : f.concat(g);
fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.end] = fg;
} else {
fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
}
} else if (f = fragmentByStart[end]) {
delete fragmentByStart[f.start];
f.unshift(i);
f.start = start;
if (g = fragmentByEnd[start]) {
delete fragmentByEnd[g.end];
var gf = g === f ? f : g.concat(f);
fragmentByStart[gf.start = g.start] = fragmentByEnd[gf.end = f.end] = gf;
} else {
fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
}
} else {
f = [i];
fragmentByStart[f.start = start] = fragmentByEnd[f.end = end] = f;
}
});
function ends(i) {
var arc = topology.arcs[i < 0 ? ~i : i],
p0 = arc[0],
p1;
if (topology.transform) p1 = [0, 0], arc.forEach(function (dp) {
p1[0] += dp[0], p1[1] += dp[1];
});else p1 = arc[arc.length - 1];
return i < 0 ? [p1, p0] : [p0, p1];
}
function flush(fragmentByEnd, fragmentByStart) {
for (var k in fragmentByEnd) {
var f = fragmentByEnd[k];
delete fragmentByStart[f.start];
delete f.start;
delete f.end;
f.forEach(function (i) {
stitchedArcs[i < 0 ? ~i : i] = 1;
});
fragments.push(f);
}
}
flush(fragmentByEnd, fragmentByStart);
flush(fragmentByStart, fragmentByEnd);
arcs.forEach(function (i) {
if (!stitchedArcs[i < 0 ? ~i : i]) fragments.push([i]);
});
return fragments;
}
function mesh (topology) {
return object$1(topology, meshArcs.apply(this, arguments));
}
function meshArcs(topology, object, filter) {
var arcs, i, n;
if (arguments.length > 1) arcs = extractArcs(topology, object, filter);else for (i = 0, arcs = new Array(n = topology.arcs.length); i < n; ++i) arcs[i] = i;
return {
type: "MultiLineString",
arcs: stitch(topology, arcs)
};
}
function extractArcs(topology, object, filter) {
var arcs = [],
geomsByArc = [],
geom;
function extract0(i) {
var j = i < 0 ? ~i : i;
(geomsByArc[j] || (geomsByArc[j] = [])).push({
i: i,
g: geom
});
}
function extract1(arcs) {
arcs.forEach(extract0);
}
function extract2(arcs) {
arcs.forEach(extract1);
}
function extract3(arcs) {
arcs.forEach(extract2);
}
function geometry(o) {
switch (geom = o, o.type) {
case "GeometryCollection":
o.geometries.forEach(geometry);
break;
case "LineString":
extract1(o.arcs);
break;
case "MultiLineString":
case "Polygon":
extract2(o.arcs);
break;
case "MultiPolygon":
extract3(o.arcs);
break;
}
}
geometry(object);
geomsByArc.forEach(filter == null ? function (geoms) {
arcs.push(geoms[0].i);
} : function (geoms) {
if (filter(geoms[0].g, geoms[geoms.length - 1].g)) arcs.push(geoms[0].i);
});
return arcs;
}
function ascending$1(a, b) {
return a == null || b == null ? NaN : a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
}
function descending$1(a, b) {
return a == null || b == null ? NaN : b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
}
function bisector(f) {
let compare1, compare2, delta;
// 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$1;
compare2 = (d, x) => ascending$1(f(d), x);
delta = (d, x) => f(d) - x;
} else {
compare1 = f === ascending$1 || f === descending$1 ? f : zero$2;
compare2 = f;
delta = f;
}
function left(a, x, lo = 0, hi = a.length) {
if (lo < hi) {
if (compare1(x, x) !== 0) return hi;
do {
const mid = lo + hi >>> 1;
if (compare2(a[mid], x) < 0) lo = mid + 1;else hi = mid;
} while (lo < hi);
}
return lo;
}
function right(a, x, lo = 0, hi = a.length) {
if (lo < hi) {
if (compare1(x, x) !== 0) return hi;
do {
const mid = lo + hi >>> 1;
if (compare2(a[mid], x) <= 0) lo = mid + 1;else hi = mid;
} while (lo < hi);
}
return lo;
}
function center(a, x, lo = 0, hi = a.length) {
const i = left(a, x, lo, hi - 1);
return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i;
}
return {
left,
center,
right
};
}
function zero$2() {
return 0;
}
function number$6(x) {
return x === null ? NaN : +x;
}
function* numbers$2(values, valueof) {
if (valueof === undefined) {
for (let value of values) {
if (value != null && (value = +value) >= value) {
yield value;
}
}
} else {
let index = -1;
for (let value of values) {
if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {
yield value;
}
}
}
}
const ascendingBisect = bisector(ascending$1);
const bisectRight$1 = ascendingBisect.right;
const bisectLeft$1 = ascendingBisect.left;
bisector(number$6).center;
function variance(values, valueof) {
let count = 0;
let delta;
let mean = 0;
let sum = 0;
if (valueof === undefined) {
for (let value of values) {
if (value != null && (value = +value) >= value) {
delta = value - mean;
mean += delta / ++count;
sum += delta * (value - mean);
}
}
} else {
let index = -1;
for (let value of values) {
if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {
delta = value - mean;
mean += delta / ++count;
sum += delta * (value - mean);
}
}
}
if (count > 1) return sum / (count - 1);
}
function deviation(values, valueof) {
const v = variance(values, valueof);
return v ? Math.sqrt(v) : v;
}
// https://github.com/python/cpython/blob/a74eea238f5baba15797e2e8b570d153bc8690a7/Modules/mathmodule.c#L1423
class Adder {
constructor() {
this._partials = new Float64Array(32);
this._n = 0;
}
add(x) {
const p = this._partials;
let i = 0;
for (let j = 0; j < this._n && j < 32; j++) {
const y = p[j],
hi = x + y,
lo = Math.abs(x) < Math.abs(y) ? x - (hi - y) : y - (hi - x);
if (lo) p[i++] = lo;
x = hi;
}
p[i] = x;
this._n = i + 1;
return this;
}
valueOf() {
const p = this._partials;
let n = this._n,
x,
y,
lo,
hi = 0;
if (n > 0) {
hi = p[--n];
while (n > 0) {
x = hi;
y = p[--n];
hi = x + y;
lo = y - (hi - x);
if (lo) break;
}
if (n > 0 && (lo < 0 && p[n - 1] < 0 || lo > 0 && p[n - 1] > 0)) {
y = lo * 2;
x = hi + y;
if (y == x - hi) hi = x;
}
}
return hi;
}
}
class InternMap extends Map {
constructor(entries, key = keyof) {
super();
Object.defineProperties(this, {
_intern: {
value: new Map()
},
_key: {
value: key
}
});
if (entries != null) for (const [key, value] of entries) this.set(key, value);
}
get(key) {
return super.get(intern_get(this, key));
}
has(key) {
return super.has(intern_get(this, key));
}
set(key, value) {
return super.set(intern_set(this, key), value);
}
delete(key) {
return super.delete(intern_delete(this, key));
}
}
class InternSet extends Set {
constructor(values, key = keyof) {
super();
Object.defineProperties(this, {
_intern: {
value: new Map()
},
_key: {
value: key
}
});
if (values != null) for (const value of values) this.add(value);
}
has(value) {
return super.has(intern_get(this, value));
}
add(value) {
return super.add(intern_set(this, value));
}
delete(value) {
return super.delete(intern_delete(this, value));
}
}
function intern_get({
_intern,
_key
}, value) {
const key = _key(value);
return _intern.has(key) ? _intern.get(key) : value;
}
function intern_set({
_intern,
_key
}, value) {
const key = _key(value);
if (_intern.has(key)) return _intern.get(key);
_intern.set(key, value);
return value;
}
function intern_delete({
_intern,
_key
}, value) {
const key = _key(value);
if (_intern.has(key)) {
value = _intern.get(key);
_intern.delete(key);
}
return value;
}
function keyof(value) {
return value !== null && typeof value === "object" ? value.valueOf() : value;
}
function permute(source, keys) {
return Array.from(keys, key => source[key]);
}
function compareDefined(compare = ascending$1) {
if (compare === ascending$1) 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);
}
const e10 = Math.sqrt(50),
e5 = Math.sqrt(10),
e2 = Math.sqrt(2);
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 (!(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 {
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;
}
return ticks;
}
function tickIncrement(start, stop, count) {
stop = +stop, start = +start, count = +count;
return tickSpec(start, stop, count)[2];
}
function tickStep(start, stop, count) {
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 max$2(values, valueof) {
let max;
if (valueof === undefined) {
for (const value of values) {
if (value != null && (max < value || max === undefined && value >= value)) {
max = value;
}
}
} else {
let index = -1;
for (let value of values) {
if ((value = valueof(value, ++index, values)) != null && (max < value || max === undefined && value >= value)) {
max = value;
}
}
}
return max;
}
function min$2(values, valueof) {
let min;
if (valueof === undefined) {
for (const value of values) {
if (value != null && (min > value || min === undefined && value >= value)) {
min = value;
}
}
} else {
let index = -1;
for (let value of values) {
if ((value = valueof(value, ++index, values)) != null && (min > value || min === undefined && value >= value)) {
min = value;
}
}
}
return min;
}
// Based on https://github.com/mourner/quickselect
// ISC license, Copyright 2018 Vladimir Agafonkin.
function quickselect(array, k, left = 0, right = 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);
const s = 0.5 * Math.exp(2 * z / 3);
const sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
const newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
const newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
quickselect(array, k, newLeft, newRight, compare);
}
const t = array[k];
let i = left;
let j = right;
swap$1(array, left, k);
if (compare(array[right], t) > 0) swap$1(array, left, right);
while (i < j) {
swap$1(array, i, j), ++i, --j;
while (compare(array[i], t) < 0) ++i;
while (compare(array[j], t) > 0) --j;
}
if (compare(array[left], t) === 0) swap$1(array, left, j);else ++j, swap$1(array, j, right);
if (j <= k) left = j + 1;
if (k <= j) right = j - 1;
}
return array;
}
function swap$1(array, i, j) {
const t = array[i];
array[i] = array[j];
array[j] = t;
}
function quantile$1(values, p, valueof) {
values = Float64Array.from(numbers$2(values, valueof));
if (!(n = values.length) || isNaN(p = +p)) return;
if (p <= 0 || n < 2) return min$2(values);
if (p >= 1) return max$2(values);
var n,
i = (n - 1) * p,
i0 = Math.floor(i),
value0 = max$2(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$6) {
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 mean(values, valueof) {
let count = 0;
let sum = 0;
if (valueof === undefined) {
for (let value of values) {
if (value != null && (value = +value) >= value) {
++count, sum += value;
}
}
} else {
let index = -1;
for (let value of values) {
if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {
++count, sum += value;
}
}
}
if (count) return sum / count;
}
function median(values, valueof) {
return quantile$1(values, 0.5, valueof);
}
function* flatten(arrays) {
for (const array of arrays) {
yield* array;
}
}
function merge$2(arrays) {
return Array.from(flatten(arrays));
}
function range$3(start, stop, step) {
start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
var i = -1,
n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
range = new Array(n);
while (++i < n) {
range[i] = start + i * step;
}
return range;
}
function sum$1(values, valueof) {
let sum = 0;
{
for (let value of values) {
if (value = +value) {
sum += value;
}
}
}
return sum;
}
function intersection(values, ...others) {
values = new InternSet(values);
others = others.map(set$4);
out: for (const value of values) {
for (const other of others) {
if (!other.has(value)) {
values.delete(value);
continue out;
}
}
}
return values;
}
function set$4(values) {
return values instanceof InternSet ? values : new InternSet(values);
}
function union(...others) {
const set = new InternSet();
for (const other of others) {
for (const o of other) {
set.add(o);
}
}
return set;
}
function formatDecimal (x) {
return Math.abs(x = Math.round(x)) >= 1e21 ? x.toLocaleString("en").replace(/,/g, "") : x.toString(10);
}
// Computes the decimal coefficient and exponent of the specified number x with
// significant digits p, where x is positive and p is in [1, 21] or undefined.
// For example, formatDecimalParts(1.23) returns ["123", 0].
function formatDecimalParts(x, p) {
if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
var i,
coefficient = x.slice(0, i);
// The string returned by toExponential either has the form \d\.\d+e[-+]\d+
// (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
return [coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient, +x.slice(i + 1)];
}
function exponent (x) {
return x = formatDecimalParts(Math.abs(x)), x ? x[1] : NaN;
}
function formatGroup (grouping, thousands) {
return function (value, width) {
var i = value.length,
t = [],
j = 0,
g = grouping[0],
length = 0;
while (i > 0 && g > 0) {
if (length + g + 1 > width) g = Math.max(1, width - length);
t.push(value.substring(i -= g, i + g));
if ((length += g + 1) > width) break;
g = grouping[j = (j + 1) % grouping.length];
}
return t.reverse().join(thousands);
};
}
function formatNumerals (numerals) {
return function (value) {
return value.replace(/[0-9]/g, function (i) {
return numerals[+i];
});
};
}
// [[fill]align][sign][symbol][0][width][,][.precision][~][type]
var re = /^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;
function formatSpecifier(specifier) {
if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
var match;
return new FormatSpecifier({
fill: match[1],
align: match[2],
sign: match[3],
symbol: match[4],
zero: match[5],
width: match[6],
comma: match[7],
precision: match[8] && match[8].slice(1),
trim: match[9],
type: match[10]
});
}
formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof
function FormatSpecifier(specifier) {
this.fill = specifier.fill === undefined ? " " : specifier.fill + "";
this.align = specifier.align === undefined ? ">" : specifier.align + "";
this.sign = specifier.sign === undefined ? "-" : specifier.sign + "";
this.symbol = specifier.symbol === undefined ? "" : specifier.symbol + "";
this.zero = !!specifier.zero;
this.width = specifier.width === undefined ? undefined : +specifier.width;
this.comma = !!specifier.comma;
th