datalib
Version:
JavaScript utilites for loading, summarizing and working with data.
1,767 lines (1,521 loc) • 165 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.dl = factory());
}(this, (function () { 'use strict';
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
function getCjsExportFromNamespace (n) {
return n && n.default || n;
}
var util = createCommonjsModule(function (module) {
var u = module.exports;
// utility functions
var FNAME = '__name__';
u.namedfunc = function(name, f) { return (f[FNAME] = name, f); };
u.name = function(f) { return f==null ? null : f[FNAME]; };
u.identity = function(x) { return x; };
u.true = u.namedfunc('true', function() { return true; });
u.false = u.namedfunc('false', function() { return false; });
u.duplicate = function(obj) {
return JSON.parse(JSON.stringify(obj));
};
u.equal = function(a, b) {
return JSON.stringify(a) === JSON.stringify(b);
};
u.extend = function(obj) {
for (var x, name, i=1, len=arguments.length; i<len; ++i) {
x = arguments[i];
for (name in x) { obj[name] = x[name]; }
}
return obj;
};
u.length = function(x) {
return x != null && x.length != null ? x.length : null;
};
u.keys = function(x) {
var keys = [], k;
for (k in x) keys.push(k);
return keys;
};
u.vals = function(x) {
var vals = [], k;
for (k in x) vals.push(x[k]);
return vals;
};
u.toMap = function(list, f) {
return (f = u.$(f)) ?
list.reduce(function(obj, x) { return (obj[f(x)] = 1, obj); }, {}) :
list.reduce(function(obj, x) { return (obj[x] = 1, obj); }, {});
};
u.keystr = function(values) {
// use to ensure consistent key generation across modules
var n = values.length;
if (!n) return '';
for (var s=String(values[0]), i=1; i<n; ++i) {
s += '|' + String(values[i]);
}
return s;
};
// type checking functions
var toString = Object.prototype.toString;
u.isObject = function(obj) {
return obj === Object(obj);
};
u.isFunction = function(obj) {
return toString.call(obj) === '[object Function]';
};
u.isString = function(obj) {
return typeof value === 'string' || toString.call(obj) === '[object String]';
};
u.isArray = Array.isArray || function(obj) {
return toString.call(obj) === '[object Array]';
};
u.isNumber = function(obj) {
return typeof obj === 'number' || toString.call(obj) === '[object Number]';
};
u.isBoolean = function(obj) {
return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
};
u.isDate = function(obj) {
return toString.call(obj) === '[object Date]';
};
u.isValid = function(obj) {
return obj != null && obj === obj;
};
u.isBuffer = (typeof Buffer === 'function' && Buffer.isBuffer) || u.false;
// type coercion functions
u.number = function(s) {
return s == null || s === '' ? null : +s;
};
u.boolean = function(s) {
return s == null || s === '' ? null : s==='false' ? false : !!s;
};
// parse a date with optional d3.time-format format
u.date = function(s, format) {
var d = format ? format : Date;
return s == null || s === '' ? null : d.parse(s);
};
u.array = function(x) {
return x != null ? (u.isArray(x) ? x : [x]) : [];
};
u.str = function(x) {
return u.isArray(x) ? '[' + x.map(u.str) + ']'
: u.isObject(x) || u.isString(x) ?
// Output valid JSON and JS source strings.
// See http://timelessrepo.com/json-isnt-a-javascript-subset
JSON.stringify(x).replace('\u2028','\\u2028').replace('\u2029', '\\u2029')
: x;
};
// data access functions
var field_re = /\[(.*?)\]|[^.\[]+/g;
u.field = function(f) {
return String(f).match(field_re).map(function(d) {
return d[0] !== '[' ? d :
d[1] !== "'" && d[1] !== '"' ? d.slice(1, -1) :
d.slice(2, -2).replace(/\\(["'])/g, '$1');
});
};
u.accessor = function(f) {
/* jshint evil: true */
return f==null || u.isFunction(f) ? f :
u.namedfunc(f, Function('x', 'return x[' + u.field(f).map(u.str).join('][') + '];'));
};
// short-cut for accessor
u.$ = u.accessor;
u.mutator = function(f) {
var s;
return u.isString(f) && (s=u.field(f)).length > 1 ?
function(x, v) {
for (var i=0; i<s.length-1; ++i) x = x[s[i]];
x[s[i]] = v;
} :
function(x, v) { x[f] = v; };
};
u.$func = function(name, op) {
return function(f) {
f = u.$(f) || u.identity;
var n = name + (u.name(f) ? '_'+u.name(f) : '');
return u.namedfunc(n, function(d) { return op(f(d)); });
};
};
u.$valid = u.$func('valid', u.isValid);
u.$length = u.$func('length', u.length);
u.$in = function(f, values) {
f = u.$(f);
var map = u.isArray(values) ? u.toMap(values) : values;
return function(d) { return !!map[f(d)]; };
};
// comparison / sorting functions
u.comparator = function(sort) {
var sign = [];
if (sort === undefined) sort = [];
sort = u.array(sort).map(function(f) {
var s = 1;
if (f[0] === '-') { s = -1; f = f.slice(1); }
else if (f[0] === '+') { s = +1; f = f.slice(1); }
sign.push(s);
return u.accessor(f);
});
return function(a, b) {
var i, n, f, c;
for (i=0, n=sort.length; i<n; ++i) {
f = sort[i];
c = u.cmp(f(a), f(b));
if (c) return c * sign[i];
}
return 0;
};
};
u.cmp = function(a, b) {
return (a < b || a == null) && b != null ? -1 :
(a > b || b == null) && a != null ? 1 :
((b = b instanceof Date ? +b : b),
(a = a instanceof Date ? +a : a)) !== a && b === b ? -1 :
b !== b && a === a ? 1 : 0;
};
u.numcmp = function(a, b) { return a - b; };
u.stablesort = function(array, sortBy, keyFn) {
var indices = array.reduce(function(idx, v, i) {
return (idx[keyFn(v)] = i, idx);
}, {});
array.sort(function(a, b) {
var sa = sortBy(a),
sb = sortBy(b);
return sa < sb ? -1 : sa > sb ? 1
: (indices[keyFn(a)] - indices[keyFn(b)]);
});
return array;
};
// permutes an array using a Knuth shuffle
u.permute = function(a) {
var m = a.length,
swap,
i;
while (m) {
i = Math.floor(Math.random() * m--);
swap = a[m];
a[m] = a[i];
a[i] = swap;
}
};
// string functions
u.pad = function(s, length, pos, padchar) {
padchar = padchar || " ";
var d = length - s.length;
if (d <= 0) return s;
switch (pos) {
case 'left':
return strrep(d, padchar) + s;
case 'middle':
case 'center':
return strrep(Math.floor(d/2), padchar) +
s + strrep(Math.ceil(d/2), padchar);
default:
return s + strrep(d, padchar);
}
};
function strrep(n, str) {
var s = "", i;
for (i=0; i<n; ++i) s += str;
return s;
}
u.truncate = function(s, length, pos, word, ellipsis) {
var len = s.length;
if (len <= length) return s;
ellipsis = ellipsis !== undefined ? String(ellipsis) : '\u2026';
var l = Math.max(0, length - ellipsis.length);
switch (pos) {
case 'left':
return ellipsis + (word ? truncateOnWord(s,l,1) : s.slice(len-l));
case 'middle':
case 'center':
var l1 = Math.ceil(l/2), l2 = Math.floor(l/2);
return (word ? truncateOnWord(s,l1) : s.slice(0,l1)) +
ellipsis + (word ? truncateOnWord(s,l2,1) : s.slice(len-l2));
default:
return (word ? truncateOnWord(s,l) : s.slice(0,l)) + ellipsis;
}
};
function truncateOnWord(s, len, rev) {
var cnt = 0, tok = s.split(truncate_word_re);
if (rev) {
s = (tok = tok.reverse())
.filter(function(w) { cnt += w.length; return cnt <= len; })
.reverse();
} else {
s = tok.filter(function(w) { cnt += w.length; return cnt <= len; });
}
return s.length ? s.join('').trim() : tok[0].slice(0, len);
}
var truncate_word_re = /([\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u2028\u2029\u3000\uFEFF])/;
});
var name = "datalib";
var version = "1.9.3";
var description = "JavaScript utilites for loading, summarizing and working with data.";
var keywords = [
"data",
"table",
"statistics",
"parse",
"csv",
"tsv",
"json",
"utility"
];
var repository = {
type: "git",
url: "http://github.com/vega/datalib.git"
};
var author = {
name: "Jeffrey Heer",
url: "http://idl.cs.washington.edu"
};
var contributors = [
{
name: "Michael Correll",
url: "http://pages.cs.wisc.edu/~mcorrell/"
},
{
name: "Ryan Russell",
url: "https://github.com/RussellSprouts"
},
{
name: "Matthew Conlen",
url: "https://github.com/mathisonian"
}
];
var license = "BSD-3-Clause";
var dependencies = {
"d3-dsv": "0.1",
"d3-format": "0.4",
"d3-time": "0.1",
"d3-time-format": "0.2",
request: "^2.67.0",
"sync-request": "^6.0.0",
"topojson-client": "^3.0.0"
};
var devDependencies = {
chai: "^4.1.2",
istanbul: "latest",
jshint: "^2.9.5",
mocha: "^5.2.0",
rollup: "^0.62.0",
"rollup-plugin-commonjs": "^9.1.3",
"rollup-plugin-json": "^3.0.0",
"rollup-plugin-node-resolve": "^3.3.0",
"uglify-js": "^3.4.3"
};
var main = "src/index.js";
var unpkg = "datalib.min.js";
var jsdelivr = "datalib.min.js";
var scripts = {
deploy: "npm run test && scripts/deploy.sh",
lint: "jshint src/",
test: "npm run lint && TZ=America/Los_Angeles mocha --recursive test/",
cover: "TZ=America/Los_Angeles istanbul cover _mocha -- --recursive test/",
build: "rollup -c",
postbuild: "uglifyjs datalib.js -c -m -o datalib.min.js"
};
var browser = {
buffer: false,
fs: false,
http: false,
request: false,
"sync-request": false,
url: false
};
var _package = {
name: name,
version: version,
description: description,
keywords: keywords,
repository: repository,
author: author,
contributors: contributors,
license: license,
dependencies: dependencies,
devDependencies: devDependencies,
main: main,
unpkg: unpkg,
jsdelivr: jsdelivr,
scripts: scripts,
browser: browser
};
var _package$1 = /*#__PURE__*/Object.freeze({
name: name,
version: version,
description: description,
keywords: keywords,
repository: repository,
author: author,
contributors: contributors,
license: license,
dependencies: dependencies,
devDependencies: devDependencies,
main: main,
unpkg: unpkg,
jsdelivr: jsdelivr,
scripts: scripts,
browser: browser,
default: _package
});
var require$$3 = {};
// Matches absolute URLs with optional protocol
// https://... file://... //...
var protocol_re = /^([A-Za-z]+:)?\/\//;
// Special treatment in node.js for the file: protocol
var fileProtocol = 'file://';
// Validate and cleanup URL to ensure that it is allowed to be accessed
// Returns cleaned up URL, or false if access is not allowed
function sanitizeUrl(opt) {
var url = opt.url;
if (!url && opt.file) { return fileProtocol + opt.file; }
// In case this is a relative url (has no host), prepend opt.baseURL
if (opt.baseURL && !protocol_re.test(url)) {
if (!startsWith(url, '/') && opt.baseURL[opt.baseURL.length-1] !== '/') {
url = '/' + url; // Ensure that there is a slash between the baseURL (e.g. hostname) and url
}
url = opt.baseURL + url;
}
// relative protocol, starts with '//'
if (!load.useXHR && startsWith(url, '//')) {
url = (opt.defaultProtocol || 'http') + ':' + url;
}
// If opt.domainWhiteList is set, only allows url, whose hostname
// * Is the same as the origin (window.location.hostname)
// * Equals one of the values in the whitelist
// * Is a proper subdomain of one of the values in the whitelist
if (opt.domainWhiteList) {
var domain, origin;
if (load.useXHR) {
var a = document.createElement('a');
a.href = url;
// From http://stackoverflow.com/questions/736513/how-do-i-parse-a-url-into-hostname-and-path-in-javascript
// IE doesn't populate all link properties when setting .href with a relative URL,
// however .href will return an absolute URL which then can be used on itself
// to populate these additional fields.
if (a.host === '') {
a.href = a.href;
}
domain = a.hostname.toLowerCase();
origin = window.location.hostname;
} else {
// relative protocol is broken: https://github.com/defunctzombie/node-url/issues/5
var parts = require$$3.parse(url);
domain = parts.hostname;
origin = null;
}
if (origin !== domain) {
var whiteListed = opt.domainWhiteList.some(function(d) {
var idx = domain.length - d.length;
return d === domain ||
(idx > 1 && domain[idx-1] === '.' && domain.lastIndexOf(d) === idx);
});
if (!whiteListed) {
throw 'URL is not whitelisted: ' + url;
}
}
}
return url;
}
function load(opt, callback) {
return load.loader(opt, callback);
}
function loader(opt, callback) {
var error = callback || function(e) { throw e; }, url;
try {
url = load.sanitizeUrl(opt); // enable override
} catch (err) {
error(err);
return;
}
if (!url) {
error('Invalid URL: ' + opt.url);
} else if (load.useXHR) {
// on client, use xhr
return load.xhr(url, opt, callback);
} else if (startsWith(url, fileProtocol)) {
// on server, if url starts with 'file://', strip it and load from file
return load.file(url.slice(fileProtocol.length), opt, callback);
} else if (url.indexOf('://') < 0) { // TODO better protocol check?
// on server, if no protocol assume file
return load.file(url, opt, callback);
} else {
// for regular URLs on server
return load.http(url, opt, callback);
}
}
function xhrHasResponse(request) {
var type = request.responseType;
return type && type !== 'text' ?
request.response : // null on error
request.responseText; // '' on error
}
function xhr(url, opt, callback) {
var async = !!callback;
var request = new XMLHttpRequest();
// If IE does not support CORS, use XDomainRequest (copied from d3.xhr)
if (typeof XDomainRequest !== 'undefined' &&
!('withCredentials' in request) &&
/^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest();
function respond() {
var status = request.status;
if (!status && xhrHasResponse(request) || status >= 200 && status < 300 || status === 304) {
callback(null, request.responseText);
} else {
callback(request, null);
}
}
if (async) {
if ('onload' in request) {
request.onload = request.onerror = respond;
} else {
request.onreadystatechange = function() {
if (request.readyState > 3) respond();
};
}
}
request.open('GET', url, async);
/* istanbul ignore else */
if (request.setRequestHeader) {
var headers = util.extend({}, load.headers, opt.headers);
for (var name in headers) {
request.setRequestHeader(name, headers[name]);
}
}
request.send();
if (!async && xhrHasResponse(request)) {
return request.responseText;
}
}
function file(filename, opt, callback) {
var fs = require$$3;
if (!callback) {
return fs.readFileSync(filename, 'utf8');
}
fs.readFile(filename, callback);
}
function http(url, opt, callback) {
var headers = util.extend({}, load.headers, opt.headers);
var options = {url: url, encoding: null, gzip: true, headers: headers};
if (!callback) {
return require$$3('GET', url, options).getBody();
}
require$$3(options, function(error, response, body) {
if (!error && response.statusCode === 200) {
callback(null, body);
} else {
error = error ||
'Load failed with response code ' + response.statusCode + '.';
callback(error, null);
}
});
}
function startsWith(string, searchString) {
return string == null ? false : string.lastIndexOf(searchString, 0) === 0;
}
// Allow these functions to be overriden by the user of the library
load.loader = loader;
load.sanitizeUrl = sanitizeUrl;
load.xhr = xhr;
load.file = file;
load.http = http;
// Default settings
load.useXHR = (typeof XMLHttpRequest !== 'undefined');
load.headers = {};
var load_1 = load;
var TYPES = '__types__';
var PARSERS = {
boolean: util.boolean,
integer: util.number,
number: util.number,
date: util.date,
string: function(x) { return x == null || x === '' ? null : x + ''; }
};
var TESTS = {
boolean: function(x) { return x==='true' || x==='false' || util.isBoolean(x); },
integer: function(x) { return TESTS.number(x) && (x=+x) === ~~x; },
number: function(x) { return !isNaN(+x) && !util.isDate(x); },
date: function(x) { return !isNaN(Date.parse(x)); }
};
function annotation(data, types) {
if (!types) return data && data[TYPES] || null;
data[TYPES] = types;
}
function fieldNames(datum) {
return util.keys(datum);
}
function bracket(fieldName) {
return '[' + fieldName + ']';
}
function type(values, f) {
values = util.array(values);
f = util.$(f);
var v, i, n;
// if data array has type annotations, use them
if (values[TYPES]) {
v = f(values[TYPES]);
if (util.isString(v)) return v;
}
for (i=0, n=values.length; !util.isValid(v) && i<n; ++i) {
v = f ? f(values[i]) : values[i];
}
return util.isDate(v) ? 'date' :
util.isNumber(v) ? 'number' :
util.isBoolean(v) ? 'boolean' :
util.isString(v) ? 'string' : null;
}
function typeAll(data, fields) {
if (!data.length) return;
var get = fields ? util.identity : (fields = fieldNames(data[0]), bracket);
return fields.reduce(function(types, f) {
return (types[f] = type(data, get(f)), types);
}, {});
}
function infer(values, f, ignore) {
values = util.array(values);
f = util.$(f);
var i, j, v;
// types to test for, in precedence order
var types = ['boolean', 'integer', 'number', 'date'];
for (i=0; i<values.length; ++i) {
// get next value to test
v = f ? f(values[i]) : values[i];
// test value against remaining types
for (j=0; j<types.length; ++j) {
if ((!ignore || !ignore.test(v)) && util.isValid(v) && !TESTS[types[j]](v)) {
types.splice(j, 1);
j -= 1;
}
}
// if no types left, return 'string'
if (types.length === 0) return 'string';
}
return types[0];
}
function inferAll(data, fields, ignore) {
var get = fields ? util.identity : (fields = fieldNames(data[0]), bracket);
return fields.reduce(function(types, f) {
types[f] = infer(data, get(f), ignore);
return types;
}, {});
}
type.annotation = annotation;
type.all = typeAll;
type.infer = infer;
type.inferAll = inferAll;
type.parsers = PARSERS;
var type_1 = type;
var d3Dsv = createCommonjsModule(function (module, exports) {
(function (global, factory) {
factory(exports);
}(commonjsGlobal, function (exports) {
function dsv(delimiter) {
return new Dsv(delimiter);
}
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 Dsv(delimiter) {
var reFormat = new RegExp("[\"" + delimiter + "\n]"),
delimiterCode = delimiter.charCodeAt(0);
this.parse = function(text, f) {
var convert, columns, rows = this.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;
};
this.parseRows = function(text, f) {
var EOL = {}, // sentinel value for end-of-line
EOF = {}, // sentinel value for end-of-file
rows = [], // output rows
N = text.length,
I = 0, // current character index
n = 0, // the current line number
t, // the current token
eol; // is the current token followed by EOL?
function token() {
if (I >= N) return EOF; // special case: end of file
if (eol) return eol = false, EOL; // special case: end of line
// special case: quotes
var j = I, c;
if (text.charCodeAt(j) === 34) {
var i = j;
while (i++ < N) {
if (text.charCodeAt(i) === 34) {
if (text.charCodeAt(i + 1) !== 34) break;
++i;
}
}
I = i + 2;
c = text.charCodeAt(i + 1);
if (c === 13) {
eol = true;
if (text.charCodeAt(i + 2) === 10) ++I;
} else if (c === 10) {
eol = true;
}
return text.slice(j + 1, i).replace(/""/g, "\"");
}
// common case: find next delimiter or newline
while (I < N) {
var k = 1;
c = text.charCodeAt(I++);
if (c === 10) eol = true; // \n
else if (c === 13) { eol = true; if (text.charCodeAt(I) === 10) ++I, ++k; } // \r|\r\n
else if (c !== delimiterCode) continue;
return text.slice(j, I - k);
}
// special case: last token before EOF
return text.slice(j);
}
while ((t = token()) !== EOF) {
var a = [];
while (t !== EOL && t !== EOF) {
a.push(t);
t = token();
}
if (f && (a = f(a, n++)) == null) continue;
rows.push(a);
}
return rows;
};
this.format = function(rows, columns) {
if (columns == null) columns = inferColumns(rows);
return [columns.map(formatValue).join(delimiter)].concat(rows.map(function(row) {
return columns.map(function(column) {
return formatValue(row[column]);
}).join(delimiter);
})).join("\n");
};
this.formatRows = function(rows) {
return rows.map(formatRow).join("\n");
};
function formatRow(row) {
return row.map(formatValue).join(delimiter);
}
function formatValue(text) {
return reFormat.test(text) ? "\"" + text.replace(/\"/g, "\"\"") + "\"" : text;
}
}
dsv.prototype = Dsv.prototype;
var csv = dsv(",");
var tsv = dsv("\t");
var version = "0.1.14";
exports.version = version;
exports.dsv = dsv;
exports.csv = csv;
exports.tsv = tsv;
}));
});
function dsv(data, format) {
if (data) {
var h = format.header;
data = (h ? h.join(format.delimiter) + '\n' : '') + data;
}
return d3Dsv.dsv(format.delimiter).parse(data);
}
dsv.delimiter = function(delim) {
var fmt = {delimiter: delim};
return function(data, format) {
return dsv(data, format ? util.extend(format, fmt) : fmt);
};
};
var dsv_1 = dsv;
var json = function(data, format) {
var d = util.isObject(data) && !util.isBuffer(data) ?
data : JSON.parse(data);
if (format && format.property) {
d = util.accessor(format.property)(d);
}
return d;
};
function identity(x) {
return x;
}
function transform(transform) {
if (transform == null) return identity;
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 bbox(topology) {
var t = transform(topology.transform), key,
x0 = Infinity, y0 = x0, x1 = -x0, y1 = -x0;
function bboxPoint(p) {
p = t(p);
if (p[0] < x0) x0 = p[0];
if (p[0] > x1) x1 = p[0];
if (p[1] < y0) y0 = p[1];
if (p[1] > y1) y1 = p[1];
}
function bboxGeometry(o) {
switch (o.type) {
case "GeometryCollection": o.geometries.forEach(bboxGeometry); break;
case "Point": bboxPoint(o.coordinates); break;
case "MultiPoint": o.coordinates.forEach(bboxPoint); break;
}
}
topology.arcs.forEach(function(arc) {
var i = -1, n = arc.length, p;
while (++i < n) {
p = t(arc[i], i);
if (p[0] < x0) x0 = p[0];
if (p[0] > x1) x1 = p[0];
if (p[1] < y0) y0 = p[1];
if (p[1] > y1) y1 = p[1];
}
});
for (key in topology.objects) {
bboxGeometry(topology.objects[key]);
}
return [x0, y0, x1, y1];
}
function reverse(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(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(topology, o) {
var transformPoint = transform(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(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(topology, meshArcs.apply(this, arguments));
}
function meshArcs(topology, object$$1, filter) {
var arcs, i, n;
if (arguments.length > 1) arcs = extractArcs(topology, object$$1, 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$$1, 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$$1);
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 planarRingArea(ring) {
var i = -1, n = ring.length, a, b = ring[n - 1], area = 0;
while (++i < n) a = b, b = ring[i], area += a[0] * b[1] - a[1] * b[0];
return Math.abs(area); // Note: doubled area!
}
function merge(topology) {
return object(topology, mergeArcs.apply(this, arguments));
}
function mergeArcs(topology, objects) {
var polygonsByArc = {},
polygons = [],
groups = [];
objects.forEach(geometry);
function geometry(o) {
switch (o.type) {
case "GeometryCollection": o.geometries.forEach(geometry); break;
case "Polygon": extract(o.arcs); break;
case "MultiPolygon": o.arcs.forEach(extract); break;
}
}
function extract(polygon) {
polygon.forEach(function(ring) {
ring.forEach(function(arc) {
(polygonsByArc[arc = arc < 0 ? ~arc : arc] || (polygonsByArc[arc] = [])).push(polygon);
});
});
polygons.push(polygon);
}
function area(ring) {
return planarRingArea(object(topology, {type: "Polygon", arcs: [ring]}).coordinates[0]);
}
polygons.forEach(function(polygon) {
if (!polygon._) {
var group = [],
neighbors = [polygon];
polygon._ = 1;
groups.push(group);
while (polygon = neighbors.pop()) {
group.push(polygon);
polygon.forEach(function(ring) {
ring.forEach(function(arc) {
polygonsByArc[arc < 0 ? ~arc : arc].forEach(function(polygon) {
if (!polygon._) {
polygon._ = 1;
neighbors.push(polygon);
}
});
});
});
}
}
});
polygons.forEach(function(polygon) {
delete polygon._;
});
return {
type: "MultiPolygon",
arcs: groups.map(function(polygons) {
var arcs = [], n;
// Extract the exterior (unique) arcs.
polygons.forEach(function(polygon) {
polygon.forEach(function(ring) {
ring.forEach(function(arc) {
if (polygonsByArc[arc < 0 ? ~arc : arc].length < 2) {
arcs.push(arc);
}
});
});
});
// Stitch the arcs into one or more rings.
arcs = stitch(topology, arcs);
// If more than one ring is returned,
// at most one of these rings can be the exterior;
// choose the one with the greatest absolute area.
if ((n = arcs.length) > 1) {
for (var i = 1, k = area(arcs[0]), ki, t; i < n; ++i) {
if ((ki = area(arcs[i])) > k) {
t = arcs[0], arcs[0] = arcs[i], arcs[i] = t, k = ki;
}
}
}
return arcs;
}).filter(function(arcs) {
return arcs.length > 0;
})
};
}
function bisect(a, x) {
var lo = 0, hi = a.length;
while (lo < hi) {
var mid = lo + hi >>> 1;
if (a[mid] < x) lo = mid + 1;
else hi = mid;
}
return lo;
}
function neighbors(objects) {
var indexesByArc = {}, // arc index -> array of object indexes
neighbors = objects.map(function() { return []; });
function line(arcs, i) {
arcs.forEach(function(a) {
if (a < 0) a = ~a;
var o = indexesByArc[a];
if (o) o.push(i);
else indexesByArc[a] = [i];
});
}
function polygon(arcs, i) {
arcs.forEach(function(arc) { line(arc, i); });
}
function geometry(o, i) {
if (o.type === "GeometryCollection") o.geometries.forEach(function(o) { geometry(o, i); });
else if (o.type in geometryType) geometryType[o.type](o.arcs, i);
}
var geometryType = {
LineString: line,
MultiLineString: polygon,
Polygon: polygon,
MultiPolygon: function(arcs, i) { arcs.forEach(function(arc) { polygon(arc, i); }); }
};
objects.forEach(geometry);
for (var i in indexesByArc) {
for (var indexes = indexesByArc[i], m = indexes.length, j = 0; j < m; ++j) {
for (var k = j + 1; k < m; ++k) {
var ij = indexes[j], ik = indexes[k], n;
if ((n = neighbors[ij])[i = bisect(n, ik)] !== ik) n.splice(i, 0, ik);
if ((n = neighbors[ik])[i = bisect(n, ij)] !== ij) n.splice(i, 0, ij);
}
}
}
return neighbors;
}
function untransform(transform) {
if (transform == null) return identity;
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),
x1 = Math.round((input[0] - dx) / kx),
y1 = Math.round((input[1] - dy) / ky);
output[0] = x1 - x0, x0 = x1;
output[1] = y1 - y0, y0 = y1;
while (j < n) output[j] = input[j], ++j;
return output;
};
}
function quantize(topology, transform) {
if (topology.transform) throw new Error("already quantized");
if (!transform || !transform.scale) {
if (!((n = Math.floor(transform)) >= 2)) throw new Error("n must be ≥2");
box = topology.bbox || bbox(topology);
var x0 = box[0], y0 = box[1], x1 = box[2], y1 = box[3], n;
transform = {scale: [x1 - x0 ? (x1 - x0) / (n - 1) : 1, y1 - y0 ? (y1 - y0) / (n - 1) : 1], translate: [x0, y0]};
} else {
box = topology.bbox;
}
var t = untransform(transform), box, key, inputs = topology.objects, outputs = {};
function quantizePoint(point) {
return t(point);
}
function quantizeGeometry(input) {
var output;
switch (input.type) {
case "GeometryCollection": output = {type: "GeometryCollection", geometries: input.geometries.map(quantizeGeometry)}; break;
case "Point": output = {type: "Point", coordinates: quantizePoint(input.coordinates)}; break;
case "MultiPoint": output = {type: "MultiPoint", coordinates: input.coordinates.map(quantizePoint)}; break;
default: return input;
}
if (input.id != null) output.id = input.id;
if (input.bbox != null) output.bbox = input.bbox;
if (input.properties != null) output.properties = input.properties;
return output;
}
function quantizeArc(input) {
var i = 0, j = 1, n = input.length, p, output = new Array(n); // pessimistic
output[0] = t(input[0], 0);
while (++i < n) if ((p = t(input[i], i))[0] || p[1]) output[j++] = p; // non-coincident points
if (j === 1) output[j++] = [0, 0]; // an arc must have at least two points
output.length = j;
return output;
}
for (key in inputs) outputs[key] = quantizeGeometry(inputs[key]);
return {
type: "Topology",
bbox: box,
transform: transform,
objects: outputs,
arcs: topology.arcs.map(quantizeArc)
};
}
var src = /*#__PURE__*/Object.freeze({
bbox: bbox,
feature: feature,
mesh: mesh,
meshArcs: meshArcs,
merge: merge,
mergeArcs: mergeArcs,
neighbors: neighbors,
quantize: quantize,
transform: transform,
untransform: untransform
});
var reader = function(data, format) {
var topojson = reader.topojson;
if (topojson == null) { throw Error('TopoJSON library not loaded.'); }
var t = json(data, format), obj;
if (format && format.feature) {
if ((obj = t.objects[format.feature])) {
return topojson.feature(t, obj).features;
} else {
throw Error('Invalid TopoJSON object: ' + format.feature);
}
} else if (format && format.mesh) {
if ((obj = t.objects[format.mesh])) {
return [topojson.mesh(t, t.objects[format.mesh])];
} else {
throw Error('Invalid TopoJSON object: ' + format.mesh);
}
} else {
throw Error('Missing TopoJSON feature or mesh parameter.');
}
};
reader.topojson = src;
var topojson = reader;
var treejson = function(tree, format) {
return toTable(json(tree, format), format);
};
function toTable(root, fields) {
var childrenField = fields && fields.children || 'children',
parentField = fields && fields.parent || 'parent',
table = [];
function visit(node, parent) {
node[parentField] = parent;
table.push(node);
var children = node[childrenField];
if (children) {
for (var i=0; i<children.length; ++i) {
visit(children[i], node);
}
}
}
visit(root, null);
return (table.root = root, table);
}
var formats = {
json: json,
topojson: topojson,
treejson: treejson,
dsv: dsv_1,
csv: dsv_1.delimiter(','),
tsv: dsv_1.delimiter('\t')
};
var d3Time = createCommonjsModule(function (module, exports) {
(function (global, factory) {
factory(exports);
}(commonjsGlobal, function (exports) {
var t0 = new Date;
var t1 = new Date;
function newInterval(floori, offseti, count, field) {
function interval(date) {
return floori(date = new Date(+date)), date;
}
interval.floor = interval;
interval.round = function(date) {
var d0 = new Date(+date),
d1 = new Date(date - 1);
floori(d0), floori(d1), offseti(d1, 1);
return date - d0 < d1 - date ? d0 : d1;
};
interval.ceil = function(date) {
return floori(date = new Date(date - 1)), offseti(date, 1), date;
};
interval.offset = function(date, step) {
return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date;
};
interval.range = function(start, stop, step) {
var range = [];
start = new Date(start - 1);
stop = new Date(+stop);
step = step == null ? 1 : Math.floor(step);
if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date
offseti(start, 1), floori(start);
if (start < stop) range.push(new Date(+start));
while (offseti(start, step), floori(start), start < stop) range.push(new Date(+start));
return range;
};
interval.filter = function(test) {
return newInterval(function(date) {
while (floori(date), !test(date)) date.setTime(date - 1);
}, function(date, step) {
while (--step >= 0) while (offseti(date, 1), !test(date));
});
};
if (count) {
interval.count = function(start, end) {
t0.setTime(+start), t1.setTime(+end);
floori(t0), floori(t1);
return Math.floor(count(t0, t1));
};
interval.every = function(step) {
step = Math.floor(step);
return !isFinite(step) || !(step > 0) ? null
: !(step > 1) ? interval
: interval.filter(field
? function(d) { return field(d) % step === 0; }
: function(d) { return interval.count(0, d) % step === 0; });
};
}
return interval;
}
var millisecond = newInterval(function() {
// noop
}, function(date, step) {
date.setTime(+date + step);
}, function(start, end) {
return end - start;
});
// An optimized implementation for this simple case.
millisecond.every = function(k) {
k = Math.floor(k);
if (!isFinite(k) || !(k > 0)) return null;
if (!(k > 1)) return millisecond;
return newInterval(function(date) {
date.setTime(Math.floor(date / k) * k);
}, function(date, step) {
date.setTime(+date + step * k);
}, function(start, end) {
return (end - start) / k;
});
};
var second = newInterval(function(date) {
date.setMilliseconds(0);
}, function(date, step) {
date.setTime(+date + step * 1e3);
}, function(start, end) {
return (end - start) / 1e3;
}, function(date) {
return date.getSeconds();
});
var minute = newInterval(function(date) {
date.setSeconds(0, 0);
}, function(date, step) {
date.setTime(+date + step * 6e4);
}, function(start, end) {
return (end - start) / 6e4;
}, function(date) {
return date.getMinutes();
});
var hour = newInterval(function(date) {
date.setMinutes(0, 0, 0);
}, function(date, step) {
date.setTime(+date + step * 36e5);
}, function(start, end) {
return (end - start) / 36e5;
}, function(date) {
return date.getHours();
});
var day = newInterval(function(date) {
date.setHours(0, 0, 0, 0);
}, function(date, step) {
date.setDate(date.getDate() + step);
}, function(start, end) {
return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * 6e4) / 864e5;
}, function(date) {
return date.getDate() - 1;
});
function weekday(i) {
return newInterval(function(date) {
date.setHours(0, 0, 0, 0);
date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7);
}, function(date, step) {
date.setDate(date.getDate() + step * 7);
}, function(start, end) {
return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * 6e4) / 6048e5;
});
}
var sunday = weekday(0);
var monday = weekday(1);
var tuesday = weekday(2);
var wednesday = weekday(3);
var thursday = weekday(4);
var friday = weekday(5);
var saturday = weekday(6);
var month = newInterval(function(date) {
date.setHours(0, 0, 0, 0);
date.setDate(1);
}, function(date, step) {
date.setMonth(date.getMonth() + step);
}, function(start, end) {
return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12;
}, function(date) {
return date.getMonth();
});
var year = newInterval(function(date) {
date.setHours(0, 0, 0, 0);
date.setMonth(0, 1);
}, function(date, step) {
date.setFullYear(date.getFullYear() + step);
}, function(start, end) {
return end.getFullYear() - start.getFullYear();
}, function(date) {
return date.getFullYear();
});
var utcSecond = newInterval(function(date) {
date.setUTCMilliseconds(0);
}, function(date, step) {
date.setTime(+date + step * 1e3);
}, function(start, end) {
return (end - start) / 1e3;
}, function(date) {
return date.getUTCSeconds();
});
var utcMinute = newInterval(function(date) {
date.setUTCSeconds(0, 0);
}, function(date, step) {
date.setTime(+date + step * 6e4);
}, function(start, end) {
return (end - start) / 6e4;
}, function(date) {
return date.getUTCMinutes();
});
var utcHour = newInterval(function(date) {
date.setUTCMinutes(0, 0, 0);
}, function(date, step) {
date.setTime(+date + step * 36e5);
}, function(start, end) {
return (end - start) / 36e5;
}, function(date) {
return date.getUTCHours();
});
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) / 864e5;
}, function(date) {
return date.getUTCDate() - 1;
});
function utcWeekday(i) {
return newInterval(function(date) {
date.setUTCHours(0, 0, 0, 0);
date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7);
}, function(date, step) {
date.setUTCDate(date.getUTCDate() + step * 7);
}, function(start, end) {
return (end - start) / 6048e5;
});
}
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 utcMonth = newInterval(function(date) {
date.setUTCHours(0, 0, 0, 0);
date.setUTCDate(1);
}, 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 utcYear = newInterval(function(date) {
date.setUTCHours(0, 0, 0, 0);
date.setUTCMonth(0, 1);
}, function(date, step) {
date.setUTCFullYear(date.getUTCFullYear() + step);
}, function(start, end) {
return end.getUTCFullYear() - start.getUTCFullYear();
}, function(date) {
return date.getUTCFullYear();
});
var milliseconds = millisecond.range;
var seconds = second.range;
var minutes = minute.range;
var hours = hour.range;
var days = day.range;
var sundays = sunday.range;
var mondays = monday.range;
var tuesdays = tuesday.range;
var wednesdays = wednesday.range;
var thursdays = thursday.range;
var fridays = friday.range;
var saturdays = saturday.range;
var weeks = sunday.range;
var months = month.range;
var years = year.range;
var utcMillisecond = millisecond;
var utcMilliseconds = milliseconds;
var utcSeconds = utcSecond.range;
var utcMinutes = utcMinute.range;
var utcHours = utcHour.range;
var utcDays = utcDay.range;
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 utcWeeks = utcSunday.range;
var utcMonths = utcMonth.range;
var utcYears = utcYear.range;
var version = "0.1.1";
exports.version = version;
exports.milliseconds = milliseconds;
exports.seconds = seconds;
exports.minutes = minutes;
exports.hours = hours;
exports.days = days;
exports.sundays = sundays;
exports.mondays = mondays;
exports.tuesdays = tuesdays;
exports.wednesdays = wednesdays;
exports.thursdays = thursdays;
exports.fridays = fridays;
exports.saturdays = saturdays;
exports.weeks = weeks;
exports.months = months;
exports.years = years;
exports.utcMillisecond = utcMillisecond;
exports.utcMilliseconds = utcMilliseconds;
exports.utcSeconds = utcSeconds;
exports.utcMinutes = utcMinutes;
exports.utcHours = utcHours;
exports.utcDays = utcDays;
exports.utcSundays = utcSundays;
exports.utcMondays = utcMondays;
exports.utcTuesdays = utcTuesdays;
exports.utcWednesdays = utcWednesdays;
exports.utcThursdays = utcThursdays;
exports.utcFridays = utcFridays;