(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (factory((global.vega = global.vega || {}))); }(this, (function (exports) { 'use strict'; var accessor = function(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; } var error$1 = function(message) { throw Error(message); }; var splitAccessPath = function(p) { var path = [], q = null, b = 0, n = p.length, s = '', i, j, c; p = p + ''; function push() { path.push(s + p.substring(i, j)); s = ''; i = j + 1; } for (i=j=0; j i) { push(); } else { i = j + 1; } } else if (c === '[') { if (j > i) push(); b = i = j + 1; } else if (c === ']') { if (!b) error$1('Access path missing open bracket: ' + p); if (b > 0) push(); b = 0; i = j + 1; } } if (b) error$1('Access path missing closing bracket: ' + p); if (q) error$1('Access path missing closing quote: ' + p); if (j > i) { j++; push(); } return path; }; var isArray = Array.isArray; var isObject = function(_) { return _ === Object(_); }; var isString = function(_) { return typeof _ === 'string'; }; function $(x) { return isArray(x) ? '[' + x.map($) + ']' : isObject(x) || 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; } var field = function(field, name) { var path = splitAccessPath(field), code = 'return _[' + path.map($).join('][') + '];'; return accessor( Function('_', code), [(field = path.length===1 ? path[0] : field)], name || field ); }; var empty = []; var id = field('id'); var identity = accessor(function(_) { return _; }, empty, 'identity'); var zero = accessor(function() { return 0; }, empty, 'zero'); var one = accessor(function() { return 1; }, empty, 'one'); var truthy = accessor(function() { return true; }, empty, 'true'); var falsy = accessor(function() { return false; }, empty, 'false'); function log(method, level, input) { var args = [level].concat([].slice.call(input)); console[method].apply(console, args); // eslint-disable-line no-console } var None = 0; var Error$1 = 1; var Warn = 2; var Info = 3; var Debug = 4; var logger = function(_) { var level = _ || None; return { level: function(_) { if (arguments.length) { level = +_; return this; } else { return level; } }, error: function() { if (level >= Error$1) log('error', 'ERROR', arguments); return this; }, warn: function() { if (level >= Warn) log('warn', 'WARN', arguments); return this; }, info: function() { if (level >= Info) log('log', 'INFO', arguments); return this; }, debug: function() { if (level >= Debug) log('log', 'DEBUG', arguments); return this; } } }; var array = function(_) { return _ != null ? (isArray(_) ? _ : [_]) : []; }; var isFunction = function(_) { return typeof _ === 'function'; }; var compare = function(fields, orders) { var idx = [], cmp = (fields = array(fields)).map(function(f, i) { if (f == null) { return null; } else { idx.push(i); return isFunction(f) ? f : splitAccessPath(f).map($).join(']['); } }), n = idx.length - 1, ord = array(orders), code = 'var u,v;return ', i, j, f, u, v, d, t, lt, gt; if (n < 0) return null; for (j=0; j<=n; ++j) { i = idx[j]; f = cmp[i]; if (isFunction(f)) { d = 'f' + i; u = '(u=this.' + d + '(a))'; v = '(v=this.' + d + '(b))'; (t = t || {})[d] = f; } else { u = '(u=a['+f+'])'; v = '(v=b['+f+'])'; } d = '((v=v instanceof Date?+v:v),(u=u instanceof Date?+u:u))'; if (ord[i] !== 'descending') { gt = 1; lt = -1; } else { gt = -1; lt = 1; } code += '(' + u+'<'+v+'||u==null)&&v!=null?' + lt + ':(u>v||v==null)&&u!=null?' + gt + ':'+d+'!==u&&v===v?' + lt + ':v!==v&&u===u?' + gt + (i < n ? ':' : ':0'); } f = Function('a', 'b', code + ';'); if (t) f = f.bind(t); fields = fields.reduce(function(map, field) { if (isFunction(field)) { (accessorFields(field) || []).forEach(function(_) { map[_] = 1; }); } else if (field != null) { map[field + ''] = 1; } return map; }, {}); return accessor(f, Object.keys(fields)); }; var constant = function(_) { return isFunction(_) ? _ : function() { return _; }; }; var debounce = function(delay, handler) { var tid, evt; function callback() { handler(evt); tid = evt = null; } return function(e) { evt = e; if (tid) clearTimeout(tid); tid = setTimeout(callback, delay); }; }; var extend = function(_) { for (var x, k, i=1, len=arguments.length; i= b) { a = c = b; break; } } 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; } } 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]; }; var NULL = {}; var fastmap = function(input) { var obj = {}, map, test; function has(key) { return obj.hasOwnProperty(key) && obj[key] !== NULL; } map = { size: 0, empty: 0, object: obj, has: has, get: function(key) { return has(key) ? obj[key] : undefined; }, set: function(key, value) { if (!has(key)) { ++map.size; if (obj[key] === NULL) --map.empty; } obj[key] = value; return this; }, delete: function(key) { if (has(key)) { --map.size; ++map.empty; obj[key] = NULL; } return this; }, clear: function() { map.size = map.empty = 0; map.object = obj = {}; }, test: function(_) { if (arguments.length) { test = _; return map; } else { return test; } }, clean: function() { var next = {}, size = 0, key, value; for (key in obj) { 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(function(key) { map.set(key, input[key]); }); return map; }; var inherits = function(child, parent) { var proto = (child.prototype = Object.create(parent.prototype)); proto.constructor = child; return proto; }; var isBoolean = function(_) { return typeof _ === 'boolean'; }; var isDate = function(_) { return Object.prototype.toString.call(_) === '[object Date]'; }; var isNumber = function(_) { return typeof _ === 'number'; }; var isRegExp = function(_) { return Object.prototype.toString.call(_) === '[object RegExp]'; }; var key = function(fields) { fields = fields ? array(fields) : fields; var fn = !(fields && fields.length) ? function() { return ''; } : Function('_', 'return \'\'+' + fields.map(function(f) { return '_[' + splitAccessPath(f).map($).join('][') + ']'; }).join('+\'|\'+') + ';'); return accessor(fn, fields, 'key'); }; var merge = function(compare, array0, array1, output) { var n0 = array0.length, n1 = array1.length; if (!n1) return array0; if (!n0) return array1; var merged = output || new array0.constructor(n0 + n1), i0 = 0, i1 = 0, i = 0; for (; i0 0 ? array1[i1++] : array0[i0++]; } for (; i0= 0) s += str; return s; }; var pad = function(str, length, padchar, align) { var 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); }; var peek = function(array) { return array[array.length - 1]; }; var toBoolean = function(_) { return _ == null || _ === '' ? null : !_ || _ === 'false' || _ === '0' ? false : !!_; }; function defaultParser(_) { return isNumber(_) ? _ : isDate(_) ? _ : Date.parse(_); } var toDate = function(_, parser) { parser = parser || defaultParser; return _ == null || _ === '' ? null : parser(_); }; var toNumber = function(_) { return _ == null || _ === '' ? null : +_; }; var toString = function(_) { return _ == null || _ === '' ? null : _ + ''; }; var toSet = function(_) { for (var s={}, i=0, n=_.length; i= 0) { list.splice(idx, 1); } } return list; }; return list; } var TUPLE_ID_KEY = Symbol('vega_id'); var TUPLE_ID = 1; /** * Resets the internal tuple id counter to one. */ /** * Checks if an input value is a registered tuple. * @param {*} t - The value to check. * @return {boolean} True if the input is a tuple, false otherwise. */ function isTuple(t) { return !!(t && tupleid(t)); } /** * Returns the id of a tuple. * @param {object} t - The input tuple. * @return {*} the tuple id. */ function tupleid(t) { return t[TUPLE_ID_KEY]; } /** * Sets the id of a tuple. * @param {object} t - The input tuple. * @param {*} id - The id value to set. * @return {object} the input tuple. */ function setid(t, id) { t[TUPLE_ID_KEY] = id; return t; } /** * Ingest an object or value as a data tuple. * If the input value is an object, an id field will be added to it. For * efficiency, the input object is modified directly. A copy is not made. * If the input value is a literal, it will be wrapped in a new object * instance, with the value accessible as the 'data' property. * @param datum - The value to ingest. * @return {object} The ingested data tuple. */ function ingest(datum) { var t = (datum === Object(datum)) ? datum : {data: datum}; return tupleid(t) ? t : setid(t, TUPLE_ID++); } /** * Given a source tuple, return a derived copy. * @param {object} t - The source tuple. * @return {object} The derived tuple. */ function derive(t) { return rederive(t, ingest({})); } /** * Rederive a derived tuple by copying values from the source tuple. * @param {object} t - The source tuple. * @param {object} d - The derived tuple. * @return {object} The derived tuple. */ function rederive(t, d) { for (var k in t) d[k] = t[k]; return d; } /** * Replace an existing tuple with a new tuple. * @param {object} t - The existing data tuple. * @param {object} d - The new tuple that replaces the old. * @return {object} The new tuple. */ function replace(t, d) { return setid(d, tupleid(t)); } function isChangeSet(v) { return v && v.constructor === changeset; } function changeset() { var add = [], // insert tuples rem = [], // remove tuples mod = [], // modify tuples remp = [], // remove by predicate modp = [], // modify by predicate reflow = false; return { constructor: changeset, insert: function(t) { var d = array(t), i = 0, n = d.length; for (; i= 0) { if (v[index] !== value || force) { v[index] = value; mod[index + ':' + name] = -1; mod[name] = -1; } } else if (v !== value || force) { o[name] = value; mod[name] = isArray(value) ? 1 + value.length : -1; } return o; }; /** * Tests if one or more parameters has been modified. If invoked with no * arguments, returns true if any parameter value has changed. If the first * argument is array, returns trues if any parameter name in the array has * changed. Otherwise, tests if the given name and optional array index has * changed. * @param {string} name - The parameter name to test. * @param {number} [index=undefined] - The parameter array index to test. * @return {boolean} - Returns true if a queried parameter was modified. */ prototype$2.modified = function(name, index) { var mod = this[CACHE], k; if (!arguments.length) { for (k in mod) { if (mod[k]) return true; } return false; } else if (isArray(name)) { for (k=0; k= 0) ? (index + 1 < mod[name] || !!mod[index + ':' + name]) : !!mod[name]; }; /** * Clears the modification records. After calling this method, * all parameters are considered unmodified. */ prototype$2.clear = function() { this[CACHE] = {}; return this; }; var OP_ID = 0; var PULSE = 'pulse'; var NO_PARAMS = new Parameters(); // Boolean Flags var SKIP = 1; var MODIFIED = 2; /** * An Operator is a processing node in a dataflow graph. * Each operator stores a value and an optional value update function. * Operators can accept a hash of named parameters. Parameter values can * either be direct (JavaScript literals, arrays, objects) or indirect * (other operators whose values will be pulled dynamically). Operators * included as parameters will have this operator added as a dependency. * @constructor * @param {*} [init] - The initial value for this operator. * @param {function(object, Pulse)} [update] - An update function. Upon * evaluation of this operator, the update function will be invoked and the * return value will be used as the new value of this operator. * @param {object} [params] - The parameters for this operator. * @param {boolean} [react=true] - Flag indicating if this operator should * listen for changes to upstream operators included as parameters. * @see parameters */ function Operator(init, update, params, react) { this.id = ++OP_ID; this.value = init; this.stamp = -1; this.rank = -1; this.qrank = -1; this.flags = 0; if (update) { this._update = update; } if (params) this.parameters(params, react); } var prototype$1 = Operator.prototype; /** * Returns a list of target operators dependent on this operator. * If this list does not exist, it is created and then returned. * @return {UniqueList} */ prototype$1.targets = function() { return this._targets || (this._targets = UniqueList(id)); }; /** * Sets the value of this operator. * @param {*} value - the value to set. * @return {Number} Returns 1 if the operator value has changed * according to strict equality, returns 0 otherwise. */ prototype$1.set = function(value) { if (this.value !== value) { this.value = value; return 1; } else { return 0; } }; function flag(bit) { return function(state) { var f = this.flags; if (arguments.length === 0) return !!(f & bit); this.flags = state ? (f | bit) : (f & ~bit); return this; }; } /** * Indicates that operator evaluation should be skipped on the next pulse. * This operator will still propagate incoming pulses, but its update function * will not be invoked. The skip flag is reset after every pulse, so calling * this method will affect processing of the next pulse only. */ prototype$1.skip = flag(SKIP); /** * Indicates that this operator's value has been modified on its most recent * pulse. Normally modification is checked via strict equality; however, in * some cases it is more efficient to update the internal state of an object. * In those cases, the modified flag can be used to trigger propagation. Once * set, the modification flag persists across pulses until unset. The flag can * be used with the last timestamp to test if a modification is recent. */ prototype$1.modified = flag(MODIFIED); /** * Sets the parameters for this operator. The parameter values are analyzed for * operator instances. If found, this operator will be added as a dependency * of the parameterizing operator. Operator values are dynamically marshalled * from each operator parameter prior to evaluation. If a parameter value is * an array, the array will also be searched for Operator instances. However, * the search does not recurse into sub-arrays or object properties. * @param {object} params - A hash of operator parameters. * @param {boolean} [react=true] - A flag indicating if this operator should * automatically update (react) when parameter values change. In other words, * this flag determines if the operator registers itself as a listener on * any upstream operators included in the parameters. * @return {Operator[]} - An array of upstream dependencies. */ prototype$1.parameters = function(params, react) { react = react !== false; var self = this, argval = (self._argval = self._argval || new Parameters()), argops = (self._argops = self._argops || []), deps = [], name, value, n, i; function add(name, index, value) { if (value instanceof Operator) { if (value !== self) { if (react) value.targets().add(self); deps.push(value); } argops.push({op:value, name:name, index:index}); } else { argval.set(name, index, value); } } for (name in params) { value = params[name]; if (name === PULSE) { array(value).forEach(function(op) { if (!(op instanceof Operator)) { error$1('Pulse parameters must be operator instances.'); } else if (op !== self) { op.targets().add(self); deps.push(op); } }); self.source = value; } else if (isArray(value)) { argval.set(name, -1, Array(n = value.length)); for (i=0; i} - The source operators that should propagate * to the target operator. */ var connect = function(target, sources) { var targetRank = target.rank, i, n; for (i=0, n=sources.length; i pause) { t = now; return 1; } else { return 0; } }); }; prototype$3.debounce = function(delay) { var s = stream(); this.targets().add(stream(null, null, debounce(delay, function(e) { var df = e.dataflow; s.receive(e); if (df && df.run) df.run(); }) )); return s; }; prototype$3.between = function(a, b) { var active = false; a.targets().add(stream(null, null, function() { active = true; })); b.targets().add(stream(null, null, function() { active = false; })); return this.filter(function() { return active; }); }; /** * Create a new event stream from an event source. * @param {object} source - The event source to monitor. The input must * support the addEventListener method. * @param {string} type - The event type. * @param {function(object): boolean} [filter] - Event filter function. * @param {function(object): *} [apply] - Event application function. * If provided, this function will be invoked and the result will be * used as the downstream event value. * @return {EventStream} */ var events = function(source, type, filter, apply) { var df = this, s = stream(filter, apply), send = function(e) { e.dataflow = df; try { s.receive(e); } catch (error) { df.error(error); } finally { df.run(); } }, sources; if (typeof source === 'string' && typeof document !== 'undefined') { sources = document.querySelectorAll(source); } else { sources = array(source); } for (var i=0, n=sources.length; i= keys.length) { if (sortValues != null) array.sort(sortValues); return rollup != null ? rollup(array) : array; } var i = -1, n = array.length, key = keys[depth++], keyValue, value, valuesByKey = map(), values, result = createResult(); while (++i < n) { if (values = valuesByKey.get(keyValue = key(value = array[i]) + "")) { values.push(value); } else { valuesByKey.set(keyValue, [value]); } } valuesByKey.each(function(values, key) { setResult(result, key, apply(values, depth, createResult, setResult)); }); return result; } function entries(map$$1, depth) { if (++depth > keys.length) return map$$1; var array, sortKey = sortKeys[depth - 1]; if (rollup != null && depth >= keys.length) array = map$$1.entries(); else array = [], map$$1.each(function(v, k) { array.push({key: k, values: entries(v, depth)}); }); return sortKey != null ? array.sort(function(a, b) { return sortKey(a.key, b.key); }) : array; } return nest = { object: function(array) { return apply(array, 0, createObject, setObject); }, map: function(array) { return apply(array, 0, createMap, setMap); }, entries: function(array) { return entries(apply(array, 0, createMap, setMap), 0); }, key: function(d) { keys.push(d); return nest; }, sortKeys: function(order) { sortKeys[keys.length - 1] = order; return nest; }, sortValues: function(order) { sortValues = order; return nest; }, rollup: function(f) { rollup = f; return nest; } }; }; function createObject() { return {}; } function setObject(object, key, value) { object[key] = value; } function createMap() { return map(); } function setMap(map$$1, key, value) { map$$1.set(key, value); } function Set() {} var proto = map.prototype; Set.prototype = set.prototype = { constructor: Set, has: proto.has, add: function(value) { value += ""; this[prefix + value] = value; return this; }, remove: proto.remove, clear: proto.clear, values: proto.keys, size: proto.size, empty: proto.empty, each: proto.each }; function set(object, f) { var set = new Set; // Copy constructor. if (object instanceof Set) object.each(function(value) { set.add(value); }); // Otherwise, assume it’s an array. else if (object) { var i = -1, n = object.length; if (f == null) while (++i < n) set.add(object[i]); else while (++i < n) set.add(f(object[i], i, object)); } return set; } var noop = {value: function() {}}; function dispatch() { for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) { if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t); _[t] = []; } return new Dispatch(_); } function Dispatch(_) { this._ = _; } function parseTypenames(typenames, types) { return typenames.trim().split(/^|\s+/).map(function(t) { var name = "", i = t.indexOf("."); if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i); if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t); return {type: t, name: name}; }); } Dispatch.prototype = dispatch.prototype = { constructor: Dispatch, on: function(typename, callback) { var _ = this._, T = parseTypenames(typename + "", _), t, i = -1, n = T.length; // If no callback was specified, return the callback of the given type and name. if (arguments.length < 2) { while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t; return; } // If a type was specified, set the callback for the given type and name. // Otherwise, if a null callback was specified, remove callbacks of the given name. if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback); while (++i < n) { if (t = (typename = T[i]).type) _[t] = set$2(_[t], typename.name, callback); else if (callback == null) for (t in _) _[t] = set$2(_[t], typename.name, null); } return this; }, copy: function() { var copy = {}, _ = this._; for (var t in _) copy[t] = _[t].slice(); return new Dispatch(copy); }, call: function(type, that) { if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2]; if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type); for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args); }, apply: function(type, that, args) { if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type); for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args); } }; function get(type, name) { for (var i = 0, n = type.length, c; i < n; ++i) { if ((c = type[i]).name === name) { return c.value; } } } function set$2(type, name, callback) { for (var i = 0, n = type.length; i < n; ++i) { if (type[i].name === name) { type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1)); break; } } if (callback != null) type.push({name: name, value: callback}); return type; } var request$1 = function(url, callback) { var request, event = dispatch("beforesend", "progress", "load", "error"), mimeType, headers = map(), xhr = new XMLHttpRequest, user = null, password = null, response, responseType, timeout = 0; // If IE does not support CORS, use XDomainRequest. if (typeof XDomainRequest !== "undefined" && !("withCredentials" in xhr) && /^(http(s)?:)?\/\//.test(url)) xhr = new XDomainRequest; "onload" in xhr ? xhr.onload = xhr.onerror = xhr.ontimeout = respond : xhr.onreadystatechange = function(o) { xhr.readyState > 3 && respond(o); }; function respond(o) { var status = xhr.status, result; if (!status && hasResponse(xhr) || status >= 200 && status < 300 || status === 304) { if (response) { try { result = response.call(request, xhr); } catch (e) { event.call("error", request, e); return; } } else { result = xhr; } event.call("load", request, result); } else { event.call("error", request, o); } } xhr.onprogress = function(e) { event.call("progress", request, e); }; request = { header: function(name, value) { name = (name + "").toLowerCase(); if (arguments.length < 2) return headers.get(name); if (value == null) headers.remove(name); else headers.set(name, value + ""); return request; }, // If mimeType is non-null and no Accept header is set, a default is used. mimeType: function(value) { if (!arguments.length) return mimeType; mimeType = value == null ? null : value + ""; return request; }, // Specifies what type the response value should take; // for instance, arraybuffer, blob, document, or text. responseType: function(value) { if (!arguments.length) return responseType; responseType = value; return request; }, timeout: function(value) { if (!arguments.length) return timeout; timeout = +value; return request; }, user: function(value) { return arguments.length < 1 ? user : (user = value == null ? null : value + "", request); }, password: function(value) { return arguments.length < 1 ? password : (password = value == null ? null : value + "", request); }, // Specify how to convert the response content to a specific type; // changes the callback value on "load" events. response: function(value) { response = value; return request; }, // Alias for send("GET", …). get: function(data, callback) { return request.send("GET", data, callback); }, // Alias for send("POST", …). post: function(data, callback) { return request.send("POST", data, callback); }, // If callback is non-null, it will be used for error and load events. send: function(method, data, callback) { xhr.open(method, url, true, user, password); if (mimeType != null && !headers.has("accept")) headers.set("accept", mimeType + ",*/*"); if (xhr.setRequestHeader) headers.each(function(value, name) { xhr.setRequestHeader(name, value); }); if (mimeType != null && xhr.overrideMimeType) xhr.overrideMimeType(mimeType); if (responseType != null) xhr.responseType = responseType; if (timeout > 0) xhr.timeout = timeout; if (callback == null && typeof data === "function") callback = data, data = null; if (callback != null && callback.length === 1) callback = fixCallback(callback); if (callback != null) request.on("error", callback).on("load", function(xhr) { callback(null, xhr); }); event.call("beforesend", request, xhr); xhr.send(data == null ? null : data); return request; }, abort: function() { xhr.abort(); return request; }, on: function() { var value = event.on.apply(event, arguments); return value === event ? request : value; } }; if (callback != null) { if (typeof callback !== "function") throw new Error("invalid callback: " + callback); return request.get(callback); } return request; }; function fixCallback(callback) { return function(error, xhr) { callback(error == null ? xhr : null); }; } function hasResponse(xhr) { var type = xhr.responseType; return type && type !== "text" ? xhr.response // null on error : xhr.responseText; // "" on error } 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; } var dsvFormat = function(delimiter) { var reFormat = new RegExp("[\"" + delimiter + "\n\r]"), delimiterCode = 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 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; } function format(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"); } function formatRows(rows) { return rows.map(formatRow).join("\n"); } function formatRow(row) { return row.map(formatValue).join(delimiter); } function formatValue(text) { return text == null ? "" : reFormat.test(text += "") ? "\"" + text.replace(/\"/g, "\"\"") + "\"" : text; } return { parse: parse, parseRows: parseRows, format: format, formatRows: formatRows }; }; var csv$1 = dsvFormat(","); var tsv = dsvFormat("\t"); // 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://'; // Request options to check for d3-request var requestOptions = [ 'mimeType', 'responseType', 'user', 'password' ]; /** * Creates a new loader instance that provides methods for requesting files * from either the network or disk, and for sanitizing request URIs. * @param {object} [options] - Optional default loading options to use. * @return {object} - A new loader instance. */ var loader = function(options) { return { options: options || {}, sanitize: sanitize, load: load, file: file, http: http }; }; function marshall(loader, options) { return extend({}, loader.options, options); } /** * Load an external resource, typically either from the web or from the local * filesystem. This function uses {@link sanitize} to first sanitize the uri, * then calls either {@link http} (for web requests) or {@link file} (for * filesystem loading). * @param {string} uri - The resource indicator (e.g., URL or filename). * @param {object} [options] - Optional loading options. These options will * override any existing default options. * @return {Promise} - A promise that resolves to the loaded content. */ function load(uri, options) { var loader = this; return loader.sanitize(uri, options) .then(function(opt) { var url = opt.href; return opt.localFile ? loader.file(url) : loader.http(url, options); }); } /** * URI sanitizer function. * @param {string} uri - The uri (url or filename) to sanity check. * @param {object} options - An options hash. * @return {Promise} - A promise that resolves to an object containing * sanitized uri data, or rejects it the input uri is deemed invalid. * The properties of the resolved object are assumed to be * valid attributes for an HTML 'a' tag. The sanitized uri *must* be * provided by the 'href' property of the returned object. */ function sanitize(uri, options) { options = marshall(this, options); return new Promise(function(accept, reject) { var result = {href: null}, isFile, hasProtocol, loadFile, base; if (uri == null || typeof uri !== 'string') { reject('Sanitize failure, invalid URI: ' + $(uri)); return; } hasProtocol = protocol_re.test(uri); // if relative url (no protocol/host), prepend baseURL if ((base = options.baseURL) && !hasProtocol) { // Ensure that there is a slash between the baseURL (e.g. hostname) and url if (!startsWith(uri, '/') && base[base.length-1] !== '/') { uri = '/' + uri; } uri = base + uri; } // should we load from file system? loadFile = (isFile = startsWith(uri, fileProtocol)) || options.mode === 'file' || options.mode !== 'http' && !hasProtocol && fs(); if (isFile) { // strip file protocol uri = uri.slice(fileProtocol.length); } else if (startsWith(uri, '//')) { if (options.defaultProtocol === 'file') { // if is file, strip protocol and set loadFile flag uri = uri.slice(2); loadFile = true; } else { // if relative protocol (starts with '//'), prepend default protocol uri = (options.defaultProtocol || 'http') + ':' + uri; } } // set non-enumerable mode flag to indicate local file load Object.defineProperty(result, 'localFile', {value: !!loadFile}); // set uri and return result.href = uri; accept(result); }); } /** * HTTP request loader. * @param {string} url - The url to request. * @param {object} options - An options hash. * @return {Promise} - A promise that resolves to the file contents. */ function http(url, options) { options = marshall(this, options); return new Promise(function(accept, reject) { var req = request$1(url), name; for (name in options.headers) { req.header(name, options.headers[name]); } requestOptions.forEach(function(name) { if (options[name]) req[name](options[name]); }); req.on('error', function(error) { reject(error || 'Error loading URL: ' + url); }) .on('load', function(result) { var text$$1 = result && result.responseText; (!result || result.status === 0) ? reject(text$$1 || 'Error') : accept(text$$1); }) .get(); }); } /** * File system loader. * @param {string} filename - The file system path to load. * @return {Promise} - A promise that resolves to the file contents. */ function file(filename) { return new Promise(function(accept, reject) { var f = fs(); f ? f.readFile(filename, function(error, data) { if (error) reject(error); else accept(data); }) : reject('No file system access for ' + filename); }); } function fs() { var fs = typeof require === 'function' && require('fs'); return fs && isFunction(fs.readFile) ? fs : null; } function startsWith(string, query) { return string == null ? false : string.lastIndexOf(query, 0) === 0; } var typeParsers = { boolean: toBoolean, integer: toNumber, number: toNumber, date: toDate, string: toString }; var typeTests = [ isBoolean$1, isInteger, isNumber$1, isDate$1 ]; var typeList = [ 'boolean', 'integer', 'number', 'date' ]; function inferType(values, field$$1) { var tests = typeTests.slice(), value, i, n, j; for (i=0, n=values.length; i>> 1; if (a[mid] < x) lo = mid + 1; else hi = mid; } return lo; } var feature = function(topology, 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 f = { type: "Feature", id: o.id, properties: o.properties || {}, geometry: object(topology, o) }; if (o.id == null) delete f.id; return f; } function object(topology, o) { var absolute$$1 = absolute(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, p; k < n; ++k) { points.push(p = a[k].slice()); absolute$$1(p, k); } if (i < 0) reverse(points, n); } function point(p) { p = p.slice(); absolute$$1(p, 0); return 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].slice()); return points; } function ring(arcs) { var points = line(arcs); while (points.length < 4) points.push(points[0].slice()); return points; } function polygon(arcs) { return arcs.map(ring); } function geometry(o) { var t = o.type; return t === "GeometryCollection" ? {type: t, geometries: o.geometries.map(geometry)} : t in geometryType ? {type: t, coordinates: geometryType[t](o)} : null; } var geometryType = { Point: function(o) { return point(o.coordinates); }, MultiPoint: function(o) { return o.coordinates.map(point); }, LineString: function(o) { return line(o.arcs); }, MultiLineString: function(o) { return o.arcs.map(line); }, Polygon: function(o) { return polygon(o.arcs); }, MultiPolygon: function(o) { return o.arcs.map(polygon); } }; return geometry(o); } var stitchArcs = function(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; }; var mesh = function(topology) { return object(topology, meshArcs.apply(this, arguments)); }; function meshArcs(topology, o, filter) { var arcs = []; function arc(i) { var j = i < 0 ? ~i : i; (geomsByArc[j] || (geomsByArc[j] = [])).push({i: i, g: geom}); } function line(arcs) { arcs.forEach(arc); } function polygon(arcs) { arcs.forEach(line); } function geometry(o) { if (o.type === "GeometryCollection") o.geometries.forEach(geometry); else if (o.type in geometryType) geom = o, geometryType[o.type](o.arcs); } if (arguments.length > 1) { var geomsByArc = [], geom; var geometryType = { LineString: line, MultiLineString: polygon, Polygon: polygon, MultiPolygon: function(arcs) { arcs.forEach(polygon); } }; geometry(o); geomsByArc.forEach(arguments.length < 3 ? function(geoms) { arcs.push(geoms[0].i); } : function(geoms) { if (filter(geoms[0].g, geoms[geoms.length - 1].g)) arcs.push(geoms[0].i); }); } else { for (var i = 0, n = topology.arcs.length; i < n; ++i) arcs.push(i); } return {type: "MultiLineString", arcs: stitchArcs(topology, arcs)}; } var topojson = function(data, format) { var object, property; data = json$1(data, format); if (format && (property = format.feature)) { return (object = data.objects[property]) ? feature(data, object).features : error$1('Invalid TopoJSON object: ' + property); } else if (format && (property = format.mesh)) { return (object = data.objects[property]) ? [mesh(data, object)] : error$1('Invalid TopoJSON object: ' + property); } error$1('Missing TopoJSON feature or mesh parameter.'); }; var formats = { dsv: dsv$1, csv: delimitedFormat(','), tsv: delimitedFormat('\t'), json: json$1, topojson: topojson }; var formats$1 = function(name, format) { if (arguments.length > 1) { formats[name] = format; return this; } else { return formats.hasOwnProperty(name) ? formats[name] : null; } }; 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.ceil = function(date) { return floori(date = new Date(date - 1)), offseti(date, 1), floori(date), date; }; interval.round = function(date) { var d0 = interval(date), d1 = interval.ceil(date); return date - d0 < d1 - date ? d0 : d1; }; interval.offset = function(date, step) { return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date; }; interval.range = function(start, stop, step) { var range = []; start = interval.ceil(start); step = step == null ? 1 : Math.floor(step); if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date do range.push(new Date(+start)); while (offseti(start, step), floori(start), start < stop) return range; }; interval.filter = function(test) { return newInterval(function(date) { if (date >= date) while (floori(date), !test(date)) date.setTime(date - 1); }, function(date, step) { if (date >= date) { if (step < 0) while (++step <= 0) { while (offseti(date, -1), !test(date)) {} // eslint-disable-line no-empty } else while (--step >= 0) { while (offseti(date, +1), !test(date)) {} // eslint-disable-line no-empty } } }); }; if (count) { interval.count = function(start, end) { t0.setTime(+start), t1.setTime(+end); floori(t0), floori(t1); return Math.floor(count(t0, t1)); }; interval.every = function(step) { step = Math.floor(step); return !isFinite(step) || !(step > 0) ? null : !(step > 1) ? interval : interval.filter(field ? function(d) { return field(d) % step === 0; } : function(d) { return interval.count(0, d) % step === 0; }); }; } return interval; } var millisecond = newInterval(function() { // noop }, function(date, step) { date.setTime(+date + step); }, function(start, end) { return end - start; }); // An optimized implementation for this simple case. millisecond.every = function(k) { k = Math.floor(k); if (!isFinite(k) || !(k > 0)) return null; if (!(k > 1)) return millisecond; return newInterval(function(date) { date.setTime(Math.floor(date / k) * k); }, function(date, step) { date.setTime(+date + step * k); }, function(start, end) { return (end - start) / k; }); }; var durationSecond = 1e3; var durationMinute = 6e4; var durationHour = 36e5; var durationDay = 864e5; var durationWeek = 6048e5; var second = newInterval(function(date) { date.setTime(Math.floor(date / durationSecond) * durationSecond); }, function(date, step) { date.setTime(+date + step * durationSecond); }, function(start, end) { return (end - start) / durationSecond; }, function(date) { return date.getUTCSeconds(); }); var minute = newInterval(function(date) { date.setTime(Math.floor(date / durationMinute) * durationMinute); }, function(date, step) { date.setTime(+date + step * durationMinute); }, function(start, end) { return (end - start) / durationMinute; }, function(date) { return date.getMinutes(); }); var hour = newInterval(function(date) { var offset = date.getTimezoneOffset() * durationMinute % durationHour; if (offset < 0) offset += durationHour; date.setTime(Math.floor((+date - offset) / durationHour) * durationHour + offset); }, function(date, step) { date.setTime(+date + step * durationHour); }, function(start, end) { return (end - start) / durationHour; }, 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()) * durationMinute) / durationDay; }, function(date) { return date.getDate() - 1; }); function weekday(i) { return newInterval(function(date) { date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7); date.setHours(0, 0, 0, 0); }, function(date, step) { date.setDate(date.getDate() + step * 7); }, function(start, end) { return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationWeek; }); } var sunday = weekday(0); var monday = weekday(1); var tuesday = weekday(2); var wednesday = weekday(3); var thursday = weekday(4); var friday = weekday(5); var saturday = weekday(6); var month = newInterval(function(date) { date.setDate(1); date.setHours(0, 0, 0, 0); }, function(date, step) { date.setMonth(date.getMonth() + step); }, function(start, end) { return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12; }, function(date) { return date.getMonth(); }); var year = newInterval(function(date) { date.setMonth(0, 1); date.setHours(0, 0, 0, 0); }, function(date, step) { date.setFullYear(date.getFullYear() + step); }, function(start, end) { return end.getFullYear() - start.getFullYear(); }, function(date) { return date.getFullYear(); }); // An optimized implementation for this simple case. year.every = function(k) { return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) { date.setFullYear(Math.floor(date.getFullYear() / k) * k); date.setMonth(0, 1); date.setHours(0, 0, 0, 0); }, function(date, step) { date.setFullYear(date.getFullYear() + step * k); }); }; var 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 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 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; }); 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 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 utcYear = newInterval(function(date) { date.setUTCMonth(0, 1); date.setUTCHours(0, 0, 0, 0); }, function(date, step) { date.setUTCFullYear(date.getUTCFullYear() + step); }, function(start, end) { return end.getUTCFullYear() - start.getUTCFullYear(); }, function(date) { return date.getUTCFullYear(); }); // An optimized implementation for this simple case. utcYear.every = function(k) { return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) { date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k); date.setUTCMonth(0, 1); date.setUTCHours(0, 0, 0, 0); }, function(date, step) { date.setUTCFullYear(date.getUTCFullYear() + step * k); }); }; function localDate(d) { if (0 <= d.y && d.y < 100) { var date = new Date(-1, d.m, d.d, d.H, d.M, d.S, d.L); date.setFullYear(d.y); return date; } return new Date(d.y, d.m, d.d, d.H, d.M, d.S, d.L); } function utcDate(d) { if (0 <= d.y && d.y < 100) { var date = new Date(Date.UTC(-1, d.m, d.d, d.H, d.M, d.S, d.L)); date.setUTCFullYear(d.y); return date; } return new Date(Date.UTC(d.y, d.m, d.d, d.H, d.M, d.S, d.L)); } function newYear(y) { return {y: y, m: 0, d: 1, H: 0, M: 0, S: 0, L: 0}; } function formatLocale(locale) { var locale_dateTime = locale.dateTime, locale_date = locale.date, locale_time = locale.time, locale_periods = locale.periods, locale_weekdays = locale.days, locale_shortWeekdays = locale.shortDays, locale_months = locale.months, locale_shortMonths = locale.shortMonths; var periodRe = formatRe(locale_periods), periodLookup = formatLookup(locale_periods), weekdayRe = formatRe(locale_weekdays), weekdayLookup = formatLookup(locale_weekdays), shortWeekdayRe = formatRe(locale_shortWeekdays), shortWeekdayLookup = formatLookup(locale_shortWeekdays), monthRe = formatRe(locale_months), monthLookup = formatLookup(locale_months), shortMonthRe = formatRe(locale_shortMonths), shortMonthLookup = formatLookup(locale_shortMonths); var formats = { "a": formatShortWeekday, "A": formatWeekday, "b": formatShortMonth, "B": formatMonth, "c": null, "d": formatDayOfMonth, "e": formatDayOfMonth, "H": formatHour24, "I": formatHour12, "j": formatDayOfYear, "L": formatMilliseconds, "m": formatMonthNumber, "M": formatMinutes, "p": formatPeriod, "S": formatSeconds, "U": formatWeekNumberSunday, "w": formatWeekdayNumber, "W": formatWeekNumberMonday, "x": null, "X": null, "y": formatYear, "Y": formatFullYear, "Z": formatZone, "%": formatLiteralPercent }; var utcFormats = { "a": formatUTCShortWeekday, "A": formatUTCWeekday, "b": formatUTCShortMonth, "B": formatUTCMonth, "c": null, "d": formatUTCDayOfMonth, "e": formatUTCDayOfMonth, "H": formatUTCHour24, "I": formatUTCHour12, "j": formatUTCDayOfYear, "L": formatUTCMilliseconds, "m": formatUTCMonthNumber, "M": formatUTCMinutes, "p": formatUTCPeriod, "S": formatUTCSeconds, "U": formatUTCWeekNumberSunday, "w": formatUTCWeekdayNumber, "W": formatUTCWeekNumberMonday, "x": null, "X": null, "y": formatUTCYear, "Y": formatUTCFullYear, "Z": formatUTCZone, "%": formatLiteralPercent }; var parses = { "a": parseShortWeekday, "A": parseWeekday, "b": parseShortMonth, "B": parseMonth, "c": parseLocaleDateTime, "d": parseDayOfMonth, "e": parseDayOfMonth, "H": parseHour24, "I": parseHour24, "j": parseDayOfYear, "L": parseMilliseconds, "m": parseMonthNumber, "M": parseMinutes, "p": parsePeriod, "S": parseSeconds, "U": parseWeekNumberSunday, "w": parseWeekdayNumber, "W": parseWeekNumberMonday, "x": parseLocaleDate, "X": parseLocaleTime, "y": parseYear, "Y": parseFullYear, "Z": parseZone, "%": parseLiteralPercent }; // These recursive directive definitions must be deferred. formats.x = newFormat(locale_date, formats); formats.X = newFormat(locale_time, formats); formats.c = newFormat(locale_dateTime, formats); utcFormats.x = newFormat(locale_date, utcFormats); utcFormats.X = newFormat(locale_time, utcFormats); utcFormats.c = newFormat(locale_dateTime, utcFormats); function newFormat(specifier, formats) { return function(date) { var string = [], i = -1, j = 0, n = specifier.length, c, pad, format; if (!(date instanceof Date)) date = new Date(+date); while (++i < n) { if (specifier.charCodeAt(i) === 37) { string.push(specifier.slice(j, i)); if ((pad = pads[c = specifier.charAt(++i)]) != null) c = specifier.charAt(++i); else pad = c === "e" ? " " : "0"; if (format = formats[c]) c = format(date, pad); string.push(c); j = i + 1; } } string.push(specifier.slice(j, i)); return string.join(""); }; } function newParse(specifier, newDate) { return function(string) { var d = newYear(1900), i = parseSpecifier(d, specifier, string += "", 0); if (i != string.length) return null; // The am-pm flag is 0 for AM, and 1 for PM. if ("p" in d) d.H = d.H % 12 + d.p * 12; // Convert day-of-week and week-of-year to day-of-year. if ("W" in d || "U" in d) { if (!("w" in d)) d.w = "W" in d ? 1 : 0; var day$$1 = "Z" in d ? utcDate(newYear(d.y)).getUTCDay() : newDate(newYear(d.y)).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; } // If a time zone is specified, all fields are interpreted as UTC and then // offset according to the specified time zone. if ("Z" in d) { d.H += d.Z / 100 | 0; d.M += d.Z % 100; return utcDate(d); } // Otherwise, all fields are in local time. return newDate(d); }; } function parseSpecifier(d, specifier, string, j) { var i = 0, n = specifier.length, m = string.length, c, parse; while (i < n) { if (j >= m) return -1; c = specifier.charCodeAt(i++); if (c === 37) { c = specifier.charAt(i++); parse = parses[c in pads ? specifier.charAt(i++) : c]; if (!parse || ((j = parse(d, string, j)) < 0)) return -1; } else if (c != string.charCodeAt(j++)) { return -1; } } return j; } function parsePeriod(d, string, i) { var n = periodRe.exec(string.slice(i)); return n ? (d.p = periodLookup[n[0].toLowerCase()], i + n[0].length) : -1; } function parseShortWeekday(d, string, i) { var n = shortWeekdayRe.exec(string.slice(i)); return n ? (d.w = shortWeekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1; } function parseWeekday(d, string, i) { var n = weekdayRe.exec(string.slice(i)); return n ? (d.w = weekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1; } function parseShortMonth(d, string, i) { var n = shortMonthRe.exec(string.slice(i)); return n ? (d.m = shortMonthLookup[n[0].toLowerCase()], i + n[0].length) : -1; } function parseMonth(d, string, i) { var n = monthRe.exec(string.slice(i)); return n ? (d.m = monthLookup[n[0].toLowerCase()], i + n[0].length) : -1; } function parseLocaleDateTime(d, string, i) { return parseSpecifier(d, locale_dateTime, string, i); } function parseLocaleDate(d, string, i) { return parseSpecifier(d, locale_date, string, i); } function parseLocaleTime(d, string, i) { return parseSpecifier(d, locale_time, string, i); } function formatShortWeekday(d) { return locale_shortWeekdays[d.getDay()]; } function formatWeekday(d) { return locale_weekdays[d.getDay()]; } function formatShortMonth(d) { return locale_shortMonths[d.getMonth()]; } function formatMonth(d) { return locale_months[d.getMonth()]; } function formatPeriod(d) { return locale_periods[+(d.getHours() >= 12)]; } function formatUTCShortWeekday(d) { return locale_shortWeekdays[d.getUTCDay()]; } function formatUTCWeekday(d) { return locale_weekdays[d.getUTCDay()]; } function formatUTCShortMonth(d) { return locale_shortMonths[d.getUTCMonth()]; } function formatUTCMonth(d) { return locale_months[d.getUTCMonth()]; } function formatUTCPeriod(d) { return locale_periods[+(d.getUTCHours() >= 12)]; } return { format: function(specifier) { var f = newFormat(specifier += "", formats); f.toString = function() { return specifier; }; return f; }, parse: function(specifier) { var p = newParse(specifier += "", localDate); p.toString = function() { return specifier; }; return p; }, utcFormat: function(specifier) { var f = newFormat(specifier += "", utcFormats); f.toString = function() { return specifier; }; return f; }, utcParse: function(specifier) { var p = newParse(specifier, utcDate); p.toString = function() { return specifier; }; return p; } }; } var pads = {"-": "", "_": " ", "0": "0"}; var numberRe = /^\s*\d+/; var percentRe = /^%/; var requoteRe = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g; function pad$1(value, fill, width) { var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length; return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string); } function requote(s) { return s.replace(requoteRe, "\\$&"); } function formatRe(names) { return new RegExp("^(?:" + names.map(requote).join("|") + ")", "i"); } function formatLookup(names) { var map = {}, i = -1, n = names.length; while (++i < n) map[names[i].toLowerCase()] = i; return map; } function parseWeekdayNumber(d, string, i) { var n = numberRe.exec(string.slice(i, i + 1)); return n ? (d.w = +n[0], i + n[0].length) : -1; } function parseWeekNumberSunday(d, string, i) { var n = numberRe.exec(string.slice(i)); return n ? (d.U = +n[0], i + n[0].length) : -1; } function parseWeekNumberMonday(d, string, i) { var n = numberRe.exec(string.slice(i)); return n ? (d.W = +n[0], i + n[0].length) : -1; } function parseFullYear(d, string, i) { var n = numberRe.exec(string.slice(i, i + 4)); return n ? (d.y = +n[0], i + n[0].length) : -1; } function parseYear(d, string, i) { var n = numberRe.exec(string.slice(i, i + 2)); return n ? (d.y = +n[0] + (+n[0] > 68 ? 1900 : 2000), i + n[0].length) : -1; } function parseZone(d, string, i) { var n = /^(Z)|([+-]\d\d)(?:\:?(\d\d))?/.exec(string.slice(i, i + 6)); return n ? (d.Z = n[1] ? 0 : -(n[2] + (n[3] || "00")), i + n[0].length) : -1; } function parseMonthNumber(d, string, i) { var n = numberRe.exec(string.slice(i, i + 2)); return n ? (d.m = n[0] - 1, i + n[0].length) : -1; } function parseDayOfMonth(d, string, i) { var n = numberRe.exec(string.slice(i, i + 2)); return n ? (d.d = +n[0], i + n[0].length) : -1; } function parseDayOfYear(d, string, i) { var n = numberRe.exec(string.slice(i, i + 3)); return n ? (d.m = 0, d.d = +n[0], i + n[0].length) : -1; } function parseHour24(d, string, i) { var n = numberRe.exec(string.slice(i, i + 2)); return n ? (d.H = +n[0], i + n[0].length) : -1; } function parseMinutes(d, string, i) { var n = numberRe.exec(string.slice(i, i + 2)); return n ? (d.M = +n[0], i + n[0].length) : -1; } function parseSeconds(d, string, i) { var n = numberRe.exec(string.slice(i, i + 2)); return n ? (d.S = +n[0], i + n[0].length) : -1; } function parseMilliseconds(d, string, i) { var n = numberRe.exec(string.slice(i, i + 3)); return n ? (d.L = +n[0], i + n[0].length) : -1; } function parseLiteralPercent(d, string, i) { var n = percentRe.exec(string.slice(i, i + 1)); return n ? i + n[0].length : -1; } function formatDayOfMonth(d, p) { return pad$1(d.getDate(), p, 2); } function formatHour24(d, p) { return pad$1(d.getHours(), p, 2); } function formatHour12(d, p) { return pad$1(d.getHours() % 12 || 12, p, 2); } function formatDayOfYear(d, p) { return pad$1(1 + day.count(year(d), d), p, 3); } function formatMilliseconds(d, p) { return pad$1(d.getMilliseconds(), p, 3); } function formatMonthNumber(d, p) { return pad$1(d.getMonth() + 1, p, 2); } function formatMinutes(d, p) { return pad$1(d.getMinutes(), p, 2); } function formatSeconds(d, p) { return pad$1(d.getSeconds(), p, 2); } function formatWeekNumberSunday(d, p) { return pad$1(sunday.count(year(d), d), p, 2); } function formatWeekdayNumber(d) { return d.getDay(); } function formatWeekNumberMonday(d, p) { return pad$1(monday.count(year(d), d), p, 2); } function formatYear(d, p) { return pad$1(d.getFullYear() % 100, p, 2); } function formatFullYear(d, p) { return pad$1(d.getFullYear() % 10000, p, 4); } function formatZone(d) { var z = d.getTimezoneOffset(); return (z > 0 ? "-" : (z *= -1, "+")) + pad$1(z / 60 | 0, "0", 2) + pad$1(z % 60, "0", 2); } function formatUTCDayOfMonth(d, p) { return pad$1(d.getUTCDate(), p, 2); } function formatUTCHour24(d, p) { return pad$1(d.getUTCHours(), p, 2); } function formatUTCHour12(d, p) { return pad$1(d.getUTCHours() % 12 || 12, p, 2); } function formatUTCDayOfYear(d, p) { return pad$1(1 + utcDay.count(utcYear(d), d), p, 3); } function formatUTCMilliseconds(d, p) { return pad$1(d.getUTCMilliseconds(), p, 3); } function formatUTCMonthNumber(d, p) { return pad$1(d.getUTCMonth() + 1, p, 2); } function formatUTCMinutes(d, p) { return pad$1(d.getUTCMinutes(), p, 2); } function formatUTCSeconds(d, p) { return pad$1(d.getUTCSeconds(), p, 2); } function formatUTCWeekNumberSunday(d, p) { return pad$1(utcSunday.count(utcYear(d), d), p, 2); } function formatUTCWeekdayNumber(d) { return d.getUTCDay(); } function formatUTCWeekNumberMonday(d, p) { return pad$1(utcMonday.count(utcYear(d), d), p, 2); } function formatUTCYear(d, p) { return pad$1(d.getUTCFullYear() % 100, p, 2); } function formatUTCFullYear(d, p) { return pad$1(d.getUTCFullYear() % 10000, p, 4); } function formatUTCZone() { return "+0000"; } function formatLiteralPercent() { return "%"; } var locale$1; var timeFormat; var timeParse; var utcFormat; var utcParse; defaultLocale({ dateTime: "%x, %X", date: "%-m/%-d/%Y", time: "%-I:%M:%S %p", periods: ["AM", "PM"], days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], shortDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] }); function defaultLocale(definition) { locale$1 = formatLocale(definition); timeFormat = locale$1.format; timeParse = locale$1.parse; utcFormat = locale$1.utcFormat; utcParse = locale$1.utcParse; return locale$1; } var isoSpecifier = "%Y-%m-%dT%H:%M:%S.%LZ"; function formatIsoNative(date) { return date.toISOString(); } var formatIso = Date.prototype.toISOString ? formatIsoNative : utcFormat(isoSpecifier); function parseIsoNative(string) { var date = new Date(string); return isNaN(date) ? null : date; } var parseIso = +new Date("2000-01-01T00:00:00.000Z") ? parseIsoNative : utcParse(isoSpecifier); var read = function(data, schema, dateParse) { schema = schema || {}; var reader = formats$1(schema.type || 'json'); if (!reader) error$1('Unknown data format type: ' + schema.type); data = reader(data, schema); if (schema.parse) parse(data, schema.parse, dateParse); if (data.hasOwnProperty('columns')) delete data.columns; return data; }; function parse(data, types, dateParse) { dateParse = dateParse || timeParse; var fields = data.columns || Object.keys(data[0]), parsers, datum, field$$1, i, j, n, m; if (types === 'auto') types = inferTypes(data, fields); fields = Object.keys(types); parsers = fields.map(function(field$$1) { var type = types[field$$1], parts, pattern; if (type && (type.indexOf('date:') === 0 || type.indexOf('utc:') === 0)) { parts = type.split(/:(.+)?/, 2); // split on first : pattern = parts[1]; if ((pattern[0] === '\'' && pattern[pattern.length-1] === '\'') || (pattern[0] === '"' && pattern[pattern.length-1] === '"')) { pattern = pattern.slice(1, -1); } return parts[0] === 'utc' ? utcParse(pattern) : dateParse(pattern); } if (!typeParsers[type]) { throw Error('Illegal format pattern: ' + field$$1 + ':' + type); } return typeParsers[type]; }); for (i=0, n=data.length, m=fields.length; i= 0;) { queue.push(cur = list[i]); if (cur === op) error$1('Cycle detected in dataflow graph.'); } } } } /** * Sentinel value indicating pulse propagation should stop. */ var StopPropagation = {}; // Pulse visit type flags var ADD = (1 << 0); var REM = (1 << 1); var MOD = (1 << 2); var ADD_REM = ADD | REM; var ADD_MOD = ADD | MOD; var ALL = ADD | REM | MOD; var REFLOW = (1 << 3); var SOURCE = (1 << 4); var NO_SOURCE = (1 << 5); var NO_FIELDS = (1 << 6); /** * A Pulse enables inter-operator communication during a run of the * dataflow graph. In addition to the current timestamp, a pulse may also * contain a change-set of added, removed or modified data tuples, as well as * a pointer to a full backing data source. Tuple change sets may not * be fully materialized; for example, to prevent needless array creation * a change set may include larger arrays and corresponding filter functions. * The pulse provides a {@link visit} method to enable proper and efficient * iteration over requested data tuples. * * In addition, each pulse can track modification flags for data tuple fields. * Responsible transform operators should call the {@link modifies} method to * indicate changes to data fields. The {@link modified} method enables * querying of this modification state. * * @constructor * @param {Dataflow} dataflow - The backing dataflow instance. * @param {number} stamp - The current propagation timestamp. * @param {string} [encode] - An optional encoding set name, which is then * accessible as Pulse.encode. Operators can respond to (or ignore) this * setting as appropriate. This parameter can be used in conjunction with * the Encode transform in the vega-encode module. */ function Pulse(dataflow, stamp, encode) { this.dataflow = dataflow; this.stamp = stamp == null ? -1 : stamp; this.add = []; this.rem = []; this.mod = []; this.fields = null; this.encode = encode || null; } var prototype$4 = Pulse.prototype; /** * Sentinel value indicating pulse propagation should stop. */ prototype$4.StopPropagation = StopPropagation; /** * Boolean flag indicating ADD (added) tuples. */ prototype$4.ADD = ADD; /** * Boolean flag indicating REM (removed) tuples. */ prototype$4.REM = REM; /** * Boolean flag indicating MOD (modified) tuples. */ prototype$4.MOD = MOD; /** * Boolean flag indicating ADD (added) and REM (removed) tuples. */ prototype$4.ADD_REM = ADD_REM; /** * Boolean flag indicating ADD (added) and MOD (modified) tuples. */ prototype$4.ADD_MOD = ADD_MOD; /** * Boolean flag indicating ADD, REM and MOD tuples. */ prototype$4.ALL = ALL; /** * Boolean flag indicating all tuples in a data source * except for the ADD, REM and MOD tuples. */ prototype$4.REFLOW = REFLOW; /** * Boolean flag indicating a 'pass-through' to a * backing data source, ignoring ADD, REM and MOD tuples. */ prototype$4.SOURCE = SOURCE; /** * Boolean flag indicating that source data should be * suppressed when creating a forked pulse. */ prototype$4.NO_SOURCE = NO_SOURCE; /** * Boolean flag indicating that field modifications should be * suppressed when creating a forked pulse. */ prototype$4.NO_FIELDS = NO_FIELDS; /** * Creates a new pulse based on the values of this pulse. * The dataflow, time stamp and field modification values are copied over. * By default, new empty ADD, REM and MOD arrays are created. * @param {number} flags - Integer of boolean flags indicating which (if any) * tuple arrays should be copied to the new pulse. The supported flag values * are ADD, REM and MOD. Array references are copied directly: new array * instances are not created. * @return {Pulse} - The forked pulse instance. * @see init */ prototype$4.fork = function(flags) { return new Pulse(this.dataflow).init(this, flags); }; /** * Returns a pulse that adds all tuples from a backing source. This is * useful for cases where operators are added to a dataflow after an * upstream data pipeline has already been processed, ensuring that * new operators can observe all tuples within a stream. * @return {Pulse} - A pulse instance with all source tuples included * in the add array. If the current pulse already has all source * tuples in its add array, it is returned directly. If the current * pulse does not have a backing source, it is returned directly. */ prototype$4.addAll = function() { var p = this; if (!this.source || this.source.length === this.add.length) { return p; } else { p = new Pulse(this.dataflow).init(this); p.add = p.source; return p; } }; /** * Initialize this pulse based on the values of another pulse. This method * is used internally by {@link fork} to initialize a new forked tuple. * The dataflow, time stamp and field modification values are copied over. * By default, new empty ADD, REM and MOD arrays are created. * @param {Pulse} src - The source pulse to copy from. * @param {number} flags - Integer of boolean flags indicating which (if any) * tuple arrays should be copied to the new pulse. The supported flag values * are ADD, REM and MOD. Array references are copied directly: new array * instances are not created. By default, source data arrays are copied * to the new pulse. Use the NO_SOURCE flag to enforce a null source. * @return {Pulse} - Returns this Pulse instance. */ prototype$4.init = function(src, flags) { var p = this; p.stamp = src.stamp; p.encode = src.encode; if (src.fields && !(flags & NO_FIELDS)) { p.fields = src.fields; } if (flags & ADD) { p.addF = src.addF; p.add = src.add; } else { p.addF = null; p.add = []; } if (flags & REM) { p.remF = src.remF; p.rem = src.rem; } else { p.remF = null; p.rem = []; } if (flags & MOD) { p.modF = src.modF; p.mod = src.mod; } else { p.modF = null; p.mod = []; } if (flags & NO_SOURCE) { p.srcF = null; p.source = null; } else { p.srcF = src.srcF; p.source = src.source; } return p; }; /** * Schedules a function to run after pulse propagation completes. * @param {function} func - The function to run. */ prototype$4.runAfter = function(func) { this.dataflow.runAfter(func); }; /** * Indicates if tuples have been added, removed or modified. * @param {number} [flags] - The tuple types (ADD, REM or MOD) to query. * Defaults to ALL, returning true if any tuple type has changed. * @return {boolean} - Returns true if one or more queried tuple types have * changed, false otherwise. */ prototype$4.changed = function(flags) { var f = flags || ALL; return ((f & ADD) && this.add.length) || ((f & REM) && this.rem.length) || ((f & MOD) && this.mod.length); }; /** * Forces a "reflow" of tuple values, such that all tuples in the backing * source are added to the MOD set, unless already present in the ADD set. * @param {boolean} [fork=false] - If true, returns a forked copy of this * pulse, and invokes reflow on that derived pulse. * @return {Pulse} - The reflowed pulse instance. */ prototype$4.reflow = function(fork) { if (fork) return this.fork(ALL).reflow(); var len = this.add.length, src = this.source && this.source.length; if (src && src !== len) { this.mod = this.source; if (len) this.filter(MOD, filter(this, ADD)); } return this; }; /** * Marks one or more data field names as modified to assist dependency * tracking and incremental processing by transform operators. * @param {string|Array} _ - The field(s) to mark as modified. * @return {Pulse} - This pulse instance. */ prototype$4.modifies = function(_) { var fields = array(_), hash = this.fields || (this.fields = {}); fields.forEach(function(f) { hash[f] = true; }); return this; }; /** * Checks if one or more data fields have been modified during this pulse * propagation timestamp. * @param {string|Array} _ - The field(s) to check for modified. * @return {boolean} - Returns true if any of the provided fields has been * marked as modified, false otherwise. */ prototype$4.modified = function(_) { var fields = this.fields; return !(this.mod.length && fields) ? false : !arguments.length ? !!fields : isArray(_) ? _.some(function(f) { return fields[f]; }) : fields[_]; }; /** * Adds a filter function to one more tuple sets. Filters are applied to * backing tuple arrays, to determine the actual set of tuples considered * added, removed or modified. They can be used to delay materialization of * a tuple set in order to avoid expensive array copies. In addition, the * filter functions can serve as value transformers: unlike standard predicate * function (which return boolean values), Pulse filters should return the * actual tuple value to process. If a tuple set is already filtered, the * new filter function will be appended into a conjuntive ('and') query. * @param {number} flags - Flags indicating the tuple set(s) to filter. * @param {function(*):object} filter - Filter function that will be applied * to the tuple set array, and should return a data tuple if the value * should be included in the tuple set, and falsy (or null) otherwise. * @return {Pulse} - Returns this pulse instance. */ prototype$4.filter = function(flags, filter) { var p = this; if (flags & ADD) p.addF = addFilter(p.addF, filter); if (flags & REM) p.remF = addFilter(p.remF, filter); if (flags & MOD) p.modF = addFilter(p.modF, filter); if (flags & SOURCE) p.srcF = addFilter(p.srcF, filter); return p; }; function addFilter(a, b) { return a ? function(t,i) { return a(t,i) && b(t,i); } : b; } /** * Materialize one or more tuple sets in this pulse. If the tuple set(s) have * a registered filter function, it will be applied and the tuple set(s) will * be replaced with materialized tuple arrays. * @param {number} flags - Flags indicating the tuple set(s) to materialize. * @return {Pulse} - Returns this pulse instance. */ prototype$4.materialize = function(flags) { flags = flags || ALL; var p = this; if ((flags & ADD) && p.addF) { p.add = materialize(p.add, p.addF); p.addF = null; } if ((flags & REM) && p.remF) { p.rem = materialize(p.rem, p.remF); p.remF = null; } if ((flags & MOD) && p.modF) { p.mod = materialize(p.mod, p.modF); p.modF = null; } if ((flags & SOURCE) && p.srcF) { p.source = p.source.filter(p.srcF); p.srcF = null; } return p; }; function materialize(data, filter) { var out = []; visitArray(data, filter, function(_) { out.push(_); }); return out; } function filter(pulse, flags) { var map = {}; pulse.visit(flags, function(t) { map[tupleid(t)] = 1; }); return function(t) { return map[tupleid(t)] ? null : t; }; } /** * Visit one or more tuple sets in this pulse. * @param {number} flags - Flags indicating the tuple set(s) to visit. * Legal values are ADD, REM, MOD and SOURCE (if a backing data source * has been set). * @param {function(object):*} - Visitor function invoked per-tuple. * @return {Pulse} - Returns this pulse instance. */ prototype$4.visit = function(flags, visitor) { var p = this, v = visitor, src, sum; if (flags & SOURCE) { visitArray(p.source, p.srcF, v); return p; } if (flags & ADD) visitArray(p.add, p.addF, v); if (flags & REM) visitArray(p.rem, p.remF, v); if (flags & MOD) visitArray(p.mod, p.modF, v); if ((flags & REFLOW) && (src = p.source)) { sum = p.add.length + p.mod.length; if (sum === src.length) { // do nothing } else if (sum) { visitArray(src, filter(p, ADD_MOD), v); } else { // if no add/rem/mod tuples, visit source visitArray(src, p.srcF, v); } } return p; }; /** * Represents a set of multiple pulses. Used as input for operators * that accept multiple pulses at a time. Contained pulses are * accessible via the public "pulses" array property. This pulse doe * not carry added, removed or modified tuples directly. However, * the visit method can be used to traverse all such tuples contained * in sub-pulses with a timestamp matching this parent multi-pulse. * @constructor * @param {Dataflow} dataflow - The backing dataflow instance. * @param {number} stamp - The timestamp. * @param {Array} pulses - The sub-pulses for this multi-pulse. */ function MultiPulse(dataflow, stamp, pulses, encode) { var p = this, c = 0, pulse, hash, i, n, f; this.dataflow = dataflow; this.stamp = stamp; this.fields = null; this.encode = encode || null; this.pulses = pulses; for (i=0, n=pulses.length; i= Info) { dt = Date.now(); df.debug('-- START PROPAGATION (' + df._clock + ') -----'); } // initialize queue, reset touched operators df._touched.forEach(function(op) { df._enqueue(op, true); }); df._touched = UniqueList(id); try { while (df._heap.size() > 0) { op = df._heap.pop(); // re-queue if rank changes if (op.rank !== op.qrank) { df._enqueue(op, true); continue; } // otherwise, evaluate the operator next = op.run(df._getPulse(op, encode)); if (level >= Debug) { df.debug(op.id, next === StopPropagation ? 'STOP' : next, op); } // propagate the pulse if (next !== StopPropagation) { df._pulse = next; if (op._targets) op._targets.forEach(function(op) { df._enqueue(op); }); } // increment visit counter ++count; } } catch (err) { error = err; } // reset pulse map df._pulses = {}; df._pulse = null; if (level >= Info) { dt = Date.now() - dt; df.info('> Pulse ' + df._clock + ': ' + count + ' operators; ' + dt + 'ms'); } if (error) { df._postrun = []; df.error(error); } if (df._onrun) { try { df._onrun(df, count, error); } catch (err) { df.error(err); } } // invoke callbacks queued via runAfter if (df._postrun.length) { var postrun = df._postrun; df._postrun = []; postrun.forEach(function(f) { try { f(df); } catch (err) { df.error(err); } }); } return count; } /** * Runs the dataflow and returns a Promise that resolves when the * propagation cycle completes. The standard run method may exit early * if there are pending data loading operations. In contrast, this * method returns a Promise to allow callers to receive notification * when dataflow evaluation completes. * @return {Promise} - A promise that resolves to this dataflow. */ function runAsync() { return this._pending || Promise.resolve(this.run()); } /** * Schedules a callback function to be invoked after the current pulse * propagation completes. If no propagation is currently occurring, * the function is invoked immediately. * @param {function(Dataflow)} callback - The callback function to run. * The callback will be invoked with this Dataflow instance as its * sole argument. * @param {boolean} enqueue - A boolean flag indicating that the * callback should be queued up to run after the next propagation * cycle, suppressing immediate invovation when propagation is not * currently occurring. */ function runAfter(callback, enqueue) { if (this._pulse || enqueue) { // pulse propagation is currently running, queue to run after this._postrun.push(callback); } else { // pulse propagation already complete, invoke immediately try { callback(this); } catch (err) { this.error(err); } } } /** * Enqueue an operator into the priority queue for evaluation. The operator * will be enqueued if it has no registered pulse for the current cycle, or if * the force argument is true. Upon enqueue, this method also sets the * operator's qrank to the current rank value. * @param {Operator} op - The operator to enqueue. * @param {boolean} [force] - A flag indicating if the operator should be * forceably added to the queue, even if it has already been previously * enqueued during the current pulse propagation. This is useful when the * dataflow graph is dynamically modified and the operator rank changes. */ function enqueue(op, force) { var p = !this._pulses[op.id]; if (p) this._pulses[op.id] = this._pulse; if (p || force) { op.qrank = op.rank; this._heap.push(op); } } /** * Provide a correct pulse for evaluating an operator. If the operator has an * explicit source operator, we will try to pull the pulse(s) from it. * If there is an array of source operators, we build a multi-pulse. * Otherwise, we return a current pulse with correct source data. * If the pulse is the pulse map has an explicit target set, we use that. * Else if the pulse on the upstream source operator is current, we use that. * Else we use the pulse from the pulse map, but copy the source tuple array. * @param {Operator} op - The operator for which to get an input pulse. * @param {string} [encode] - An (optional) encoding set name with which to * annotate the returned pulse. See {@link run} for more information. */ function getPulse(op, encode) { var s = op.source, stamp = this._clock, p; if (s && isArray(s)) { p = s.map(function(_) { return _.pulse; }); return new MultiPulse(this, stamp, p, encode); } else { s = s && s.pulse; p = this._pulses[op.id]; if (s && s !== StopPropagation) { if (s.stamp === stamp && p.target !== op) p = s; else p.source = s.source; } return p; } } var NO_OPT = {skip: false, force: false}; /** * Touches an operator, scheduling it to be evaluated. If invoked outside of * a pulse propagation, the operator will be evaluated the next time this * dataflow is run. If invoked in the midst of pulse propagation, the operator * will be queued for evaluation if and only if the operator has not yet been * evaluated on the current propagation timestamp. * @param {Operator} op - The operator to touch. * @param {object} [options] - Additional options hash. * @param {boolean} [options.skip] - If true, the operator will * be skipped: it will not be evaluated, but its dependents will be. * @return {Dataflow} */ function touch(op, options) { var opt = options || NO_OPT; if (this._pulse) { // if in midst of propagation, add to priority queue this._enqueue(op); } else { // otherwise, queue for next propagation this._touched.add(op); } if (opt.skip) op.skip(true); return this; } /** * Updates the value of the given operator. * @param {Operator} op - The operator to update. * @param {*} value - The value to set. * @param {object} [options] - Additional options hash. * @param {boolean} [options.force] - If true, the operator will * be re-evaluated even if its value has not changed. * @param {boolean} [options.skip] - If true, the operator will * be skipped: it will not be evaluated, but its dependents will be. * @return {Dataflow} */ function update(op, value, options) { var opt = options || NO_OPT; if (op.set(value) || opt.force) { this.touch(op, opt); } return this; } /** * Pulses an operator with a changeset of tuples. If invoked outside of * a pulse propagation, the pulse will be applied the next time this * dataflow is run. If invoked in the midst of pulse propagation, the pulse * will be added to the set of active pulses and will be applied if and * only if the target operator has not yet been evaluated on the current * propagation timestamp. * @param {Operator} op - The operator to pulse. * @param {ChangeSet} value - The tuple changeset to apply. * @param {object} [options] - Additional options hash. * @param {boolean} [options.skip] - If true, the operator will * be skipped: it will not be evaluated, but its dependents will be. * @return {Dataflow} */ function pulse(op, changeset, options) { this.touch(op, options || NO_OPT); var p = new Pulse(this, this._clock + (this._pulse ? 0 : 1)), t = op.pulse && op.pulse.source || []; p.target = op; this._pulses[op.id] = changeset.pulse(p, t); return this; } function Heap(comparator) { this.cmp = comparator; this.nodes = []; } var prototype$6 = Heap.prototype; prototype$6.size = function() { return this.nodes.length; }; prototype$6.clear = function() { this.nodes = []; return this; }; prototype$6.peek = function() { return this.nodes[0]; }; prototype$6.push = function(x) { var array = this.nodes; array.push(x); return siftdown(array, 0, array.length-1, this.cmp); }; prototype$6.pop = function() { var array = this.nodes, last = array.pop(), item; if (array.length) { item = array[0]; array[0] = last; siftup(array, 0, this.cmp); } else { item = last; } return item; }; prototype$6.replace = function(item) { var array = this.nodes, retval = array[0]; array[0] = item; siftup(array, 0, this.cmp); return retval; }; prototype$6.pushpop = function(item) { var array = this.nodes, ref = array[0]; if (array.length && this.cmp(ref, item) < 0) { array[0] = item; item = ref; siftup(array, 0, this.cmp); } return item; }; function siftdown(array, start, idx, cmp) { var item, parent, pidx; item = array[idx]; while (idx > start) { pidx = (idx - 1) >> 1; parent = array[pidx]; if (cmp(item, parent) < 0) { array[idx] = parent; idx = pidx; continue; } break; } return (array[idx] = item); } function siftup(array, idx, cmp) { var start = idx, end = array.length, item = array[idx], cidx = 2 * idx + 1, ridx; while (cidx < end) { ridx = cidx + 1; if (ridx < end && cmp(array[cidx], array[ridx]) >= 0) { cidx = ridx; } array[idx] = array[cidx]; idx = cidx; cidx = 2 * idx + 1; } array[idx] = item; return siftdown(array, start, idx, cmp); } /** * A dataflow graph for reactive processing of data streams. * @constructor */ function Dataflow() { this._log = logger(); this.logLevel(Error$1); this._clock = 0; this._rank = 0; this._loader = loader(); this._touched = UniqueList(id); this._pulses = {}; this._pulse = null; this._heap = new Heap(function(a, b) { return a.qrank - b.qrank; }); this._postrun = []; } var prototype = Dataflow.prototype; /** * The current timestamp of this dataflow. This value reflects the * timestamp of the previous dataflow run. The dataflow is initialized * with a stamp value of 0. The initial run of the dataflow will have * a timestap of 1, and so on. This value will match the * {@link Pulse.stamp} property. * @return {number} - The current timestamp value. */ prototype.stamp = function() { return this._clock; }; /** * Gets or sets the loader instance to use for data file loading. A * loader object must provide a "load" method for loading files and a * "sanitize" method for checking URL/filename validity. Both methods * should accept a URI and options hash as arguments, and return a Promise * that resolves to the loaded file contents (load) or a hash containing * sanitized URI data with the sanitized url assigned to the "href" property * (sanitize). * @param {object} _ - The loader instance to use. * @return {object|Dataflow} - If no arguments are provided, returns * the current loader instance. Otherwise returns this Dataflow instance. */ prototype.loader = function(_) { if (arguments.length) { this._loader = _; return this; } else { return this._loader; } }; /** * Empty entry threshold for garbage cleaning. Map data structures will * perform cleaning once the number of empty entries exceeds this value. */ prototype.cleanThreshold = 1e4; // OPERATOR REGISTRATION prototype.add = add; prototype.connect = connect; prototype.rank = rank; prototype.rerank = rerank; // OPERATOR UPDATES prototype.pulse = pulse; prototype.touch = touch; prototype.update = update; prototype.changeset = changeset; // DATA LOADING prototype.ingest = ingest$1; prototype.request = request; // EVENT HANDLING prototype.events = events; prototype.on = on; // PULSE PROPAGATION prototype.run = run; prototype.runAsync = runAsync; prototype.runAfter = runAfter; prototype._enqueue = enqueue; prototype._getPulse = getPulse; // LOGGING AND ERROR HANDLING function logMethod(method) { return function() { return this._log[method].apply(this, arguments); }; } /** * Logs an error message. By default, logged messages are written to console * output. The message will only be logged if the current log level is high * enough to permit error messages. */ prototype.error = logMethod('error'); /** * Logs a warning message. By default, logged messages are written to console * output. The message will only be logged if the current log level is high * enough to permit warning messages. */ prototype.warn = logMethod('warn'); /** * Logs a information message. By default, logged messages are written to * console output. The message will only be logged if the current log level is * high enough to permit information messages. */ prototype.info = logMethod('info'); /** * Logs a debug message. By default, logged messages are written to console * output. The message will only be logged if the current log level is high * enough to permit debug messages. */ prototype.debug = logMethod('debug'); /** * Get or set the current log level. If an argument is provided, it * will be used as the new log level. * @param {number} [level] - Should be one of None, Warn, Info * @return {number} - The current log level. */ prototype.logLevel = logMethod('level'); /** * Abstract class for operators that process data tuples. * Subclasses must provide a {@link transform} method for operator processing. * @constructor * @param {*} [init] - The initial value for this operator. * @param {object} [params] - The parameters for this operator. * @param {Operator} [source] - The operator from which to receive pulses. */ function Transform(init, params) { Operator.call(this, init, null, params); } var prototype$7 = inherits(Transform, Operator); /** * Overrides {@link Operator.evaluate} for transform operators. * Internally, this method calls {@link evaluate} to perform processing. * If {@link evaluate} returns a falsy value, the input pulse is returned. * This method should NOT be overridden, instead overrride {@link evaluate}. * @param {Pulse} pulse - the current dataflow pulse. * @return the output pulse for this operator (or StopPropagation) */ prototype$7.run = function(pulse) { if (pulse.stamp <= this.stamp) return pulse.StopPropagation; var rv; if (this.skip()) { this.skip(false); } else { rv = this.evaluate(pulse); } rv = rv || pulse; if (rv !== pulse.StopPropagation) this.pulse = rv; this.stamp = pulse.stamp; return rv; }; /** * Overrides {@link Operator.evaluate} for transform operators. * Marshalls parameter values and then invokes {@link transform}. * @param {Pulse} pulse - the current dataflow pulse. * @return {Pulse} The output pulse (or StopPropagation). A falsy return value (including undefined) will let the input pulse pass through. */ prototype$7.evaluate = function(pulse) { var params = this.marshall(pulse.stamp), out = this.transform(params, pulse); params.clear(); return out; }; /** * Process incoming pulses. * Subclasses should override this method to implement transforms. * @param {Parameters} _ - The operator parameter values. * @param {Pulse} pulse - The current dataflow pulse. * @return {Pulse} The output pulse (or StopPropagation). A falsy return * value (including undefined) will let the input pulse pass through. */ prototype$7.transform = function() {}; var transforms = {}; function definition(type) { var t = transform(type); return t && t.Definition || null; } function transform(type) { type = type && type.toLowerCase(); return transforms.hasOwnProperty(type) ? transforms[type] : null; } // Utilities function multikey(f) { return function(x) { var n = f.length, i = 1, k = String(f[0](x)); for (; i 1 ? this.dev / (this.valid-1) : 0', req: ['mean'], idx: 1 }), 'variancep': measure({ name: 'variancep', set: 'this.valid > 1 ? this.dev / this.valid : 0', req: ['variance'], idx: 2 }), 'stdev': measure({ name: 'stdev', set: 'this.valid > 1 ? Math.sqrt(this.dev / (this.valid-1)) : 0', req: ['variance'], idx: 2 }), 'stdevp': measure({ name: 'stdevp', set: 'this.valid > 1 ? Math.sqrt(this.dev / this.valid) : 0', req: ['variance'], idx: 2 }), 'stderr': measure({ name: 'stderr', set: 'this.valid > 1 ? Math.sqrt(this.dev / (this.valid * (this.valid-1))) : 0', req: ['variance'], idx: 2 }), 'distinct': measure({ name: 'distinct', set: 'cell.data.distinct(this.get)', req: ['values'], idx: 3 }), 'ci0': measure({ name: 'ci0', set: 'cell.data.ci0(this.get)', req: ['values'], idx: 3 }), 'ci1': measure({ name: 'ci1', set: 'cell.data.ci1(this.get)', req: ['values'], idx: 3 }), 'median': measure({ name: 'median', set: 'cell.data.q2(this.get)', req: ['values'], idx: 3 }), 'q1': measure({ name: 'q1', set: 'cell.data.q1(this.get)', req: ['values'], idx: 3 }), 'q3': measure({ name: 'q3', set: 'cell.data.q3(this.get)', req: ['values'], idx: 3 }), 'argmin': measure({ name: 'argmin', init: 'this.argmin = null;', add: 'if (v < this.min) this.argmin = t;', rem: 'if (v <= this.min) this.argmin = null;', set: 'this.argmin || cell.data.argmin(this.get)', req: ['min'], str: ['values'], idx: 3 }), 'argmax': measure({ name: 'argmax', init: 'this.argmax = null;', add: 'if (v > this.max) this.argmax = t;', rem: 'if (v >= this.max) this.argmax = null;', set: 'this.argmax || cell.data.argmax(this.get)', req: ['max'], str: ['values'], idx: 3 }), 'min': measure({ name: 'min', init: 'this.min = null;', add: 'if (v < this.min || this.min === null) this.min = v;', rem: 'if (v <= this.min) this.min = NaN;', set: 'this.min = (isNaN(this.min) ? cell.data.min(this.get) : this.min)', str: ['values'], idx: 4 }), 'max': measure({ name: 'max', init: 'this.max = null;', add: 'if (v > this.max || this.max === null) this.max = v;', rem: 'if (v >= this.max) this.max = NaN;', set: 'this.max = (isNaN(this.max) ? cell.data.max(this.get) : this.max)', str: ['values'], idx: 4 }) }; var ValidAggregateOps = Object.keys(AggregateOps); function createMeasure(op, name) { return AggregateOps[op](name); } function measure(base) { return function(out) { var m = extend({init:'', add:'', rem:'', idx:0}, base); m.out = out || base.name; return m; }; } function compareIndex(a, b) { return a.idx - b.idx; } function resolve(agg, stream) { function collect(m, a) { function helper(r) { if (!m[r]) collect(m, m[r] = AggregateOps[r]()); } if (a.req) a.req.forEach(helper); if (stream && a.str) a.str.forEach(helper); return m; } var map = agg.reduce( collect, agg.reduce(function(m, a) { m[a.name] = a; return m; }, {}) ); var values = [], key$$1; for (key$$1 in map) values.push(map[key$$1]); return values.sort(compareIndex); } function compileMeasures(agg, field$$1) { var get = field$$1 || identity, all = resolve(agg, true), // assume streaming removes may occur init = 'var cell = this.cell; this.valid = 0; this.missing = 0;', ctr = 'this.cell = cell; this.init();', add = 'if(v==null){++this.missing; return;} if(v!==v) return; ++this.valid;', rem = 'if(v==null){--this.missing; return;} if(v!==v) return; --this.valid;', set = 'var cell = this.cell;'; all.forEach(function(a) { init += a.init; add += a.add; rem += a.rem; }); agg.slice().sort(compareIndex).forEach(function(a) { set += 't[\'' + a.out + '\']=' + a.set + ';'; }); set += 'return t;'; ctr = Function('cell', ctr); ctr.prototype.init = Function(init); ctr.prototype.add = Function('v', 't', add); ctr.prototype.rem = Function('v', 't', rem); ctr.prototype.set = Function('t', set); ctr.prototype.get = get; ctr.fields = agg.map(function(_) { return _.out; }); return ctr; } var bin = function(_) { // determine range var maxb = _.maxbins || 20, base = _.base || 10, logb = Math.log(base), div = _.divide || [5, 2], min = _.extent[0], max = _.extent[1], span = max - min, step, level, minstep, precision, v, i, n, eps; if (_.step) { // if step size is explicitly given, use that step = _.step; } else if (_.steps) { // if provided, limit choice to acceptable step sizes v = span / maxb; for (i=0, n=_.steps.length; i < n && _.steps[i] < v; ++i); step = _.steps[Math.max(0, i-1)]; } else { // else use span to determine step size level = Math.ceil(Math.log(maxb) / logb); minstep = _.minstep || 0; step = Math.max( minstep, Math.pow(base, Math.round(Math.log(span) / logb) - level) ); // increase step size if too many bins while (Math.ceil(span/step) > maxb) { step *= base; } // decrease step size if allowed for (i=0, n=div.length; i= minstep && span / v <= maxb) step = v; } } // update precision, min and max v = Math.log(step); precision = v >= 0 ? 0 : ~~(-v / logb) + 1; eps = Math.pow(base, -precision - 1); if (_.nice || _.nice === undefined) { v = Math.floor(min / step + eps) * step; min = min < v ? v - step : v; max = Math.ceil(max / step) * step; } return { start: min, stop: max, step: step }; }; var numbers = function(array, f) { var numbers = [], n = array.length, i = -1, a; if (f == null) { while (++i < n) if (!isNaN(a = number(array[i]))) numbers.push(a); } else { while (++i < n) if (!isNaN(a = number(f(array[i], i, array)))) numbers.push(a); } return numbers; }; function number(x) { return x === null ? NaN : +x; } var ascending = function(a, b) { return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; }; var bisector = function(compare) { if (compare.length === 1) compare = ascendingComparator(compare); return { left: function(a, x, lo, hi) { if (lo == null) lo = 0; if (hi == null) hi = a.length; while (lo < hi) { var mid = lo + hi >>> 1; if (compare(a[mid], x) < 0) lo = mid + 1; else hi = mid; } return lo; }, right: function(a, x, lo, hi) { if (lo == null) lo = 0; if (hi == null) hi = a.length; while (lo < hi) { var mid = lo + hi >>> 1; if (compare(a[mid], x) > 0) hi = mid; else lo = mid + 1; } return lo; } }; }; function ascendingComparator(f) { return function(d, x) { return ascending(f(d), x); }; } var ascendingBisect = bisector(ascending); var bisectRight = ascendingBisect.right; var bisectLeft = ascendingBisect.left; function pair(a, b) { return [a, b]; } var number$1 = function(x) { return x === null ? NaN : +x; }; var variance = function(values, valueof) { var n = values.length, m = 0, i = -1, mean = 0, value, delta, sum = 0; if (valueof == null) { while (++i < n) { if (!isNaN(value = number$1(values[i]))) { delta = value - mean; mean += delta / ++m; sum += delta * (value - mean); } } } else { while (++i < n) { if (!isNaN(value = number$1(valueof(values[i], i, values)))) { delta = value - mean; mean += delta / ++m; sum += delta * (value - mean); } } } if (m > 1) return sum / (m - 1); }; var extent = function(values, valueof) { var n = values.length, i = -1, value, min, max; if (valueof == null) { while (++i < n) { // Find the first comparable value. if ((value = values[i]) != null && value >= value) { min = max = value; while (++i < n) { // Compare the remaining values. if ((value = values[i]) != null) { if (min > value) min = value; if (max < value) max = value; } } } } } else { while (++i < n) { // Find the first comparable value. if ((value = valueof(values[i], i, values)) != null && value >= value) { min = max = value; while (++i < n) { // Compare the remaining values. if ((value = valueof(values[i], i, values)) != null) { if (min > value) min = value; if (max < value) max = value; } } } } } return [min, max]; }; var identity$1 = function(x) { return x; }; var sequence = function(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; }; var e10 = Math.sqrt(50); var e5 = Math.sqrt(10); var e2 = Math.sqrt(2); var ticks = function(start, stop, count) { var reverse = stop < start, i = -1, n, ticks, step; if (reverse) n = start, start = stop, stop = n; if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return []; if (step > 0) { start = Math.ceil(start / step); stop = Math.floor(stop / step); ticks = new Array(n = Math.ceil(stop - start + 1)); while (++i < n) ticks[i] = (start + i) * step; } else { start = Math.floor(start * step); stop = Math.ceil(stop * step); ticks = new Array(n = Math.ceil(start - stop + 1)); while (++i < n) ticks[i] = (start - i) / step; } if (reverse) ticks.reverse(); return ticks; }; function tickIncrement(start, stop, count) { var step = (stop - start) / Math.max(0, count), power = Math.floor(Math.log(step) / Math.LN10), error = step / Math.pow(10, power); return power >= 0 ? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power) : -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1); } function tickStep(start, stop, count) { var step0 = Math.abs(stop - start) / Math.max(0, count), step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)), error = step0 / step1; if (error >= e10) step1 *= 10; else if (error >= e5) step1 *= 5; else if (error >= e2) step1 *= 2; return stop < start ? -step1 : step1; } var thresholdSturges = function(values) { return Math.ceil(Math.log(values.length) / Math.LN2) + 1; }; var threshold = function(values, p, valueof) { if (valueof == null) valueof = number$1; if (!(n = values.length)) return; if ((p = +p) <= 0 || n < 2) return +valueof(values[0], 0, values); if (p >= 1) return +valueof(values[n - 1], n - 1, values); var n, i = (n - 1) * p, i0 = Math.floor(i), value0 = +valueof(values[i0], i0, values), value1 = +valueof(values[i0 + 1], i0 + 1, values); return value0 + (value1 - value0) * (i - i0); }; var max = function(values, valueof) { var n = values.length, i = -1, value, max; if (valueof == null) { while (++i < n) { // Find the first comparable value. if ((value = values[i]) != null && value >= value) { max = value; while (++i < n) { // Compare the remaining values. if ((value = values[i]) != null && value > max) { max = value; } } } } } else { while (++i < n) { // Find the first comparable value. if ((value = valueof(values[i], i, values)) != null && value >= value) { max = value; while (++i < n) { // Compare the remaining values. if ((value = valueof(values[i], i, values)) != null && value > max) { max = value; } } } } } return max; }; var mean = function(values, valueof) { var n = values.length, m = n, i = -1, value, sum = 0; if (valueof == null) { while (++i < n) { if (!isNaN(value = number$1(values[i]))) sum += value; else --m; } } else { while (++i < n) { if (!isNaN(value = number$1(valueof(values[i], i, values)))) sum += value; else --m; } } if (m) return sum / m; }; var median = function(values, valueof) { var n = values.length, i = -1, value, numbers = []; if (valueof == null) { while (++i < n) { if (!isNaN(value = number$1(values[i]))) { numbers.push(value); } } } else { while (++i < n) { if (!isNaN(value = number$1(valueof(values[i], i, values)))) { numbers.push(value); } } } return threshold(numbers.sort(ascending), 0.5); }; var merge$2 = function(arrays) { var n = arrays.length, m, i = -1, j = 0, merged, array; while (++i < n) j += arrays[i].length; merged = new Array(j); while (--n >= 0) { array = arrays[n]; m = array.length; while (--m >= 0) { merged[--j] = array[m]; } } return merged; }; var min = function(values, valueof) { var n = values.length, i = -1, value, min; if (valueof == null) { while (++i < n) { // Find the first comparable value. if ((value = values[i]) != null && value >= value) { min = value; while (++i < n) { // Compare the remaining values. if ((value = values[i]) != null && min > value) { min = value; } } } } } else { while (++i < n) { // Find the first comparable value. if ((value = valueof(values[i], i, values)) != null && value >= value) { min = value; while (++i < n) { // Compare the remaining values. if ((value = valueof(values[i], i, values)) != null && min > value) { min = value; } } } } } return min; }; var permute = function(array, indexes) { var i = indexes.length, permutes = new Array(i); while (i--) permutes[i] = array[indexes[i]]; return permutes; }; var sum = function(values, valueof) { var n = values.length, i = -1, value, sum = 0; if (valueof == null) { while (++i < n) { if (value = +values[i]) sum += value; // Note: zero and null are equivalent. } } else { while (++i < n) { if (value = +valueof(values[i], i, values)) sum += value; } } return sum; }; function length(d) { return d.length; } var bootstrapCI = function(array, samples, alpha, f) { var values = numbers(array, f), n = values.length, m = samples, a, i, j, mu; for (j=0, mu=Array(m); j= a && x < b) ? 1 / d : 0; }; dist.cdf = function(x) { var v = Math.floor(x); return v < a ? 0 : v >= b ? 1 : (v - a + 1) / d; }; dist.icdf = function(p) { return (p >= 0 && p <= 1) ? a - 1 + Math.floor(p * d) : NaN; }; return dist.min(min).max(max); }; var randomNormal = function(mean, stdev) { var mu, sigma, next = NaN, dist = {}; dist.mean = function(_) { if (arguments.length) { mu = _ || 0; next = NaN; return dist; } else { return mu; } }; dist.stdev = function(_) { if (arguments.length) { sigma = _ == null ? 1 : _; next = NaN; return dist; } else { return sigma; } }; dist.sample = function() { var x = 0, y = 0, rds, c; if (next === next) { x = next; next = NaN; return x; } do { x = Math.random() * 2 - 1; y = Math.random() * 2 - 1; rds = x * x + y * y; } while (rds === 0 || rds > 1); c = Math.sqrt(-2 * Math.log(rds) / rds); // Box-Muller transform next = mu + y * c * sigma; return mu + x * c * sigma; }; dist.pdf = function(x) { var exp = Math.exp(Math.pow(x-mu, 2) / (-2 * Math.pow(sigma, 2))); return (1 / (sigma * Math.sqrt(2*Math.PI))) * exp; }; // Approximation from West (2009) // Better Approximations to Cumulative Normal Functions dist.cdf = function(x) { var cd, z = (x - mu) / sigma, Z = Math.abs(z); if (Z > 37) { cd = 0; } else { var sum, exp = Math.exp(-Z*Z/2); if (Z < 7.07106781186547) { sum = 3.52624965998911e-02 * Z + 0.700383064443688; sum = sum * Z + 6.37396220353165; sum = sum * Z + 33.912866078383; sum = sum * Z + 112.079291497871; sum = sum * Z + 221.213596169931; sum = sum * Z + 220.206867912376; cd = exp * sum; sum = 8.83883476483184e-02 * Z + 1.75566716318264; sum = sum * Z + 16.064177579207; sum = sum * Z + 86.7807322029461; sum = sum * Z + 296.564248779674; sum = sum * Z + 637.333633378831; sum = sum * Z + 793.826512519948; sum = sum * Z + 440.413735824752; cd = cd / sum; } else { sum = Z + 0.65; sum = Z + 4 / sum; sum = Z + 3 / sum; sum = Z + 2 / sum; sum = Z + 1 / sum; cd = exp / sum / 2.506628274631; } } return z > 0 ? 1 - cd : cd; }; // Approximation of Probit function using inverse error function. dist.icdf = function(p) { if (p <= 0 || p >= 1) return NaN; var x = 2*p - 1, v = (8 * (Math.PI - 3)) / (3 * Math.PI * (4-Math.PI)), a = (2 / (Math.PI*v)) + (Math.log(1 - Math.pow(x,2)) / 2), b = Math.log(1 - (x*x)) / v, s = (x > 0 ? 1 : -1) * Math.sqrt(Math.sqrt((a*a) - b) - a); return mu + sigma * Math.SQRT2 * s; }; return dist.mean(mean).stdev(stdev); }; var quartiles = function(array, f) { var values = numbers(array, f); return [ threshold(values.sort(ascending), 0.25), threshold(values, 0.50), threshold(values, 0.75) ]; }; // TODO: support for additional kernels? var randomKDE = function(support, bandwidth) { var kernel = randomNormal(), dist = {}, n = 0; dist.data = function(_) { if (arguments.length) { support = _; n = _ ? _.length : 0; return dist.bandwidth(bandwidth); } else { return support; } }; dist.bandwidth = function(_) { if (!arguments.length) return bandwidth; bandwidth = _; if (!bandwidth && support) bandwidth = estimateBandwidth(support); return dist; }; dist.sample = function() { return support[~~(Math.random() * n)] + bandwidth * kernel.sample(); }; dist.pdf = function(x) { for (var y=0, i=0; i= a && x <= b) ? 1 / d : 0; }; dist.cdf = function(x) { return x < a ? 0 : x > b ? 1 : (x - a) / d; }; dist.icdf = function(p) { return (p >= 0 && p <= 1) ? a + p * d : NaN; }; return dist.min(min).max(max); }; function TupleStore(key$$1) { this._key = key$$1 ? field(key$$1) : tupleid; this.reset(); } var prototype$9 = TupleStore.prototype; prototype$9.reset = function() { this._add = []; this._rem = []; this._ext = null; this._get = null; this._q = null; }; prototype$9.add = function(v) { this._add.push(v); }; prototype$9.rem = function(v) { this._rem.push(v); }; prototype$9.values = function() { this._get = null; if (this._rem.length === 0) return this._add; var a = this._add, r = this._rem, k = this._key, n = a.length, m = r.length, x = Array(n - m), map = {}, i, j, v; // use unique key field to clear removed values for (i=0; i= 0) { s = get(v[n]) + ''; if (!map.hasOwnProperty(s)) { map[s] = 1; ++count; } } return count; }; prototype$9.extent = function(get) { if (this._get !== get || !this._ext) { var v = this.values(), i = extentIndex(v, get); this._ext = [v[i[0]], v[i[1]]]; this._get = get; } return this._ext; }; prototype$9.argmin = function(get) { return this.extent(get)[0] || {}; }; prototype$9.argmax = function(get) { return this.extent(get)[1] || {}; }; prototype$9.min = function(get) { var m = this.extent(get)[0]; return m != null ? get(m) : +Infinity; }; prototype$9.max = function(get) { var m = this.extent(get)[1]; return m != null ? get(m) : -Infinity; }; prototype$9.quartile = function(get) { if (this._get !== get || !this._q) { this._q = quartiles(this.values(), get); this._get = get; } return this._q; }; prototype$9.q1 = function(get) { return this.quartile(get)[0]; }; prototype$9.q2 = function(get) { return this.quartile(get)[1]; }; prototype$9.q3 = function(get) { return this.quartile(get)[2]; }; prototype$9.ci = function(get) { if (this._get !== get || !this._ci) { this._ci = bootstrapCI(this.values(), 1000, 0.05, get); this._get = get; } return this._ci; }; prototype$9.ci0 = function(get) { return this.ci(get)[0]; }; prototype$9.ci1 = function(get) { return this.ci(get)[1]; }; /** * Group-by aggregation operator. * @constructor * @param {object} params - The parameters for this operator. * @param {Array} [params.groupby] - An array of accessors to groupby. * @param {Array} [params.fields] - An array of accessors to aggregate. * @param {Array} [params.ops] - An array of strings indicating aggregation operations. * @param {Array} [params.as] - An array of output field names for aggregated values. * @param {boolean} [params.cross=false] - A flag indicating that the full * cross-product of groupby values should be generated, including empty cells. * If true, the drop parameter is ignored and empty cells are retained. * @param {boolean} [params.drop=true] - A flag indicating if empty cells should be removed. */ function Aggregate(params) { Transform.call(this, null, params); this._adds = []; // array of added output tuples this._mods = []; // array of modified output tuples this._alen = 0; // number of active added tuples this._mlen = 0; // number of active modified tuples this._drop = true; // should empty aggregation cells be removed this._cross = false; // produce full cross-product of group-by values this._dims = []; // group-by dimension accessors this._dnames = []; // group-by dimension names this._measures = []; // collection of aggregation monoids this._countOnly = false; // flag indicating only count aggregation this._counts = null; // collection of count fields this._prev = null; // previous aggregation cells this._inputs = null; // array of dependent input tuple field names this._outputs = null; // array of output tuple field names } Aggregate.Definition = { "type": "Aggregate", "metadata": {"generates": true, "changes": true}, "params": [ { "name": "groupby", "type": "field", "array": true }, { "name": "ops", "type": "enum", "array": true, "values": ValidAggregateOps }, { "name": "fields", "type": "field", "null": true, "array": true }, { "name": "as", "type": "string", "null": true, "array": true }, { "name": "drop", "type": "boolean", "default": true }, { "name": "cross", "type": "boolean", "default": false }, { "name": "key", "type": "field" } ] }; var prototype$8 = inherits(Aggregate, Transform); prototype$8.transform = function(_, pulse) { var aggr = this, out = pulse.fork(pulse.NO_SOURCE | pulse.NO_FIELDS), mod; this.stamp = out.stamp; if (this.value && ((mod = _.modified()) || pulse.modified(this._inputs))) { this._prev = this.value; this.value = mod ? this.init(_) : {}; pulse.visit(pulse.SOURCE, function(t) { aggr.add(t); }); } else { this.value = this.value || this.init(_); pulse.visit(pulse.REM, function(t) { aggr.rem(t); }); pulse.visit(pulse.ADD, function(t) { aggr.add(t); }); } // Indicate output fields and return aggregate tuples. out.modifies(this._outputs); // Should empty cells be dropped? aggr._drop = _.drop !== false; // If domain cross-product requested, generate empty cells as needed // and ensure that empty cells are not dropped if (_.cross && aggr._dims.length > 1) { aggr._drop = false; this.cross(); } return aggr.changes(out); }; prototype$8.cross = function() { var aggr = this, curr = aggr.value, dims = aggr._dnames, vals = dims.map(function() { return {}; }), n = dims.length; // collect all group-by domain values function collect(cells) { var key$$1, i, t, v; for (key$$1 in cells) { t = cells[key$$1].tuple; for (i=0; i} params.fields - The fields to compare. * @param {Array} [params.orders] - The sort orders. * Each entry should be one of "ascending" (default) or "descending". */ function Compare(params) { Operator.call(this, null, update$1, params); } inherits(Compare, Operator); function update$1(_) { return (this.value && !_.modified()) ? this.value : compare(_.fields, _.orders); } /** * Count regexp-defined pattern occurrences in a text field. * @constructor * @param {object} params - The parameters for this operator. * @param {function(object): *} params.field - An accessor for the text field. * @param {string} [params.pattern] - RegExp string defining the text pattern. * @param {string} [params.case] - One of 'lower', 'upper' or null (mixed) case. * @param {string} [params.stopwords] - RegExp string of words to ignore. */ function CountPattern(params) { Transform.call(this, null, params); } CountPattern.Definition = { "type": "CountPattern", "metadata": {"generates": true, "changes": true}, "params": [ { "name": "field", "type": "field", "required": true }, { "name": "case", "type": "enum", "values": ["upper", "lower", "mixed"], "default": "mixed" }, { "name": "pattern", "type": "string", "default": "[\\w\"]+" }, { "name": "stopwords", "type": "string", "default": "" }, { "name": "as", "type": "string", "array": true, "length": 2, "default": ["text", "count"] } ] }; function tokenize(text, tcase, match) { switch (tcase) { case 'upper': text = text.toUpperCase(); break; case 'lower': text = text.toLowerCase(); break; } return text.match(match); } var prototype$12 = inherits(CountPattern, Transform); prototype$12.transform = function(_, pulse) { function process(update) { return function(tuple) { var tokens = tokenize(get(tuple), _.case, match) || [], t; for (var i=0, n=tokens.length; i} [params.as] - The names of the output fields. */ function Cross(params) { Transform.call(this, null, params); } Cross.Definition = { "type": "Cross", "metadata": {"source": true, "generates": true, "changes": true}, "params": [ { "name": "filter", "type": "expr" }, { "name": "as", "type": "string", "array": true, "length": 2, "default": ["a", "b"] } ] }; var prototype$13 = inherits(Cross, Transform); prototype$13.transform = function(_, pulse) { var out = pulse.fork(pulse.NO_SOURCE), data = this.value, as = _.as || ['a', 'b'], a = as[0], b = as[1], reset = !data || pulse.changed(pulse.ADD_REM) || _.modified('as') || _.modified('filter'); if (reset) { if (data) out.rem = data; out.add = this.value = cross$1(pulse.source, a, b, _.filter || truthy); } else { out.mod = data; } out.source = this.value; return out.modifies(as); }; function cross$1(input, a, b, filter) { var data = [], t = {}, n = input.length, i = 0, j, left; for (; i} - A method for requesting * source data. Used for distributions (such as KDE) that * require sample data points. This method will only be * invoked if the 'from' parameter for a target data source * is not provided. Typically this method returns backing * source data for a Pulse object. * @return {object} - The output distribution object. */ function parse$1(def, data) { var func = def[FUNCTION]; if (!Distributions.hasOwnProperty(func)) { error$1('Unknown distribution function: ' + func); } var d = Distributions[func](); for (var name in def) { // if data field, extract values if (name === FIELD) { d.data((def.from || data()).map(def[name])); } // if distribution mixture, recurse to parse each definition else if (name === DISTRIBUTIONS) { d[name](def[name].map(function(_) { return parse$1(_, data); })); } // otherwise, simply set the parameter else if (typeof d[name] === FUNCTION) { d[name](def[name]); } } return d; } /** * Grid sample points for a probability density. Given a distribution and * a sampling extent, will generate points suitable for plotting either * PDF (probability density function) or CDF (cumulative distribution * function) curves. * @constructor * @param {object} params - The parameters for this operator. * @param {object} params.distribution - The probability distribution. This * is an object parameter dependent on the distribution type. * @param {string} [params.method='pdf'] - The distribution method to sample. * One of 'pdf' or 'cdf'. * @param {Array} [params.extent] - The [min, max] extent over which * to sample the distribution. This argument is required in most cases, but * can be omitted if the distribution (e.g., 'kde') supports a 'data' method * that returns numerical sample points from which the extent can be deduced. * @param {number} [params.steps=100] - The number of sampling steps. */ function Density(params) { Transform.call(this, null, params); } var distributions = [ { "key": {"function": "normal"}, "params": [ { "name": "mean", "type": "number", "default": 0 }, { "name": "stdev", "type": "number", "default": 1 } ] }, { "key": {"function": "uniform"}, "params": [ { "name": "min", "type": "number", "default": 0 }, { "name": "max", "type": "number", "default": 1 } ] }, { "key": {"function": "kde"}, "params": [ { "name": "field", "type": "field", "required": true }, { "name": "from", "type": "data" }, { "name": "bandwidth", "type": "number", "default": 0 } ] } ]; var mixture = { "key": {"function": "mixture"}, "params": [ { "name": "distributions", "type": "param", "array": true, "params": distributions }, { "name": "weights", "type": "number", "array": true } ] }; Density.Definition = { "type": "Density", "metadata": {"generates": true, "source": true}, "params": [ { "name": "extent", "type": "number", "array": true, "length": 2 }, { "name": "steps", "type": "number", "default": 100 }, { "name": "method", "type": "string", "default": "pdf", "values": ["pdf", "cdf"] }, { "name": "distribution", "type": "param", "params": distributions.concat(mixture) }, { "name": "as", "type": "string", "array": true, "default": ["value", "density"] } ] }; var prototype$14 = inherits(Density, Transform); prototype$14.transform = function(_, pulse) { var out = pulse.fork(pulse.NO_SOURCE | pulse.NO_FIELDS); if (!this.value || pulse.changed() || _.modified()) { var dist = parse$1(_.distribution, source(pulse)), method = _.method || 'pdf'; if (method !== 'pdf' && method !== 'cdf') { error$1('Invalid density method: ' + method); } if (!_.extent && !dist.data) { error$1('Missing density extent parameter.'); } method = dist[method]; var as = _.as || ['value', 'density'], domain = _.extent || extent(dist.data()), step = (domain[1] - domain[0]) / (_.steps || 100), values = sequence(domain[0], domain[1] + step/2, step) .map(function(v) { var tuple = {}; tuple[as[0]] = v; tuple[as[1]] = method(v); return ingest(tuple); }); if (this.value) out.rem = this.value; this.value = out.add = out.source = values; } return out; }; function source(pulse) { return function() { return pulse.materialize(pulse.SOURCE).source; }; } /** * Computes extents (min/max) for a data field. * @constructor * @param {object} params - The parameters for this operator. * @param {function(object): *} params.field - The field over which to compute extends. */ function Extent(params) { Transform.call(this, [+Infinity, -Infinity], params); } Extent.Definition = { "type": "Extent", "metadata": {}, "params": [ { "name": "field", "type": "field", "required": true } ] }; var prototype$15 = inherits(Extent, Transform); prototype$15.transform = function(_, pulse) { var extent = this.value, field$$1 = _.field, min = extent[0], max = extent[1], flag = pulse.ADD, mod; mod = pulse.changed() || pulse.modified(field$$1.fields) || _.modified('field'); if (mod) { flag = pulse.SOURCE; min = +Infinity; max = -Infinity; } pulse.visit(flag, function(t) { var v = field$$1(t); if (v < min) min = v; if (v > max) max = v; }); this.value = [min, max]; }; /** * Provides a bridge between a parent transform and a target subflow that * consumes only a subset of the tuples that pass through the parent. * @constructor * @param {Pulse} pulse - A pulse to use as the value of this operator. * @param {Transform} parent - The parent transform (typically a Facet instance). * @param {Transform} target - A transform that receives the subflow of tuples. */ function Subflow(pulse, parent) { Operator.call(this, pulse); this.parent = parent; } var prototype$17 = inherits(Subflow, Operator); prototype$17.connect = function(target) { this.targets().add(target); return (target.source = this); }; /** * Add an 'add' tuple to the subflow pulse. * @param {Tuple} t - The tuple being added. */ prototype$17.add = function(t) { this.value.add.push(t); }; /** * Add a 'rem' tuple to the subflow pulse. * @param {Tuple} t - The tuple being removed. */ prototype$17.rem = function(t) { this.value.rem.push(t); }; /** * Add a 'mod' tuple to the subflow pulse. * @param {Tuple} t - The tuple being modified. */ prototype$17.mod = function(t) { this.value.mod.push(t); }; /** * Re-initialize this operator's pulse value. * @param {Pulse} pulse - The pulse to copy from. * @see Pulse.init */ prototype$17.init = function(pulse) { this.value.init(pulse, pulse.NO_SOURCE); }; /** * Evaluate this operator. This method overrides the * default behavior to simply return the contained pulse value. * @return {Pulse} */ prototype$17.evaluate = function() { // assert: this.value.stamp === pulse.stamp return this.value; }; /** * Facets a dataflow into a set of subflows based on a key. * @constructor * @param {object} params - The parameters for this operator. * @param {function(Dataflow, string): Operator} params.subflow - A function * that generates a subflow of operators and returns its root operator. * @param {function(object): *} params.key - The key field to facet by. */ function Facet(params) { Transform.call(this, {}, params); this._keys = fastmap(); // cache previously calculated key values // keep track of active subflows, use as targets array for listeners // this allows us to limit propagation to only updated subflows var a = this._targets = []; a.active = 0; a.forEach = function(f) { for (var i=0, n=a.active; i df.cleanThreshold) df.runAfter(cache.clean); return pulse; }; /** * Generates one or more field accessor functions. * If the 'name' parameter is an array, an array of field accessors * will be created and the 'as' parameter will be ignored. * @constructor * @param {object} params - The parameters for this operator. * @param {string} params.name - The field name(s) to access. * @param {string} params.as - The accessor function name. */ function Field(params) { Operator.call(this, null, update$2, params); } inherits(Field, Operator); function update$2(_) { return (this.value && !_.modified()) ? this.value : isArray(_.name) ? array(_.name).map(function(f) { return field(f); }) : field(_.name, _.as); } /** * Filters data tuples according to a predicate function. * @constructor * @param {object} params - The parameters for this operator. * @param {function(object): *} params.expr - The predicate expression function * that determines a tuple's filter status. Truthy values pass the filter. */ function Filter(params) { Transform.call(this, fastmap(), params); } Filter.Definition = { "type": "Filter", "metadata": {"changes": true}, "params": [ { "name": "expr", "type": "expr", "required": true } ] }; var prototype$18 = inherits(Filter, Transform); prototype$18.transform = function(_, pulse) { var df = pulse.dataflow, cache = this.value, // cache ids of filtered tuples output = pulse.fork(), add = output.add, rem = output.rem, mod = output.mod, test = _.expr, isMod = true; pulse.visit(pulse.REM, function(t) { var id$$1 = tupleid(t); if (!cache.has(id$$1)) rem.push(t); else cache.delete(id$$1); }); pulse.visit(pulse.ADD, function(t) { if (test(t, _)) add.push(t); else cache.set(tupleid(t), 1); }); function revisit(t) { var id$$1 = tupleid(t), b = test(t, _), s = cache.get(id$$1); if (b && s) { cache.delete(id$$1); add.push(t); } else if (!b && !s) { cache.set(id$$1, 1); rem.push(t); } else if (isMod && b && !s) { mod.push(t); } } pulse.visit(pulse.MOD, revisit); if (_.modified()) { isMod = false; pulse.visit(pulse.REFLOW, revisit); } if (cache.empty > df.cleanThreshold) df.runAfter(cache.clean); return output; }; /** * Folds one more tuple fields into multiple tuples in which the field * name and values are available under new 'key' and 'value' fields. * @constructor * @param {object} params - The parameters for this operator. * @param {function(object): *} params.fields - An array of field accessors * for the tuple fields that should be folded. */ function Fold(params) { Transform.call(this, {}, params); } Fold.Definition = { "type": "Fold", "metadata": {"generates": true, "changes": true}, "params": [ { "name": "fields", "type": "field", "array": true, "required": true }, { "name": "as", "type": "string", "array": true, "length": 2, "default": ["key", "value"] } ] }; var prototype$19 = inherits(Fold, Transform); function keyFunction(f) { return f.fields.join('|'); } prototype$19.transform = function(_, pulse) { var cache = this.value, reset = _.modified('fields'), fields = _.fields, as = _.as || ['key', 'value'], key$$1 = as[0], value = as[1], keys = fields.map(keyFunction), n = fields.length, stamp = pulse.stamp, out = pulse.fork(pulse.NO_SOURCE), i = 0, mask = 0, id$$1; function add(t) { var f = (cache[tupleid(t)] = Array(n)); // create cache of folded tuples for (var i=0, ft; i 0) { // need more tuples, generate and add for (add=[]; --num >= 0;) { add.push(t = ingest(gen(_))); data.push(t); } out.add = out.add.length ? out.materialize(out.ADD).add.concat(add) : add; } else { // need fewer tuples, remove rem = data.slice(0, -num); out.rem = out.rem.length ? out.materialize(out.REM).rem.concat(rem) : rem; data = data.slice(-num); } out.source = this.value = data; return out; }; var Methods = { value: 'value', median: median, mean: mean, min: min, max: max }; var Empty = []; /** * Impute missing values. * @constructor * @param {object} params - The parameters for this operator. * @param {function(object): *} params.field - The value field to impute. * @param {Array} [params.groupby] - An array of * accessors to determine series within which to perform imputation. * @param {function(object): *} params.key - An accessor for a key value. * Each key value should be unique within a group. New tuples will be * imputed for any key values that are not found within a group. * @param {Array<*>} [params.keyvals] - Optional array of required key * values. New tuples will be imputed for any key values that are not * found within a group. In addition, these values will be automatically * augmented with the key values observed in the input data. * @param {string} [method='value'] - The imputation method to use. One of * 'value', 'mean', 'median', 'max', 'min'. * @param {*} [value=0] - The constant value to use for imputation * when using method 'value'. */ function Impute(params) { Transform.call(this, [], params); } Impute.Definition = { "type": "Impute", "metadata": {"changes": true}, "params": [ { "name": "field", "type": "field", "required": true }, { "name": "key", "type": "field", "required": true }, { "name": "keyvals", "array": true }, { "name": "groupby", "type": "field", "array": true }, { "name": "method", "type": "enum", "default": "value", "values": ["value", "mean", "median", "max", "min"] }, { "name": "value", "default": 0 } ] }; var prototype$22 = inherits(Impute, Transform); function getValue(_) { var m = _.method || Methods.value, v; if (Methods[m] == null) { error$1('Unrecognized imputation method: ' + m); } else if (m === Methods.value) { v = _.value !== undefined ? _.value : 0; return function() { return v; }; } else { return Methods[m]; } } function getField(_) { var f = _.field; return function(t) { return t ? f(t) : NaN; }; } prototype$22.transform = function(_, pulse) { var out = pulse.fork(pulse.ALL), impute = getValue(_), field$$1 = getField(_), fName = accessorName(_.field), kName = accessorName(_.key), gNames = (_.groupby || []).map(accessorName), groups = partition(pulse.source, _.groupby, _.key, _.keyvals), curr = [], prev = this.value, m = groups.domain.length, group, value, gVals, kVal, g, i, j, l, n, t; for (g=0, l=groups.length; g} params.fields - The field name(s) for the key function. */ function Key(params) { Operator.call(this, null, update$3, params); } inherits(Key, Operator); function update$3(_) { return (this.value && !_.modified()) ? this.value : key(_.fields); } /** * Extend tuples by joining them with values from a lookup table. * @constructor * @param {object} params - The parameters for this operator. * @param {Map} params.index - The lookup table map. * @param {Array} params.as - Output field names for each lookup value. * @param {*} [params.default] - A default value to use if lookup fails. */ function Lookup(params) { Transform.call(this, {}, params); } Lookup.Definition = { "type": "Lookup", "metadata": {"modifies": true}, "params": [ { "name": "index", "type": "index", "params": [ {"name": "from", "type": "data", "required": true }, {"name": "key", "type": "field", "required": true } ] }, { "name": "values", "type": "field", "array": true }, { "name": "fields", "type": "field", "array": true, "required": true }, { "name": "as", "type": "string", "array": true }, { "name": "default", "default": null } ] }; var prototype$24 = inherits(Lookup, Transform); prototype$24.transform = function(_, pulse) { var out = pulse, as = _.as, keys = _.fields, index = _.index, values = _.values, defaultValue = _.default==null ? null : _.default, reset = _.modified(), flag = reset ? pulse.SOURCE : pulse.ADD, n = keys.length, set, m, mods; if (values) { m = values.length; if (n > 1 && !as) { error$1('Multi-field lookup requires explicit "as" parameter.'); } if (as && as.length !== n * m) { error$1('The "as" parameter has too few output field names.'); } as = as || values.map(accessorName); set = function(t) { for (var i=0, k=0, j, v; i>} params.extents - The input extents. */ function MultiExtent(params) { Operator.call(this, null, update$4, params); } inherits(MultiExtent, Operator); function update$4(_) { if (this.value && !_.modified()) { return this.value; } var min = +Infinity, max = -Infinity, ext = _.extents, i, n, e; for (i=0, n=ext.length; i max) max = e[1]; } return [min, max]; } /** * Merge a collection of value arrays. * @constructor * @param {object} params - The parameters for this operator. * @param {Array>} params.values - The input value arrrays. */ function MultiValues(params) { Operator.call(this, null, update$5, params); } inherits(MultiValues, Operator); function update$5(_) { return (this.value && !_.modified()) ? this.value : _.values.reduce(function(data, _) { return data.concat(_); }, []); } /** * Operator whose value is simply its parameter hash. This operator is * useful for enabling reactive updates to values of nested objects. * @constructor * @param {object} params - The parameters for this operator. */ function Params(params) { Transform.call(this, null, params); } inherits(Params, Transform); Params.prototype.transform = function(_, pulse) { this.modified(_.modified()); this.value = _; return pulse.fork(pulse.NO_SOURCE | pulse.NO_FIELDS); // do not pass tuples }; /** * Partitions pre-faceted data into tuple subflows. * @constructor * @param {object} params - The parameters for this operator. * @param {function(Dataflow, string): Operator} params.subflow - A function * that generates a subflow of operators and returns its root operator. * @param {function(object): Array} params.field - The field * accessor for an array of subflow tuple objects. */ function PreFacet(params) { Facet.call(this, params); } var prototype$25 = inherits(PreFacet, Facet); prototype$25.transform = function(_, pulse) { var self = this, flow = _.subflow, field$$1 = _.field; if (_.modified('field') || field$$1 && pulse.modified(accessorFields(field$$1))) { error$1('PreFacet does not support field modification.'); } this._targets.active = 0; // reset list of active subflows pulse.visit(pulse.MOD, function(t) { var sf = self.subflow(tupleid(t), flow, pulse, t); field$$1 ? field$$1(t).forEach(function(_) { sf.mod(_); }) : sf.mod(t); }); pulse.visit(pulse.ADD, function(t) { var sf = self.subflow(tupleid(t), flow, pulse, t); field$$1 ? field$$1(t).forEach(function(_) { sf.add(ingest(_)); }) : sf.add(t); }); pulse.visit(pulse.REM, function(t) { var sf = self.subflow(tupleid(t), flow, pulse, t); field$$1 ? field$$1(t).forEach(function(_) { sf.rem(_); }) : sf.rem(t); }); return pulse; }; /** * Proxy the value of another operator as a pure signal value. * Ensures no tuples are propagated. * @constructor * @param {object} params - The parameters for this operator. * @param {*} params.value - The value to proxy, becomes the value of this operator. */ function Proxy(params) { Transform.call(this, null, params); } var prototype$26 = inherits(Proxy, Transform); prototype$26.transform = function(_, pulse) { this.value = _.value; return _.modified('value') ? pulse.fork(pulse.NO_SOURCE | pulse.NO_FIELDS) : pulse.StopPropagation; }; /** * Relays a data stream between data processing pipelines. * If the derive parameter is set, this transform will create derived * copies of observed tuples. This provides derived data streams in which * modifications to the tuples do not pollute an upstream data source. * @param {object} params - The parameters for this operator. * @param {number} [params.derive=false] - Boolean flag indicating if * the transform should make derived copies of incoming tuples. * @constructor */ function Relay(params) { Transform.call(this, null, params); } var prototype$27 = inherits(Relay, Transform); prototype$27.transform = function(_, pulse) { var out, lut; if (this.value) { lut = this.value; } else { out = pulse = pulse.addAll(); lut = this.value = {}; } if (_.derive) { out = pulse.fork(); pulse.visit(pulse.REM, function(t) { var id$$1 = tupleid(t); out.rem.push(lut[id$$1]); lut[id$$1] = null; }); pulse.visit(pulse.ADD, function(t) { var dt = derive(t); lut[tupleid(t)] = dt; out.add.push(dt); }); pulse.visit(pulse.MOD, function(t) { out.mod.push(rederive(t, lut[tupleid(t)])); }); } return out; }; /** * Samples tuples passing through this operator. * Uses reservoir sampling to maintain a representative sample. * @constructor * @param {object} params - The parameters for this operator. * @param {number} [params.size=1000] - The maximum number of samples. */ function Sample(params) { Transform.call(this, [], params); this.count = 0; } Sample.Definition = { "type": "Sample", "metadata": {"source": true, "changes": true}, "params": [ { "name": "size", "type": "number", "default": 1000 } ] }; var prototype$28 = inherits(Sample, Transform); prototype$28.transform = function(_, pulse) { var out = pulse.fork(), mod = _.modified('size'), num = _.size, res = this.value, cnt = this.count, cap = 0, map = res.reduce(function(m, t) { m[tupleid(t)] = 1; return m; }, {}); // sample reservoir update function function update(t) { var p, idx; if (res.length < num) { res.push(t); } else { idx = ~~((cnt + 1) * Math.random()); if (idx < res.length && idx >= cap) { p = res[idx]; if (map[tupleid(p)]) out.rem.push(p); // eviction res[idx] = t; } } ++cnt; } if (pulse.rem.length) { // find all tuples that should be removed, add to output pulse.visit(pulse.REM, function(t) { var id$$1 = tupleid(t); if (map[id$$1]) { map[id$$1] = -1; out.rem.push(t); } --cnt; }); // filter removed tuples out of the sample reservoir res = res.filter(function(t) { return map[tupleid(t)] !== -1; }); } if ((pulse.rem.length || mod) && res.length < num && pulse.source) { // replenish sample if backing data source is available cap = cnt = res.length; pulse.visit(pulse.SOURCE, function(t) { // update, but skip previously sampled tuples if (!map[tupleid(t)]) update(t); }); cap = -1; } if (mod && res.length > num) { for (var i=0, n=res.length-num; i df.cleanThreshold) df.runAfter(index.clean); return pulse.fork(); }; /** * Extracts an array of values. Assumes the source data has already been * reduced as needed (e.g., by an upstream Aggregate transform). * @constructor * @param {object} params - The parameters for this operator. * @param {function(object): *} params.field - The domain field to extract. * @param {function(*,*): number} [params.sort] - An optional * comparator function for sorting the values. The comparator will be * applied to backing tuples prior to value extraction. */ function Values(params) { Transform.call(this, null, params); } var prototype$32 = inherits(Values, Transform); prototype$32.transform = function(_, pulse) { var run = !this.value || _.modified('field') || _.modified('sort') || pulse.changed() || (_.sort && pulse.modified(_.sort.fields)); if (run) { this.value = (_.sort ? pulse.source.slice().sort(_.sort) : pulse.source).map(_.field); } }; function WindowOp(op, field$$1, param, as) { var fn = WindowOps[op](field$$1, param); return { init: fn.init || zero, update: function(w, t) { t[as] = fn.next(w); } }; } var WindowOps = { row_number: function() { return { next: function(w) { return w.index + 1; } }; }, rank: function() { var rank; return { init: function() { rank = 1; }, next: function(w) { var i = w.index, data = w.data; return (i && w.compare(data[i - 1], data[i])) ? (rank = i + 1) : rank; } }; }, dense_rank: function() { var drank; return { init: function() { drank = 1; }, next: function(w) { var i = w.index, d = w.data; return (i && w.compare(d[i - 1], d[i])) ? ++drank : drank; } }; }, percent_rank: function() { var rank = WindowOps.rank(), next = rank.next; return { init: rank.init, next: function(w) { return (next(w) - 1) / (w.data.length - 1); } }; }, cume_dist: function() { var cume; return { init: function() { cume = 0; }, next: function(w) { var i = w.index, d = w.data, c = w.compare; if (cume < i) { while (i + 1 < d.length && !c(d[i], d[i + 1])) ++i; cume = i; } return (1 + cume) / d.length; } }; }, ntile: function(field$$1, num) { num = +num; if (!(num > 0)) error$1('ntile num must be greater than zero.'); var cume = WindowOps.cume_dist(), next = cume.next; return { init: cume.init, next: function(w) { return Math.ceil(num * next(w)); } }; }, lag: function(field$$1, offset) { offset = +offset || 1; return { next: function(w) { var i = w.index - offset; return i >= 0 ? field$$1(w.data[i]) : null; } }; }, lead: function(field$$1, offset) { offset = +offset || 1; return { next: function(w) { var i = w.index + offset, d = w.data; return i < d.length ? field$$1(d[i]) : null; } }; }, first_value: function(field$$1) { return { next: function(w) { return field$$1(w.data[w.i0]); } }; }, last_value: function(field$$1) { return { next: function(w) { return field$$1(w.data[w.i1 - 1]); } } }, nth_value: function(field$$1, nth) { nth = +nth; if (!(nth > 0)) error$1('nth_value nth must be greater than zero.'); return { next: function(w) { var i = w.i0 + (nth - 1); return i < w.i1 ? field$$1(w.data[i]) : null; } } } }; var ValidWindowOps = Object.keys(WindowOps); function WindowState(_) { var self = this, ops = array(_.ops), fields = array(_.fields), params = array(_.params), as = array(_.as), outputs = self.outputs = [], windows = self.windows = [], inputs = {}, map = {}, countOnly = true, counts = [], measures = []; function visitInputs(f) { array(accessorFields(f)).forEach(function(_) { inputs[_] = 1; }); } visitInputs(_.sort); ops.forEach(function(op, i) { var field$$1 = fields[i], mname = accessorName(field$$1), name = measureName(op, mname, as[i]); visitInputs(field$$1); outputs.push(name); // Window operation if (WindowOps.hasOwnProperty(op)) { windows.push(WindowOp(op, fields[i], params[i], name)); } // Aggregate operation else { if (field$$1 == null && op !== 'count') { error$1('Null aggregate field specified.'); } if (op === 'count') { counts.push(name); return; } countOnly = false; var m = map[mname]; if (!m) { m = (map[mname] = []); m.field = field$$1; measures.push(m); } m.push(createMeasure(op, name)); } }); if (counts.length || measures.length) { self.cell = cell(measures, counts, countOnly); } self.inputs = Object.keys(inputs); } var prototype$34 = WindowState.prototype; prototype$34.init = function() { this.windows.forEach(function(_) { _.init(); }); if (this.cell) this.cell.init(); }; prototype$34.update = function(w, t) { var self = this, cell = self.cell, wind = self.windows, data = w.data, m = wind && wind.length, j; if (cell) { for (j=w.p0; j} [params.groupby] - An array of accessors by which to partition tuples into separate windows. * @param {Array} params.ops - An array of strings indicating window operations to perform. * @param {Array} [params.fields] - An array of accessors * for data fields to use as inputs to window operations. * @param {Array<*>} [params.params] - An array of parameter values for window operations. * @param {Array} [params.as] - An array of output field names for window operations. * @param {Array} [params.frame] - Window frame definition as two-element array. * @param {boolean} [params.ignorePeers=false] - If true, base window frame boundaries on row * number alone, ignoring peers with identical sort values. If false (default), * the window boundaries will be adjusted to include peer values. */ function Window(params) { Transform.call(this, {}, params); this._mlen = 0; this._mods = []; } Window.Definition = { "type": "Window", "metadata": {"modifies": true}, "params": [ { "name": "sort", "type": "compare" }, { "name": "groupby", "type": "field", "array": true }, { "name": "ops", "type": "enum", "array": true, "values": ValidWindowOps.concat(ValidAggregateOps) }, { "name": "params", "type": "number", "null": true, "array": true }, { "name": "fields", "type": "field", "null": true, "array": true }, { "name": "as", "type": "string", "null": true, "array": true }, { "name": "frame", "type": "number", "null": true, "array": true, "length": 2, "default": [null, 0] }, { "name": "ignorePeers", "type": "boolean", "default": false } ] }; var prototype$33 = inherits(Window, Transform); prototype$33.transform = function(_, pulse) { var self = this, state = self.state, mod = _.modified(), i, n; this.stamp = pulse.stamp; // initialize window state if (!state || mod) { state = self.state = new WindowState(_); } // retrieve group for a tuple var key$$1 = groupkey(_.groupby); function group(t) { return self.group(key$$1(t)); } // partition input tuples if (mod || pulse.modified(state.inputs)) { self.value = {}; pulse.visit(pulse.SOURCE, function(t) { group(t).add(t); }); } else { pulse.visit(pulse.REM, function(t) { group(t).remove(t); }); pulse.visit(pulse.ADD, function(t) { group(t).add(t); }); } // perform window calculations for each modified partition for (i=0, n=self._mlen; i 0 && !c(d[r0], d[r0-1])) w.i0 = bisect.left(d, d[r0]); if (r1 < n && !c(d[r1], d[r1+1])) w.i1 = bisect.right(d, d[r1]); } var tx = Object.freeze({ aggregate: Aggregate, bin: Bin, collect: Collect, compare: Compare, countpattern: CountPattern, cross: Cross, density: Density, extent: Extent, facet: Facet, field: Field, filter: Filter, fold: Fold, formula: Formula, generate: Generate, impute: Impute, joinaggregate: JoinAggregate, key: Key, lookup: Lookup, multiextent: MultiExtent, multivalues: MultiValues, params: Params, prefacet: PreFacet, proxy: Proxy, relay: Relay, sample: Sample, sequence: Sequence, sieve: Sieve, subflow: Subflow, tupleindex: TupleIndex, values: Values, window: Window }); function Bounds(b) { this.clear(); if (b) this.union(b); } var prototype$36 = Bounds.prototype; prototype$36.clone = function() { return new Bounds(this); }; prototype$36.clear = function() { this.x1 = +Number.MAX_VALUE; this.y1 = +Number.MAX_VALUE; this.x2 = -Number.MAX_VALUE; this.y2 = -Number.MAX_VALUE; return this; }; prototype$36.empty = function() { return ( this.x1 === +Number.MAX_VALUE && this.y1 === +Number.MAX_VALUE && this.x2 === -Number.MAX_VALUE && this.y2 === -Number.MAX_VALUE ); }; prototype$36.set = function(x1, y1, x2, y2) { if (x2 < x1) { this.x2 = x1; this.x1 = x2; } else { this.x1 = x1; this.x2 = x2; } if (y2 < y1) { this.y2 = y1; this.y1 = y2; } else { this.y1 = y1; this.y2 = y2; } return this; }; prototype$36.add = function(x, y) { if (x < this.x1) this.x1 = x; if (y < this.y1) this.y1 = y; if (x > this.x2) this.x2 = x; if (y > this.y2) this.y2 = y; return this; }; prototype$36.expand = function(d) { this.x1 -= d; this.y1 -= d; this.x2 += d; this.y2 += d; return this; }; prototype$36.round = function() { this.x1 = Math.floor(this.x1); this.y1 = Math.floor(this.y1); this.x2 = Math.ceil(this.x2); this.y2 = Math.ceil(this.y2); return this; }; prototype$36.translate = function(dx, dy) { this.x1 += dx; this.x2 += dx; this.y1 += dy; this.y2 += dy; return this; }; prototype$36.rotate = function(angle, x, y) { var cos = Math.cos(angle), sin = Math.sin(angle), cx = x - x*cos + y*sin, cy = y - x*sin - y*cos, x1 = this.x1, x2 = this.x2, y1 = this.y1, y2 = this.y2; return this.clear() .add(cos*x1 - sin*y1 + cx, sin*x1 + cos*y1 + cy) .add(cos*x1 - sin*y2 + cx, sin*x1 + cos*y2 + cy) .add(cos*x2 - sin*y1 + cx, sin*x2 + cos*y1 + cy) .add(cos*x2 - sin*y2 + cx, sin*x2 + cos*y2 + cy); }; prototype$36.union = function(b) { if (b.x1 < this.x1) this.x1 = b.x1; if (b.y1 < this.y1) this.y1 = b.y1; if (b.x2 > this.x2) this.x2 = b.x2; if (b.y2 > this.y2) this.y2 = b.y2; return this; }; prototype$36.intersect = function(b) { if (b.x1 > this.x1) this.x1 = b.x1; if (b.y1 > this.y1) this.y1 = b.y1; if (b.x2 < this.x2) this.x2 = b.x2; if (b.y2 < this.y2) this.y2 = b.y2; return this; }; prototype$36.encloses = function(b) { return b && ( this.x1 <= b.x1 && this.x2 >= b.x2 && this.y1 <= b.y1 && this.y2 >= b.y2 ); }; prototype$36.alignsWith = function(b) { return b && ( this.x1 == b.x1 || this.x2 == b.x2 || this.y1 == b.y1 || this.y2 == b.y2 ); }; prototype$36.intersects = function(b) { return b && !( this.x2 < b.x1 || this.x1 > b.x2 || this.y2 < b.y1 || this.y1 > b.y2 ); }; prototype$36.contains = function(x, y) { return !( x < this.x1 || x > this.x2 || y < this.y1 || y > this.y2 ); }; prototype$36.width = function() { return this.x2 - this.x1; }; prototype$36.height = function() { return this.y2 - this.y1; }; var gradient_id = 0; var Gradient = function(p0, p1) { var stops = [], gradient; return gradient = { id: 'gradient_' + (gradient_id++), x1: p0 ? p0[0] : 0, y1: p0 ? p0[1] : 0, x2: p1 ? p1[0] : 1, y2: p1 ? p1[1] : 0, stops: stops, stop: function(offset, color) { stops.push({offset: offset, color: color}); return gradient; } }; }; function Item(mark) { this.mark = mark; this.bounds = (this.bounds || new Bounds()); } function GroupItem(mark) { Item.call(this, mark); this.items = (this.items || []); } inherits(GroupItem, Item); // create a new DOM element function domCreate(doc, tag, ns) { if (!doc && typeof document !== 'undefined' && document.createElement) { doc = document; } return doc ? (ns ? doc.createElementNS(ns, tag) : doc.createElement(tag)) : null; } // find first child element with matching tag function domFind(el, tag) { tag = tag.toLowerCase(); var nodes = el.childNodes, i = 0, n = nodes.length; for (; i index) el.removeChild(nodes[--curr]); return el; } // generate css class name for mark function cssClass(mark) { return 'mark-' + mark.marktype + (mark.role ? ' role-' + mark.role : '') + (mark.name ? ' ' + mark.name : ''); } var Canvas; try { Canvas = require('canvas'); } catch (e) { Canvas = null; } var Canvas$1 = function(w, h) { var canvas = domCreate(null, 'canvas'); if (canvas && canvas.getContext) { canvas.width = w; canvas.height = h; } else if (Canvas) { try { canvas = new Canvas(w, h); } catch (e) { canvas = null; } } return canvas; }; var Image$1 = typeof Image !== 'undefined' ? Image : (Canvas && Canvas.Image || null); function ResourceLoader(customLoader) { this._pending = 0; this._loader = customLoader || loader(); } var prototype$37 = ResourceLoader.prototype; prototype$37.pending = function() { return this._pending; }; function increment(loader$$1) { loader$$1._pending += 1; } function decrement(loader$$1) { loader$$1._pending -= 1; } prototype$37.sanitizeURL = function(uri) { var loader$$1 = this; increment(loader$$1); return loader$$1._loader.sanitize(uri, {context:'href'}) .then(function(opt) { decrement(loader$$1); return opt; }) .catch(function() { decrement(loader$$1); return null; }); }; prototype$37.loadImage = function(uri) { var loader$$1 = this; increment(loader$$1); return loader$$1._loader .sanitize(uri, {context:'image'}) .then(function(opt) { var url = opt.href; if (!url || !Image$1) throw {url: url}; var image = new Image$1(); image.onload = function() { decrement(loader$$1); image.loaded = true; }; image.onerror = function() { decrement(loader$$1); image.loaded = false; }; image.src = url; return image; }) .catch(function(e) { decrement(loader$$1); return {loaded: false, width: 0, height: 0, src: e && e.url || ''}; }); }; prototype$37.ready = function() { var loader$$1 = this; return new Promise(function(accept) { function poll(value) { if (!loader$$1.pending()) accept(value); else setTimeout(function() { poll(true); }, 10); } poll(false); }); }; var pi = Math.PI; var tau = 2 * pi; var epsilon = 1e-6; var tauEpsilon = tau - epsilon; function Path() { this._x0 = this._y0 = // start of current subpath this._x1 = this._y1 = null; // end of current subpath this._ = ""; } function path() { return new Path; } Path.prototype = path.prototype = { constructor: Path, moveTo: function(x, y) { this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y); }, closePath: function() { if (this._x1 !== null) { this._x1 = this._x0, this._y1 = this._y0; this._ += "Z"; } }, lineTo: function(x, y) { this._ += "L" + (this._x1 = +x) + "," + (this._y1 = +y); }, quadraticCurveTo: function(x1, y1, x, y) { this._ += "Q" + (+x1) + "," + (+y1) + "," + (this._x1 = +x) + "," + (this._y1 = +y); }, bezierCurveTo: function(x1, y1, x2, y2, x, y) { this._ += "C" + (+x1) + "," + (+y1) + "," + (+x2) + "," + (+y2) + "," + (this._x1 = +x) + "," + (this._y1 = +y); }, arcTo: function(x1, y1, x2, y2, r) { x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r; var x0 = this._x1, y0 = this._y1, x21 = x2 - x1, y21 = y2 - y1, x01 = x0 - x1, y01 = y0 - y1, l01_2 = x01 * x01 + y01 * y01; // Is the radius negative? Error. if (r < 0) throw new Error("negative radius: " + r); // Is this path empty? Move to (x1,y1). if (this._x1 === null) { this._ += "M" + (this._x1 = x1) + "," + (this._y1 = y1); } // Or, is (x1,y1) coincident with (x0,y0)? Do nothing. else if (!(l01_2 > epsilon)) {} // 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) || !r) { this._ += "L" + (this._x1 = x1) + "," + (this._y1 = y1); } // Otherwise, draw an arc! else { var x20 = x2 - x0, y20 = y2 - y0, l21_2 = x21 * x21 + y21 * y21, l20_2 = x20 * x20 + y20 * y20, l21 = Math.sqrt(l21_2), l01 = Math.sqrt(l01_2), l = r * Math.tan((pi - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2), t01 = l / l01, t21 = l / l21; // If the start tangent is not coincident with (x0,y0), line to. if (Math.abs(t01 - 1) > epsilon) { this._ += "L" + (x1 + t01 * x01) + "," + (y1 + t01 * y01); } this._ += "A" + r + "," + r + ",0,0," + (+(y01 * x20 > x01 * y20)) + "," + (this._x1 = x1 + t21 * x21) + "," + (this._y1 = y1 + t21 * y21); } }, arc: function(x, y, r, a0, a1, ccw) { x = +x, y = +y, r = +r; var dx = r * Math.cos(a0), dy = r * Math.sin(a0), x0 = x + dx, y0 = y + dy, cw = 1 ^ ccw, da = ccw ? a0 - a1 : a1 - a0; // Is the radius negative? Error. if (r < 0) throw new Error("negative radius: " + r); // Is this path empty? Move to (x0,y0). if (this._x1 === null) { this._ += "M" + x0 + "," + y0; } // Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0). else if (Math.abs(this._x1 - x0) > epsilon || Math.abs(this._y1 - y0) > epsilon) { this._ += "L" + x0 + "," + y0; } // Is this arc empty? We’re done. if (!r) return; // Does the angle go the wrong way? Flip the direction. if (da < 0) da = da % tau + tau; // Is this a complete circle? Draw two arcs to complete the circle. if (da > tauEpsilon) { this._ += "A" + r + "," + r + ",0,1," + cw + "," + (x - dx) + "," + (y - dy) + "A" + r + "," + r + ",0,1," + cw + "," + (this._x1 = x0) + "," + (this._y1 = y0); } // Is this arc non-empty? Draw an arc! else if (da > epsilon) { this._ += "A" + r + "," + r + ",0," + (+(da >= pi)) + "," + cw + "," + (this._x1 = x + r * Math.cos(a1)) + "," + (this._y1 = y + r * Math.sin(a1)); } }, rect: function(x, y, w, h) { this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y) + "h" + (+w) + "v" + (+h) + "h" + (-w) + "Z"; }, toString: function() { return this._; } }; var constant$2 = function(x) { return function constant() { return x; }; }; var abs = Math.abs; var atan2 = Math.atan2; var cos = Math.cos; var max$1 = Math.max; var min$1 = Math.min; var sin = Math.sin; var sqrt = Math.sqrt; var epsilon$1 = 1e-12; var pi$1 = Math.PI; var halfPi = pi$1 / 2; var tau$1 = 2 * pi$1; function acos(x) { return x > 1 ? 0 : x < -1 ? pi$1 : Math.acos(x); } function asin(x) { return x >= 1 ? halfPi : x <= -1 ? -halfPi : Math.asin(x); } function arcInnerRadius(d) { return d.innerRadius; } function arcOuterRadius(d) { return d.outerRadius; } function arcStartAngle(d) { return d.startAngle; } function arcEndAngle(d) { return d.endAngle; } function arcPadAngle(d) { return d && d.padAngle; // Note: optional! } function intersect(x0, y0, x1, y1, x2, y2, x3, y3) { var x10 = x1 - x0, y10 = y1 - y0, x32 = x3 - x2, y32 = y3 - y2, t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / (y32 * x10 - x32 * y10); return [x0 + t * x10, y0 + t * y10]; } // Compute perpendicular offset line of length rc. // http://mathworld.wolfram.com/Circle-LineIntersection.html function cornerTangents(x0, y0, x1, y1, r1, rc, cw) { var x01 = x0 - x1, y01 = y0 - y1, lo = (cw ? rc : -rc) / sqrt(x01 * x01 + y01 * y01), ox = lo * y01, oy = -lo * x01, x11 = x0 + ox, y11 = y0 + oy, x10 = x1 + ox, y10 = y1 + oy, x00 = (x11 + x10) / 2, y00 = (y11 + y10) / 2, dx = x10 - x11, dy = y10 - y11, d2 = dx * dx + dy * dy, r = r1 - rc, D = x11 * y10 - x10 * y11, d = (dy < 0 ? -1 : 1) * sqrt(max$1(0, r * r * d2 - D * D)), cx0 = (D * dy - dx * d) / d2, cy0 = (-D * dx - dy * d) / d2, cx1 = (D * dy + dx * d) / d2, cy1 = (-D * dx + dy * d) / d2, dx0 = cx0 - x00, dy0 = cy0 - y00, dx1 = cx1 - x00, dy1 = cy1 - y00; // Pick the closer of the two intersection points. // TODO Is there a faster way to determine which intersection to use? if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1; return { cx: cx0, cy: cy0, x01: -ox, y01: -oy, x11: cx0 * (r1 / r - 1), y11: cy0 * (r1 / r - 1) }; } var d3_arc = function() { var innerRadius = arcInnerRadius, outerRadius = arcOuterRadius, cornerRadius = constant$2(0), padRadius = null, startAngle = arcStartAngle, endAngle = arcEndAngle, padAngle = arcPadAngle, context = null; function arc() { var buffer, r, r0 = +innerRadius.apply(this, arguments), r1 = +outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) - halfPi, a1 = endAngle.apply(this, arguments) - halfPi, da = abs(a1 - a0), cw = a1 > a0; if (!context) context = buffer = path(); // Ensure that the outer radius is always larger than the inner radius. if (r1 < r0) r = r1, r1 = r0, r0 = r; // Is it a point? if (!(r1 > epsilon$1)) context.moveTo(0, 0); // Or is it a circle or annulus? else if (da > tau$1 - epsilon$1) { context.moveTo(r1 * cos(a0), r1 * sin(a0)); context.arc(0, 0, r1, a0, a1, !cw); if (r0 > epsilon$1) { context.moveTo(r0 * cos(a1), r0 * sin(a1)); context.arc(0, 0, r0, a1, a0, cw); } } // Or is it a circular or annular sector? else { var a01 = a0, a11 = a1, a00 = a0, a10 = a1, da0 = da, da1 = da, ap = padAngle.apply(this, arguments) / 2, rp = (ap > epsilon$1) && (padRadius ? +padRadius.apply(this, arguments) : sqrt(r0 * r0 + r1 * r1)), rc = min$1(abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments)), rc0 = rc, rc1 = rc, t0, t1; // Apply padding? Note that since r1 ≥ r0, da1 ≥ da0. if (rp > epsilon$1) { var p0 = asin(rp / r0 * sin(ap)), p1 = asin(rp / r1 * sin(ap)); if ((da0 -= p0 * 2) > epsilon$1) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0; else da0 = 0, a00 = a10 = (a0 + a1) / 2; if ((da1 -= p1 * 2) > epsilon$1) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1; else da1 = 0, a01 = a11 = (a0 + a1) / 2; } var x01 = r1 * cos(a01), y01 = r1 * sin(a01), x10 = r0 * cos(a10), y10 = r0 * sin(a10); // Apply rounded corners? if (rc > epsilon$1) { var x11 = r1 * cos(a11), y11 = r1 * sin(a11), x00 = r0 * cos(a00), y00 = r0 * sin(a00); // Restrict the corner radius according to the sector angle. if (da < pi$1) { var oc = da0 > epsilon$1 ? intersect(x01, y01, x00, y00, x11, y11, x10, y10) : [x10, y10], 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$1(rc, (r0 - lc) / (kc - 1)); rc1 = min$1(rc, (r1 - lc) / (kc + 1)); } } // Is the sector collapsed to a line? if (!(da1 > epsilon$1)) context.moveTo(x01, y01); // Does the sector’s outer ring have rounded corners? else if (rc1 > epsilon$1) { t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw); t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw); context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01); // Have the corners merged? if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw); // Otherwise, draw the two corners and the ring. else { context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw); context.arc(0, 0, r1, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), !cw); context.arc(t1.cx, t1.cy, rc1, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw); } } // Or is the outer ring just a circular arc? else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw); // Is there no inner ring, and it’s a circular sector? // Or perhaps it’s an annular sector collapsed due to padding? if (!(r0 > epsilon$1) || !(da0 > epsilon$1)) context.lineTo(x10, y10); // Does the sector’s inner ring (or point) have rounded corners? else if (rc0 > epsilon$1) { t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw); t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw); context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01); // Have the corners merged? if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw); // Otherwise, draw the two corners and the ring. else { context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw); context.arc(0, 0, r0, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), cw); context.arc(t1.cx, t1.cy, rc0, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw); } } // Or is the inner ring just a circular arc? else context.arc(0, 0, r0, a10, a00, cw); } context.closePath(); if (buffer) return context = null, buffer + "" || null; } arc.centroid = function() { var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2, a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi$1 / 2; return [cos(a) * r, sin(a) * r]; }; arc.innerRadius = function(_) { return arguments.length ? (innerRadius = typeof _ === "function" ? _ : constant$2(+_), arc) : innerRadius; }; arc.outerRadius = function(_) { return arguments.length ? (outerRadius = typeof _ === "function" ? _ : constant$2(+_), arc) : outerRadius; }; arc.cornerRadius = function(_) { return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant$2(+_), arc) : cornerRadius; }; arc.padRadius = function(_) { return arguments.length ? (padRadius = _ == null ? null : typeof _ === "function" ? _ : constant$2(+_), arc) : padRadius; }; arc.startAngle = function(_) { return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$2(+_), arc) : startAngle; }; arc.endAngle = function(_) { return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$2(+_), arc) : endAngle; }; arc.padAngle = function(_) { return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$2(+_), arc) : padAngle; }; arc.context = function(_) { return arguments.length ? ((context = _ == null ? null : _), arc) : context; }; return arc; }; function Linear(context) { this._context = context; } Linear.prototype = { areaStart: function() { this._line = 0; }, areaEnd: function() { this._line = NaN; }, lineStart: function() { this._point = 0; }, lineEnd: function() { if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath(); this._line = 1 - this._line; }, point: function(x, y) { x = +x, y = +y; switch (this._point) { case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break; case 1: this._point = 2; // proceed default: this._context.lineTo(x, y); break; } } }; var curveLinear = function(context) { return new Linear(context); }; function x$1(p) { return p[0]; } function y$1(p) { return p[1]; } var line$1 = function() { var x = x$1, y = y$1, defined = constant$2(true), context = null, curve = curveLinear, output = null; function line(data) { var i, n = data.length, d, defined0 = false, buffer; if (context == null) output = curve(buffer = path()); for (i = 0; i <= n; ++i) { if (!(i < n && defined(d = data[i], i, data)) === defined0) { if (defined0 = !defined0) output.lineStart(); else output.lineEnd(); } if (defined0) output.point(+x(d, i, data), +y(d, i, data)); } if (buffer) return output = null, buffer + "" || null; } line.x = function(_) { return arguments.length ? (x = typeof _ === "function" ? _ : constant$2(+_), line) : x; }; line.y = function(_) { return arguments.length ? (y = typeof _ === "function" ? _ : constant$2(+_), line) : y; }; line.defined = function(_) { return arguments.length ? (defined = typeof _ === "function" ? _ : constant$2(!!_), line) : defined; }; line.curve = function(_) { return arguments.length ? (curve = _, context != null && (output = curve(context)), line) : curve; }; line.context = function(_) { return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), line) : context; }; return line; }; var area$1 = function() { var x0 = x$1, x1 = null, y0 = constant$2(0), y1 = y$1, defined = constant$2(true), context = null, curve = curveLinear, output = null; function area(data) { var i, j, k, n = data.length, d, defined0 = false, buffer, x0z = new Array(n), y0z = new Array(n); if (context == null) output = curve(buffer = path()); for (i = 0; i <= n; ++i) { if (!(i < n && defined(d = data[i], i, data)) === defined0) { if (defined0 = !defined0) { j = i; output.areaStart(); output.lineStart(); } else { output.lineEnd(); output.lineStart(); for (k = i - 1; k >= j; --k) { output.point(x0z[k], y0z[k]); } output.lineEnd(); output.areaEnd(); } } if (defined0) { x0z[i] = +x0(d, i, data), y0z[i] = +y0(d, i, data); output.point(x1 ? +x1(d, i, data) : x0z[i], y1 ? +y1(d, i, data) : y0z[i]); } } if (buffer) return output = null, buffer + "" || null; } function arealine() { return line$1().defined(defined).curve(curve).context(context); } area.x = function(_) { return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$2(+_), x1 = null, area) : x0; }; area.x0 = function(_) { return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$2(+_), area) : x0; }; area.x1 = function(_) { return arguments.length ? (x1 = _ == null ? null : typeof _ === "function" ? _ : constant$2(+_), area) : x1; }; area.y = function(_) { return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$2(+_), y1 = null, area) : y0; }; area.y0 = function(_) { return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$2(+_), area) : y0; }; area.y1 = function(_) { return arguments.length ? (y1 = _ == null ? null : typeof _ === "function" ? _ : constant$2(+_), area) : y1; }; area.lineX0 = area.lineY0 = function() { return arealine().x(x0).y(y0); }; area.lineY1 = function() { return arealine().x(x0).y(y1); }; area.lineX1 = function() { return arealine().x(x1).y(y0); }; area.defined = function(_) { return arguments.length ? (defined = typeof _ === "function" ? _ : constant$2(!!_), area) : defined; }; area.curve = function(_) { return arguments.length ? (curve = _, context != null && (output = curve(context)), area) : curve; }; area.context = function(_) { return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), area) : context; }; return area; }; var circle = { draw: function(context, size) { var r = Math.sqrt(size / pi$1); context.moveTo(r, 0); context.arc(0, 0, r, 0, tau$1); } }; var d3_symbol = function() { var type = constant$2(circle), size = constant$2(64), context = null; function symbol() { var buffer; if (!context) context = buffer = path(); type.apply(this, arguments).draw(context, +size.apply(this, arguments)); if (buffer) return context = null, buffer + "" || null; } symbol.type = function(_) { return arguments.length ? (type = typeof _ === "function" ? _ : constant$2(_), symbol) : type; }; symbol.size = function(_) { return arguments.length ? (size = typeof _ === "function" ? _ : constant$2(+_), symbol) : size; }; symbol.context = function(_) { return arguments.length ? (context = _ == null ? null : _, symbol) : context; }; return symbol; }; var noop$2 = function() {}; function point(that, x, y) { that._context.bezierCurveTo( (2 * that._x0 + that._x1) / 3, (2 * that._y0 + that._y1) / 3, (that._x0 + 2 * that._x1) / 3, (that._y0 + 2 * that._y1) / 3, (that._x0 + 4 * that._x1 + x) / 6, (that._y0 + 4 * that._y1 + y) / 6 ); } function Basis(context) { this._context = context; } Basis.prototype = { areaStart: function() { this._line = 0; }, areaEnd: function() { this._line = NaN; }, lineStart: function() { this._x0 = this._x1 = this._y0 = this._y1 = NaN; this._point = 0; }, lineEnd: function() { switch (this._point) { case 3: point(this, this._x1, this._y1); // proceed case 2: this._context.lineTo(this._x1, this._y1); break; } if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath(); this._line = 1 - this._line; }, point: function(x, y) { x = +x, y = +y; switch (this._point) { case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break; case 1: this._point = 2; break; case 2: this._point = 3; this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6); // proceed default: point(this, x, y); break; } this._x0 = this._x1, this._x1 = x; this._y0 = this._y1, this._y1 = y; } }; var curveBasis = function(context) { return new Basis(context); }; function BasisClosed(context) { this._context = context; } BasisClosed.prototype = { areaStart: noop$2, areaEnd: noop$2, lineStart: function() { this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = NaN; this._point = 0; }, lineEnd: function() { switch (this._point) { case 1: { this._context.moveTo(this._x2, this._y2); this._context.closePath(); break; } case 2: { this._context.moveTo((this._x2 + 2 * this._x3) / 3, (this._y2 + 2 * this._y3) / 3); this._context.lineTo((this._x3 + 2 * this._x2) / 3, (this._y3 + 2 * this._y2) / 3); this._context.closePath(); break; } case 3: { this.point(this._x2, this._y2); this.point(this._x3, this._y3); this.point(this._x4, this._y4); break; } } }, point: function(x, y) { x = +x, y = +y; switch (this._point) { case 0: this._point = 1; this._x2 = x, this._y2 = y; break; case 1: this._point = 2; this._x3 = x, this._y3 = y; break; case 2: this._point = 3; this._x4 = x, this._y4 = y; this._context.moveTo((this._x0 + 4 * this._x1 + x) / 6, (this._y0 + 4 * this._y1 + y) / 6); break; default: point(this, x, y); break; } this._x0 = this._x1, this._x1 = x; this._y0 = this._y1, this._y1 = y; } }; var curveBasisClosed = function(context) { return new BasisClosed(context); }; function BasisOpen(context) { this._context = context; } BasisOpen.prototype = { areaStart: function() { this._line = 0; }, areaEnd: function() { this._line = NaN; }, lineStart: function() { this._x0 = this._x1 = this._y0 = this._y1 = NaN; this._point = 0; }, lineEnd: function() { if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath(); this._line = 1 - this._line; }, point: function(x, y) { x = +x, y = +y; switch (this._point) { case 0: this._point = 1; break; case 1: this._point = 2; break; case 2: this._point = 3; var x0 = (this._x0 + 4 * this._x1 + x) / 6, y0 = (this._y0 + 4 * this._y1 + y) / 6; this._line ? this._context.lineTo(x0, y0) : this._context.moveTo(x0, y0); break; case 3: this._point = 4; // proceed default: point(this, x, y); break; } this._x0 = this._x1, this._x1 = x; this._y0 = this._y1, this._y1 = y; } }; var curveBasisOpen = function(context) { return new BasisOpen(context); }; function Bundle(context, beta) { this._basis = new Basis(context); this._beta = beta; } Bundle.prototype = { lineStart: function() { this._x = []; this._y = []; this._basis.lineStart(); }, lineEnd: function() { var x = this._x, y = this._y, j = x.length - 1; if (j > 0) { var x0 = x[0], y0 = y[0], dx = x[j] - x0, dy = y[j] - y0, i = -1, t; while (++i <= j) { t = i / j; this._basis.point( this._beta * x[i] + (1 - this._beta) * (x0 + t * dx), this._beta * y[i] + (1 - this._beta) * (y0 + t * dy) ); } } this._x = this._y = null; this._basis.lineEnd(); }, point: function(x, y) { this._x.push(+x); this._y.push(+y); } }; var curveBundle = (function custom(beta) { function bundle(context) { return beta === 1 ? new Basis(context) : new Bundle(context, beta); } bundle.beta = function(beta) { return custom(+beta); }; return bundle; })(0.85); function point$1(that, x, y) { that._context.bezierCurveTo( that._x1 + that._k * (that._x2 - that._x0), that._y1 + that._k * (that._y2 - that._y0), that._x2 + that._k * (that._x1 - x), that._y2 + that._k * (that._y1 - y), that._x2, that._y2 ); } function Cardinal(context, tension) { this._context = context; this._k = (1 - tension) / 6; } Cardinal.prototype = { areaStart: function() { this._line = 0; }, areaEnd: function() { this._line = NaN; }, lineStart: function() { this._x0 = this._x1 = this._x2 = this._y0 = this._y1 = this._y2 = NaN; this._point = 0; }, lineEnd: function() { switch (this._point) { case 2: this._context.lineTo(this._x2, this._y2); break; case 3: point$1(this, this._x1, this._y1); break; } if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath(); this._line = 1 - this._line; }, point: function(x, y) { x = +x, y = +y; switch (this._point) { case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break; case 1: this._point = 2; this._x1 = x, this._y1 = y; break; case 2: this._point = 3; // proceed default: point$1(this, x, y); break; } this._x0 = this._x1, this._x1 = this._x2, this._x2 = x; this._y0 = this._y1, this._y1 = this._y2, this._y2 = y; } }; var curveCardinal = (function custom(tension) { function cardinal(context) { return new Cardinal(context, tension); } cardinal.tension = function(tension) { return custom(+tension); }; return cardinal; })(0); function CardinalClosed(context, tension) { this._context = context; this._k = (1 - tension) / 6; } CardinalClosed.prototype = { areaStart: noop$2, areaEnd: noop$2, lineStart: function() { this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 = this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN; this._point = 0; }, lineEnd: function() { switch (this._point) { case 1: { this._context.moveTo(this._x3, this._y3); this._context.closePath(); break; } case 2: { this._context.lineTo(this._x3, this._y3); this._context.closePath(); break; } case 3: { this.point(this._x3, this._y3); this.point(this._x4, this._y4); this.point(this._x5, this._y5); break; } } }, point: function(x, y) { x = +x, y = +y; switch (this._point) { case 0: this._point = 1; this._x3 = x, this._y3 = y; break; case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break; case 2: this._point = 3; this._x5 = x, this._y5 = y; break; default: point$1(this, x, y); break; } this._x0 = this._x1, this._x1 = this._x2, this._x2 = x; this._y0 = this._y1, this._y1 = this._y2, this._y2 = y; } }; var curveCardinalClosed = (function custom(tension) { function cardinal(context) { return new CardinalClosed(context, tension); } cardinal.tension = function(tension) { return custom(+tension); }; return cardinal; })(0); function CardinalOpen(context, tension) { this._context = context; this._k = (1 - tension) / 6; } CardinalOpen.prototype = { areaStart: function() { this._line = 0; }, areaEnd: function() { this._line = NaN; }, lineStart: function() { this._x0 = this._x1 = this._x2 = this._y0 = this._y1 = this._y2 = NaN; this._point = 0; }, lineEnd: function() { if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath(); this._line = 1 - this._line; }, point: function(x, y) { x = +x, y = +y; switch (this._point) { case 0: this._point = 1; break; case 1: this._point = 2; break; case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break; case 3: this._point = 4; // proceed default: point$1(this, x, y); break; } this._x0 = this._x1, this._x1 = this._x2, this._x2 = x; this._y0 = this._y1, this._y1 = this._y2, this._y2 = y; } }; var curveCardinalOpen = (function custom(tension) { function cardinal(context) { return new CardinalOpen(context, tension); } cardinal.tension = function(tension) { return custom(+tension); }; return cardinal; })(0); function point$2(that, x, y) { var x1 = that._x1, y1 = that._y1, x2 = that._x2, y2 = that._y2; if (that._l01_a > epsilon$1) { var a = 2 * that._l01_2a + 3 * that._l01_a * that._l12_a + that._l12_2a, n = 3 * that._l01_a * (that._l01_a + that._l12_a); x1 = (x1 * a - that._x0 * that._l12_2a + that._x2 * that._l01_2a) / n; y1 = (y1 * a - that._y0 * that._l12_2a + that._y2 * that._l01_2a) / n; } if (that._l23_a > epsilon$1) { var b = 2 * that._l23_2a + 3 * that._l23_a * that._l12_a + that._l12_2a, m = 3 * that._l23_a * (that._l23_a + that._l12_a); x2 = (x2 * b + that._x1 * that._l23_2a - x * that._l12_2a) / m; y2 = (y2 * b + that._y1 * that._l23_2a - y * that._l12_2a) / m; } that._context.bezierCurveTo(x1, y1, x2, y2, that._x2, that._y2); } function CatmullRom(context, alpha) { this._context = context; this._alpha = alpha; } CatmullRom.prototype = { areaStart: function() { this._line = 0; }, areaEnd: function() { this._line = NaN; }, lineStart: function() { this._x0 = this._x1 = this._x2 = this._y0 = this._y1 = this._y2 = NaN; this._l01_a = this._l12_a = this._l23_a = this._l01_2a = this._l12_2a = this._l23_2a = this._point = 0; }, lineEnd: function() { switch (this._point) { case 2: this._context.lineTo(this._x2, this._y2); break; case 3: this.point(this._x2, this._y2); break; } if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath(); this._line = 1 - this._line; }, point: function(x, y) { x = +x, y = +y; if (this._point) { var x23 = this._x2 - x, y23 = this._y2 - y; this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha)); } switch (this._point) { case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break; case 1: this._point = 2; break; case 2: this._point = 3; // proceed default: point$2(this, x, y); break; } this._l01_a = this._l12_a, this._l12_a = this._l23_a; this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a; this._x0 = this._x1, this._x1 = this._x2, this._x2 = x; this._y0 = this._y1, this._y1 = this._y2, this._y2 = y; } }; var curveCatmullRom = (function custom(alpha) { function catmullRom(context) { return alpha ? new CatmullRom(context, alpha) : new Cardinal(context, 0); } catmullRom.alpha = function(alpha) { return custom(+alpha); }; return catmullRom; })(0.5); function CatmullRomClosed(context, alpha) { this._context = context; this._alpha = alpha; } CatmullRomClosed.prototype = { areaStart: noop$2, areaEnd: noop$2, lineStart: function() { this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 = this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN; this._l01_a = this._l12_a = this._l23_a = this._l01_2a = this._l12_2a = this._l23_2a = this._point = 0; }, lineEnd: function() { switch (this._point) { case 1: { this._context.moveTo(this._x3, this._y3); this._context.closePath(); break; } case 2: { this._context.lineTo(this._x3, this._y3); this._context.closePath(); break; } case 3: { this.point(this._x3, this._y3); this.point(this._x4, this._y4); this.point(this._x5, this._y5); break; } } }, point: function(x, y) { x = +x, y = +y; if (this._point) { var x23 = this._x2 - x, y23 = this._y2 - y; this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha)); } switch (this._point) { case 0: this._point = 1; this._x3 = x, this._y3 = y; break; case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break; case 2: this._point = 3; this._x5 = x, this._y5 = y; break; default: point$2(this, x, y); break; } this._l01_a = this._l12_a, this._l12_a = this._l23_a; this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a; this._x0 = this._x1, this._x1 = this._x2, this._x2 = x; this._y0 = this._y1, this._y1 = this._y2, this._y2 = y; } }; var curveCatmullRomClosed = (function custom(alpha) { function catmullRom(context) { return alpha ? new CatmullRomClosed(context, alpha) : new CardinalClosed(context, 0); } catmullRom.alpha = function(alpha) { return custom(+alpha); }; return catmullRom; })(0.5); function CatmullRomOpen(context, alpha) { this._context = context; this._alpha = alpha; } CatmullRomOpen.prototype = { areaStart: function() { this._line = 0; }, areaEnd: function() { this._line = NaN; }, lineStart: function() { this._x0 = this._x1 = this._x2 = this._y0 = this._y1 = this._y2 = NaN; this._l01_a = this._l12_a = this._l23_a = this._l01_2a = this._l12_2a = this._l23_2a = this._point = 0; }, lineEnd: function() { if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath(); this._line = 1 - this._line; }, point: function(x, y) { x = +x, y = +y; if (this._point) { var x23 = this._x2 - x, y23 = this._y2 - y; this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha)); } switch (this._point) { case 0: this._point = 1; break; case 1: this._point = 2; break; case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break; case 3: this._point = 4; // proceed default: point$2(this, x, y); break; } this._l01_a = this._l12_a, this._l12_a = this._l23_a; this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a; this._x0 = this._x1, this._x1 = this._x2, this._x2 = x; this._y0 = this._y1, this._y1 = this._y2, this._y2 = y; } }; var curveCatmullRomOpen = (function custom(alpha) { function catmullRom(context) { return alpha ? new CatmullRomOpen(context, alpha) : new CardinalOpen(context, 0); } catmullRom.alpha = function(alpha) { return custom(+alpha); }; return catmullRom; })(0.5); function LinearClosed(context) { this._context = context; } LinearClosed.prototype = { areaStart: noop$2, areaEnd: noop$2, lineStart: function() { this._point = 0; }, lineEnd: function() { if (this._point) this._context.closePath(); }, point: function(x, y) { x = +x, y = +y; if (this._point) this._context.lineTo(x, y); else this._point = 1, this._context.moveTo(x, y); } }; var curveLinearClosed = function(context) { return new LinearClosed(context); }; function sign(x) { return x < 0 ? -1 : 1; } // Calculate the slopes of the tangents (Hermite-type interpolation) based on // the following paper: Steffen, M. 1990. A Simple Method for Monotonic // Interpolation in One Dimension. Astronomy and Astrophysics, Vol. 239, NO. // NOV(II), P. 443, 1990. function slope3(that, x2, y2) { var h0 = that._x1 - that._x0, h1 = x2 - that._x1, s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0), s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0), p = (s0 * h1 + s1 * h0) / (h0 + h1); return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0; } // Calculate a one-sided slope. function slope2(that, t) { var h = that._x1 - that._x0; return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t; } // According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations // "you can express cubic Hermite interpolation in terms of cubic Bézier curves // with respect to the four values p0, p0 + m0 / 3, p1 - m1 / 3, p1". function point$3(that, t0, t1) { var x0 = that._x0, y0 = that._y0, x1 = that._x1, y1 = that._y1, dx = (x1 - x0) / 3; that._context.bezierCurveTo(x0 + dx, y0 + dx * t0, x1 - dx, y1 - dx * t1, x1, y1); } function MonotoneX(context) { this._context = context; } MonotoneX.prototype = { areaStart: function() { this._line = 0; }, areaEnd: function() { this._line = NaN; }, lineStart: function() { this._x0 = this._x1 = this._y0 = this._y1 = this._t0 = NaN; this._point = 0; }, lineEnd: function() { switch (this._point) { case 2: this._context.lineTo(this._x1, this._y1); break; case 3: point$3(this, this._t0, slope2(this, this._t0)); break; } if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath(); this._line = 1 - this._line; }, point: function(x, y) { var t1 = NaN; x = +x, y = +y; if (x === this._x1 && y === this._y1) return; // Ignore coincident points. switch (this._point) { case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break; case 1: this._point = 2; break; case 2: this._point = 3; point$3(this, slope2(this, t1 = slope3(this, x, y)), t1); break; default: point$3(this, this._t0, t1 = slope3(this, x, y)); break; } this._x0 = this._x1, this._x1 = x; this._y0 = this._y1, this._y1 = y; this._t0 = t1; } }; function MonotoneY(context) { this._context = new ReflectContext(context); } (MonotoneY.prototype = Object.create(MonotoneX.prototype)).point = function(x, y) { MonotoneX.prototype.point.call(this, y, x); }; function ReflectContext(context) { this._context = context; } ReflectContext.prototype = { moveTo: function(x, y) { this._context.moveTo(y, x); }, closePath: function() { this._context.closePath(); }, lineTo: function(x, y) { this._context.lineTo(y, x); }, bezierCurveTo: function(x1, y1, x2, y2, x, y) { this._context.bezierCurveTo(y1, x1, y2, x2, y, x); } }; function monotoneX(context) { return new MonotoneX(context); } function monotoneY(context) { return new MonotoneY(context); } function Natural(context) { this._context = context; } Natural.prototype = { areaStart: function() { this._line = 0; }, areaEnd: function() { this._line = NaN; }, lineStart: function() { this._x = []; this._y = []; }, lineEnd: function() { var x = this._x, y = this._y, n = x.length; if (n) { this._line ? this._context.lineTo(x[0], y[0]) : this._context.moveTo(x[0], y[0]); if (n === 2) { this._context.lineTo(x[1], y[1]); } else { var px = controlPoints(x), py = controlPoints(y); for (var i0 = 0, i1 = 1; i1 < n; ++i0, ++i1) { this._context.bezierCurveTo(px[0][i0], py[0][i0], px[1][i0], py[1][i0], x[i1], y[i1]); } } } if (this._line || (this._line !== 0 && n === 1)) this._context.closePath(); this._line = 1 - this._line; this._x = this._y = null; }, point: function(x, y) { this._x.push(+x); this._y.push(+y); } }; // See https://www.particleincell.com/2012/bezier-splines/ for derivation. function controlPoints(x) { var i, n = x.length - 1, m, a = new Array(n), b = new Array(n), r = new Array(n); a[0] = 0, b[0] = 2, r[0] = x[0] + 2 * x[1]; for (i = 1; i < n - 1; ++i) a[i] = 1, b[i] = 4, r[i] = 4 * x[i] + 2 * x[i + 1]; a[n - 1] = 2, b[n - 1] = 7, r[n - 1] = 8 * x[n - 1] + x[n]; for (i = 1; i < n; ++i) m = a[i] / b[i - 1], b[i] -= m, r[i] -= m * r[i - 1]; a[n - 1] = r[n - 1] / b[n - 1]; for (i = n - 2; i >= 0; --i) a[i] = (r[i] - a[i + 1]) / b[i]; b[n - 1] = (x[n] + a[n - 1]) / 2; for (i = 0; i < n - 1; ++i) b[i] = 2 * x[i + 1] - a[i + 1]; return [a, b]; } var curveNatural = function(context) { return new Natural(context); }; function Step(context, t) { this._context = context; this._t = t; } Step.prototype = { areaStart: function() { this._line = 0; }, areaEnd: function() { this._line = NaN; }, lineStart: function() { this._x = this._y = NaN; this._point = 0; }, lineEnd: function() { if (0 < this._t && this._t < 1 && this._point === 2) this._context.lineTo(this._x, this._y); if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath(); if (this._line >= 0) this._t = 1 - this._t, this._line = 1 - this._line; }, point: function(x, y) { x = +x, y = +y; switch (this._point) { case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break; case 1: this._point = 2; // proceed default: { if (this._t <= 0) { this._context.lineTo(this._x, y); this._context.lineTo(x, y); } else { var x1 = this._x * (1 - this._t) + x * this._t; this._context.lineTo(x1, this._y); this._context.lineTo(x1, y); } break; } } this._x = x, this._y = y; } }; var curveStep = function(context) { return new Step(context, 0.5); }; function stepBefore(context) { return new Step(context, 0); } function stepAfter(context) { return new Step(context, 1); } var lookup = { 'basis': { curve: curveBasis }, 'basis-closed': { curve: curveBasisClosed }, 'basis-open': { curve: curveBasisOpen }, 'bundle': { curve: curveBundle, tension: 'beta', value: 0.85 }, 'cardinal': { curve: curveCardinal, tension: 'tension', value: 0 }, 'cardinal-open': { curve: curveCardinalOpen, tension: 'tension', value: 0 }, 'cardinal-closed': { curve: curveCardinalClosed, tension: 'tension', value: 0 }, 'catmull-rom': { curve: curveCatmullRom, tension: 'alpha', value: 0.5 }, 'catmull-rom-closed': { curve: curveCatmullRomClosed, tension: 'alpha', value: 0.5 }, 'catmull-rom-open': { curve: curveCatmullRomOpen, tension: 'alpha', value: 0.5 }, 'linear': { curve: curveLinear }, 'linear-closed': { curve: curveLinearClosed }, 'monotone': { horizontal: monotoneY, vertical: monotoneX }, 'natural': { curve: curveNatural }, 'step': { curve: curveStep }, 'step-after': { curve: stepAfter }, 'step-before': { curve: stepBefore } }; function curves(type, orientation, tension) { var entry = lookup.hasOwnProperty(type) && lookup[type], curve = null; if (entry) { curve = entry.curve || entry[orientation || 'vertical']; if (entry.tension && tension != null) { curve = curve[entry.tension](tension); } } return curve; } // Path parsing and rendering code adapted from fabric.js -- Thanks! var cmdlen = { m:2, l:2, h:1, v:1, c:6, s:4, q:4, t:2, a:7 }; var regexp = [/([MLHVCSQTAZmlhvcsqtaz])/g, /###/, /(\d)([-+])/g, /\s|,|###/]; var pathParse = function(pathstr) { var result = [], path, curr, chunks, parsed, param, cmd, len, i, j, n, m; // First, break path into command sequence path = pathstr .slice() .replace(regexp[0], '###$1') .split(regexp[1]) .slice(1); // Next, parse each command in turn for (i=0, n=path.length; i len) { for (j=1, m=parsed.length; j 1) { pl = Math.sqrt(pl); rx *= pl; ry *= pl; } var a00 = cos_th / rx; var a01 = sin_th / rx; var a10 = (-sin_th) / ry; var a11 = (cos_th) / ry; var x0 = a00 * ox + a01 * oy; var y0 = a10 * ox + a11 * oy; var x1 = a00 * x + a01 * y; var y1 = a10 * x + a11 * y; var d = (x1-x0) * (x1-x0) + (y1-y0) * (y1-y0); var sfactor_sq = 1 / d - 0.25; if (sfactor_sq < 0) sfactor_sq = 0; var sfactor = Math.sqrt(sfactor_sq); if (sweep == large) sfactor = -sfactor; var xc = 0.5 * (x0 + x1) - sfactor * (y1-y0); var yc = 0.5 * (y0 + y1) + sfactor * (x1-x0); var th0 = Math.atan2(y0-yc, x0-xc); var th1 = Math.atan2(y1-yc, x1-xc); var th_arc = th1-th0; if (th_arc < 0 && sweep === 1){ th_arc += 2 * Math.PI; } else if (th_arc > 0 && sweep === 0) { th_arc -= 2 * Math.PI; } var segs = Math.ceil(Math.abs(th_arc / (Math.PI * 0.5 + 0.001))); var result = []; for (var i=0; i circleThreshold) { add$1(cx - r, cy - r); add$1(cx + r, cy + r); return; } var xmin = Infinity, xmax = -Infinity, ymin = Infinity, ymax = -Infinity, s, i, x, y; function update(a) { x = r * Math.cos(a); y = r * Math.sin(a); if (x < xmin) xmin = x; if (x > xmax) xmax = x; if (y < ymin) ymin = y; if (y > ymax) ymax = y; } // Sample end points and interior points aligned with 90 degrees update(sa); update(ea); if (ea !== sa) { sa = sa % tau$3; if (sa < 0) sa += tau$3; ea = ea % tau$3; if (ea < 0) ea += tau$3; if (ea < sa) { ccw = !ccw; // flip direction s = sa; sa = ea; ea = s; // swap end-points } if (ccw) { ea -= tau$3; s = sa - (sa % halfPi$1); for (i=0; i<3 && s>ea; ++i, s-=halfPi$1) update(s); } else { s = sa - (sa % halfPi$1) + halfPi$1; for (i=0; i<3 && s 0) { context.globalAlpha = opacity; context.fillStyle = color(context, item, item.fill); return true; } else { return false; } }; var Empty$1 = []; var stroke = function(context, item, opacity) { var lw = (lw = item.strokeWidth) != null ? lw : 1; if (lw <= 0) return false; opacity *= (item.strokeOpacity==null ? 1 : item.strokeOpacity); if (opacity > 0) { context.globalAlpha = opacity; context.strokeStyle = color(context, item, item.stroke); context.lineWidth = lw; context.lineCap = item.strokeCap || 'butt'; context.lineJoin = item.strokeJoin || 'miter'; context.miterLimit = item.strokeMiterLimit || 10; if (context.setLineDash) { context.setLineDash(item.strokeDash || Empty$1); context.lineDashOffset = item.strokeDashOffset || 0; } return true; } else { return false; } }; function compare$1(a, b) { return a.zindex - b.zindex || a.index - b.index; } function zorder(scene) { if (!scene.zdirty) return scene.zitems; var items = scene.items, output = [], item, i, n; for (i=0, n=items.length; i= 0;) { if (hit = visitor(items[i])) return hit; } if (items === zitems) { for (items=scene.items, i=items.length; --i >= 0;) { if (!items[i].zindex) { if (hit = visitor(items[i])) return hit; } } } return null; } function drawAll(path) { return function(context, scene, bounds) { visit(scene, function(item) { if (!bounds || bounds.intersects(item.bounds)) { drawPath(path, context, item, item); } }); }; } function drawOne(path) { return function(context, scene, bounds) { if (scene.items.length && (!bounds || bounds.intersects(scene.bounds))) { drawPath(path, context, scene.items[0], scene.items); } }; } function drawPath(path, context, item, items) { var opacity = item.opacity == null ? 1 : item.opacity; if (opacity === 0) return; if (path(context, items)) return; if (item.fill && fill(context, item, opacity)) { context.fill(); } if (item.stroke && stroke(context, item, opacity)) { context.stroke(); } } var trueFunc = function() { return true; }; function pick(test) { if (!test) test = trueFunc; return function(context, scene, x, y, gx, gy) { if (context.pixelRatio > 1) { x *= context.pixelRatio; y *= context.pixelRatio; } return pickVisit(scene, function(item) { var b = item.bounds; // first hit test against bounding box if ((b && !b.contains(gx, gy)) || !b) return; // if in bounding box, perform more careful test if (test(context, item, x, y, gx, gy)) return item; }); }; } function hitPath(path, filled) { return function(context, o, x, y) { var item = Array.isArray(o) ? o[0] : o, fill = (filled == null) ? item.fill : filled, stroke = item.stroke && context.isPointInStroke, lw, lc; if (stroke) { lw = item.strokeWidth; lc = item.strokeCap; context.lineWidth = lw != null ? lw : 1; context.lineCap = lc != null ? lc : 'butt'; } return path(context, o) ? false : (fill && context.isPointInPath(x, y)) || (stroke && context.isPointInStroke(x, y)); }; } function pickPath(path) { return pick(hitPath(path)); } var translate = function(x, y) { return 'translate(' + x + ',' + y + ')'; }; var translateItem = function(item) { return translate(item.x || 0, item.y || 0); }; var markItemPath = function(type, shape) { function attr(emit, item) { emit('transform', translateItem(item)); emit('d', shape(null, item)); } function bound(bounds, item) { shape(context(bounds), item); return boundStroke(bounds, item) .translate(item.x || 0, item.y || 0); } function draw(context$$1, item) { var x = item.x || 0, y = item.y || 0; context$$1.translate(x, y); context$$1.beginPath(); shape(context$$1, item); context$$1.translate(-x, -y); } return { type: type, tag: 'path', nested: false, attr: attr, bound: bound, draw: drawAll(draw), pick: pickPath(draw) }; }; var arc = markItemPath('arc', arc$1); var markMultiItemPath = function(type, shape) { function attr(emit, item) { var items = item.mark.items; if (items.length) emit('d', shape(null, items)); } function bound(bounds, mark) { var items = mark.items; if (items.length === 0) { return bounds; } else { shape(context(bounds), items); return boundStroke(bounds, items[0]); } } function draw(context$$1, items) { context$$1.beginPath(); shape(context$$1, items); } var hit = hitPath(draw); function pick$$1(context$$1, scene, x, y, gx, gy) { var items = scene.items, b = scene.bounds; if (!items || !items.length || b && !b.contains(gx, gy)) { return null; } if (context$$1.pixelRatio > 1) { x *= context$$1.pixelRatio; y *= context$$1.pixelRatio; } return hit(context$$1, items, x, y) ? items[0] : null; } return { type: type, tag: 'path', nested: true, attr: attr, bound: bound, draw: drawOne(draw), pick: pick$$1 }; }; var area$2 = markMultiItemPath('area', area); var clip_id = 1; function resetSVGClipId() { clip_id = 1; } var clip = function(renderer, item, size) { var defs = renderer._defs, id = item.clip_id || (item.clip_id = 'clip' + clip_id++), c = defs.clipping[id] || (defs.clipping[id] = {id: id}); c.width = size.width || 0; c.height = size.height || 0; return 'url(#' + id + ')'; }; var StrokeOffset = 0.5; function attr(emit, item) { emit('transform', translateItem(item)); } function background(emit, item) { var offset = item.stroke ? StrokeOffset : 0; emit('class', 'background'); emit('d', rectangle(null, item, offset, offset)); } function foreground(emit, item, renderer) { var url = item.clip ? clip(renderer, item, item) : null; emit('clip-path', url); } function bound(bounds, group) { if (!group.clip && group.items) { var items = group.items; for (var j=0, m=items.length; j 0) { context.beginPath(); offset = group.stroke ? StrokeOffset : 0; rectangle(context, group, offset, offset); if (group.fill && fill(context, group, opacity)) { context.fill(); } if (group.stroke && stroke(context, group, opacity)) { context.stroke(); } } } // set clip and bounds if (group.clip) { context.beginPath(); context.rect(0, 0, w, h); context.clip(); } if (bounds) bounds.translate(-gx, -gy); // draw group contents visit(group, function(item) { renderer.draw(context, item, bounds); }); // restore graphics context if (bounds) bounds.translate(gx, gy); context.restore(); }); } function pick$1(context, scene, x, y, gx, gy) { if (scene.bounds && !scene.bounds.contains(gx, gy) || !scene.items) { return null; } var handler = this; return pickVisit(scene, function(group) { var hit, dx, dy, b; // first hit test against bounding box // if a group is clipped, that should be handled by the bounds check. b = group.bounds; if (b && !b.contains(gx, gy)) return; // passed bounds check, so test sub-groups dx = (group.x || 0); dy = (group.y || 0); context.save(); context.translate(dx, dy); dx = gx - dx; dy = gy - dy; hit = pickVisit(group, function(mark) { return pickMark(mark, dx, dy) ? handler.pick(mark, x, y, dx, dy) : null; }); context.restore(); if (hit) return hit; hit = scene.interactive !== false && (group.fill || group.stroke) && dx >= 0 && dx <= group.width && dy >= 0 && dy <= group.height; return hit ? group : null; }); } function pickMark(mark, x, y) { return (mark.interactive !== false || mark.marktype === 'group') && mark.bounds && mark.bounds.contains(x, y); } var group = { type: 'group', tag: 'g', nested: false, attr: attr, bound: bound, draw: draw, pick: pick$1, background: background, foreground: foreground }; function getImage(item, renderer) { var image = item.image; if (!image || image.url !== item.url) { image = {loaded: false, width: 0, height: 0}; renderer.loadImage(item.url).then(function(image) { item.image = image; item.image.url = item.url; }); } return image; } function imageXOffset(align, w) { return align === 'center' ? w / 2 : align === 'right' ? w : 0; } function imageYOffset(baseline, h) { return baseline === 'middle' ? h / 2 : baseline === 'bottom' ? h : 0; } function attr$1(emit, item, renderer) { var image = getImage(item, renderer), x = item.x || 0, y = item.y || 0, w = (item.width != null ? item.width : image.width) || 0, h = (item.height != null ? item.height : image.height) || 0, a = item.aspect === false ? 'none' : 'xMidYMid'; x -= imageXOffset(item.align, w); y -= imageYOffset(item.baseline, h); emit('href', image.src || '', 'http://www.w3.org/1999/xlink', 'xlink:href'); emit('transform', translate(x, y)); emit('width', w); emit('height', h); emit('preserveAspectRatio', a); } function bound$1(bounds, item) { var image = item.image, x = item.x || 0, y = item.y || 0, w = (item.width != null ? item.width : (image && image.width)) || 0, h = (item.height != null ? item.height : (image && image.height)) || 0; x -= imageXOffset(item.align, w); y -= imageYOffset(item.baseline, h); return bounds.set(x, y, x + w, y + h); } function draw$1(context, scene, bounds) { var renderer = this; visit(scene, function(item) { if (bounds && !bounds.intersects(item.bounds)) return; // bounds check var image = getImage(item, renderer), x = item.x || 0, y = item.y || 0, w = (item.width != null ? item.width : image.width) || 0, h = (item.height != null ? item.height : image.height) || 0, opacity, ar0, ar1, t; x -= imageXOffset(item.align, w); y -= imageYOffset(item.baseline, h); if (item.aspect !== false) { ar0 = image.width / image.height; ar1 = item.width / item.height; if (ar0 === ar0 && ar1 === ar1 && ar0 !== ar1) { if (ar1 < ar0) { t = w / ar0; y += (h - t) / 2; h = t; } else { t = h * ar0; x += (w - t) / 2; w = t; } } } if (image.loaded) { context.globalAlpha = (opacity = item.opacity) != null ? opacity : 1; context.drawImage(image, x, y, w, h); } }); } var image = { type: 'image', tag: 'image', nested: false, attr: attr$1, bound: bound$1, draw: draw$1, pick: pick(), get: getImage, xOffset: imageXOffset, yOffset: imageYOffset }; var line$2 = markMultiItemPath('line', line); function attr$2(emit, item) { emit('transform', translateItem(item)); emit('d', item.path); } function path$2(context$$1, item) { var path = item.path; if (path == null) return true; var cache = item.pathCache; if (!cache || cache.path !== path) { (item.pathCache = cache = pathParse(path)).path = path; } pathRender(context$$1, cache, item.x, item.y); } function bound$2(bounds, item) { return path$2(context(bounds), item) ? bounds.set(0, 0, 0, 0) : boundStroke(bounds, item); } var path$3 = { type: 'path', tag: 'path', nested: false, attr: attr$2, bound: bound$2, draw: drawAll(path$2), pick: pickPath(path$2) }; function attr$3(emit, item) { emit('d', rectangle(null, item)); } function bound$3(bounds, item) { var x, y; return boundStroke(bounds.set( x = item.x || 0, y = item.y || 0, (x + item.width) || 0, (y + item.height) || 0 ), item); } function draw$2(context, item) { context.beginPath(); rectangle(context, item); } var rect = { type: 'rect', tag: 'path', nested: false, attr: attr$3, bound: bound$3, draw: drawAll(draw$2), pick: pickPath(draw$2) }; function attr$4(emit, item) { emit('transform', translateItem(item)); emit('x2', item.x2 != null ? item.x2 - (item.x||0) : 0); emit('y2', item.y2 != null ? item.y2 - (item.y||0) : 0); } function bound$4(bounds, item) { var x1, y1; return boundStroke(bounds.set( x1 = item.x || 0, y1 = item.y || 0, item.x2 != null ? item.x2 : x1, item.y2 != null ? item.y2 : y1 ), item); } function path$4(context, item, opacity) { var x1, y1, x2, y2; if (item.stroke && stroke(context, item, opacity)) { x1 = item.x || 0; y1 = item.y || 0; x2 = item.x2 != null ? item.x2 : x1; y2 = item.y2 != null ? item.y2 : y1; context.beginPath(); context.moveTo(x1, y1); context.lineTo(x2, y2); return true; } return false; } function draw$3(context, scene, bounds) { visit(scene, function(item) { if (bounds && !bounds.intersects(item.bounds)) return; // bounds check var opacity = item.opacity == null ? 1 : item.opacity; if (opacity && path$4(context, item, opacity)) { context.stroke(); } }); } function hit(context, item, x, y) { if (!context.isPointInStroke) return false; return path$4(context, item, 1) && context.isPointInStroke(x, y); } var rule = { type: 'rule', tag: 'line', nested: false, attr: attr$4, bound: bound$4, draw: draw$3, pick: pick(hit) }; var shape$1 = markItemPath('shape', shape); var symbol$1 = markItemPath('symbol', symbol); var context$1; var fontHeight; var textMetrics = { height: height, measureWidth: measureWidth, estimateWidth: estimateWidth, width: estimateWidth, canvas: canvas }; canvas(true); // make dumb, simple estimate if no canvas is available function estimateWidth(item) { fontHeight = height(item); return estimate(textValue(item)); } function estimate(text) { return ~~(0.8 * text.length * fontHeight); } // measure text width if canvas is available function measureWidth(item) { context$1.font = font(item); return measure$1(textValue(item)); } function measure$1(text) { return context$1.measureText(text).width; } function height(item) { return item.fontSize != null ? item.fontSize : 11; } function canvas(use) { context$1 = use && (context$1 = Canvas$1(1,1)) ? context$1.getContext('2d') : null; textMetrics.width = context$1 ? measureWidth : estimateWidth; } function textValue(item) { var s = item.text; if (s == null) { return ''; } else { return item.limit > 0 ? truncate$1(item) : s + ''; } } function truncate$1(item) { var limit = +item.limit, text = item.text + '', width; if (context$1) { context$1.font = font(item); width = measure$1; } else { fontHeight = height(item); width = estimate; } if (width(text) < limit) return text; var ellipsis = item.ellipsis || '\u2026', rtl = item.dir === 'rtl', lo = 0, hi = text.length, mid; limit -= width(ellipsis); if (rtl) { while (lo < hi) { mid = (lo + hi >>> 1); if (width(text.slice(mid)) > limit) lo = mid + 1; else hi = mid; } return ellipsis + text.slice(lo); } else { while (lo < hi) { mid = 1 + (lo + hi >>> 1); if (width(text.slice(0, mid)) < limit) lo = mid; else hi = mid - 1; } return text.slice(0, lo) + ellipsis; } } function font(item, quote) { var font = item.font; if (quote && font) { font = String(font).replace(/"/g, '\''); } return '' + (item.fontStyle ? item.fontStyle + ' ' : '') + (item.fontVariant ? item.fontVariant + ' ' : '') + (item.fontWeight ? item.fontWeight + ' ' : '') + height(item) + 'px ' + (font || 'sans-serif'); } function offset(item) { // perform our own font baseline calculation // why? not all browsers support SVG 1.1 'alignment-baseline' :( var baseline = item.baseline, h = height(item); return Math.round( baseline === 'top' ? 0.93*h : baseline === 'middle' ? 0.30*h : baseline === 'bottom' ? -0.21*h : 0 ); } var textAlign = { 'left': 'start', 'center': 'middle', 'right': 'end' }; var tempBounds = new Bounds(); function attr$5(emit, item) { var dx = item.dx || 0, dy = (item.dy || 0) + offset(item), x = item.x || 0, y = item.y || 0, a = item.angle || 0, r = item.radius || 0, t; if (r) { t = (item.theta || 0) - Math.PI/2; x += r * Math.cos(t); y += r * Math.sin(t); } emit('text-anchor', textAlign[item.align] || 'start'); if (a) { t = translate(x, y) + ' rotate('+a+')'; if (dx || dy) t += ' ' + translate(dx, dy); } else { t = translate(x + dx, y + dy); } emit('transform', t); } function bound$5(bounds, item, noRotate) { var h = textMetrics.height(item), a = item.align, r = item.radius || 0, x = item.x || 0, y = item.y || 0, dx = item.dx || 0, dy = (item.dy || 0) + offset(item) - Math.round(0.8*h), // use 4/5 offset w, t; if (r) { t = (item.theta || 0) - Math.PI/2; x += r * Math.cos(t); y += r * Math.sin(t); } // horizontal alignment w = textMetrics.width(item); if (a === 'center') { dx -= (w / 2); } else if (a === 'right') { dx -= w; } else { // left by default, do nothing } bounds.set(dx+=x, dy+=y, dx+w, dy+h); if (item.angle && !noRotate) { bounds.rotate(item.angle*Math.PI/180, x, y); } return bounds.expand(noRotate || !w ? 0 : 1); } function draw$4(context, scene, bounds) { visit(scene, function(item) { var opacity, x, y, r, t, str; if (bounds && !bounds.intersects(item.bounds)) return; // bounds check if (!(str = textValue(item))) return; // get text string opacity = item.opacity == null ? 1 : item.opacity; if (opacity === 0) return; context.font = font(item); context.textAlign = item.align || 'left'; x = item.x || 0; y = item.y || 0; if ((r = item.radius)) { t = (item.theta || 0) - Math.PI/2; x += r * Math.cos(t); y += r * Math.sin(t); } if (item.angle) { context.save(); context.translate(x, y); context.rotate(item.angle * Math.PI/180); x = y = 0; // reset x, y } x += (item.dx || 0); y += (item.dy || 0) + offset(item); if (item.fill && fill(context, item, opacity)) { context.fillText(str, x, y); } if (item.stroke && stroke(context, item, opacity)) { context.strokeText(str, x, y); } if (item.angle) context.restore(); }); } function hit$1(context, item, x, y, gx, gy) { if (item.fontSize <= 0) return false; if (!item.angle) return true; // bounds sufficient if no rotation // project point into space of unrotated bounds var b = bound$5(tempBounds, item, true), a = -item.angle * Math.PI / 180, cos = Math.cos(a), sin = Math.sin(a), ix = item.x, iy = item.y, px = cos*gx - sin*gy + (ix - ix*cos + iy*sin), py = sin*gx + cos*gy + (iy - ix*sin - iy*cos); return b.contains(px, py); } var text$1 = { type: 'text', tag: 'text', nested: false, attr: attr$5, bound: bound$5, draw: draw$4, pick: pick(hit$1) }; var trail$1 = markMultiItemPath('trail', trail); var marks = { arc: arc, area: area$2, group: group, image: image, line: line$2, path: path$3, rect: rect, rule: rule, shape: shape$1, symbol: symbol$1, text: text$1, trail: trail$1 }; var boundItem$1 = function(item, func, opt) { var type = marks[item.mark.marktype], bound = func || type.bound; if (type.nested) item = item.mark; return bound(item.bounds || (item.bounds = new Bounds()), item, opt); }; var DUMMY = {mark: null}; var boundMark = function(mark, bounds, opt) { var type = marks[mark.marktype], bound = type.bound, items = mark.items, hasItems = items && items.length, i, n, item, b; if (type.nested) { if (hasItems) { item = items[0]; } else { // no items, fake it DUMMY.mark = mark; item = DUMMY; } b = boundItem$1(item, bound, opt); bounds = bounds && bounds.union(b) || b; return bounds; } bounds = bounds || mark.bounds && mark.bounds.clear() || new Bounds(); if (hasItems) { for (i=0, n=items.length; i} origin - The origin of the display, in pixels. * The coordinate system will be translated to this point. * @return {Renderer} - This renderer instance; */ prototype$40.initialize = function(el, width, height, origin) { this._el = el; return this.resize(width, height, origin); }; /** * Returns the parent container element for a visualization. * @return {DOMElement} - The containing DOM element. */ prototype$40.element = function() { return this._el; }; /** * Returns the scene element (e.g., canvas or SVG) of the visualization * Subclasses must override if the first child is not the scene element. * @return {DOMElement} - The scene (e.g., canvas or SVG) element. */ prototype$40.scene = function() { return this._el && this._el.firstChild; }; /** * Get / set the background color. */ prototype$40.background = function(bgcolor) { if (arguments.length === 0) return this._bgcolor; this._bgcolor = bgcolor; return this; }; /** * Resize the display. * @param {number} width - The new width of the display, in pixels. * @param {number} height - The new height of the display, in pixels. * @param {Array} origin - The new origin of the display, in pixels. * The coordinate system will be translated to this point. * @return {Renderer} - This renderer instance; */ prototype$40.resize = function(width, height, origin) { this._width = width; this._height = height; this._origin = origin || [0, 0]; return this; }; /** * Report a dirty item whose bounds should be redrawn. * This base class method does nothing. Subclasses that perform * incremental should implement this method. * @param {Item} item - The dirty item whose bounds should be redrawn. */ prototype$40.dirty = function(/*item*/) { }; /** * Render an input scenegraph, potentially with a set of dirty items. * This method will perform an immediate rendering with available resources. * The renderer may also need to perform image loading to perform a complete * render. This process can lead to asynchronous re-rendering of the scene * after this method returns. To receive notification when rendering is * complete, use the renderAsync method instead. * @param {object} scene - The root mark of a scenegraph to render. * @return {Renderer} - This renderer instance. */ prototype$40.render = function(scene) { var r = this; // bind arguments into a render call, and cache it // this function may be subsequently called for async redraw r._call = function() { r._render(scene); }; // invoke the renderer r._call(); // clear the cached call for garbage collection // async redraws will stash their own copy r._call = null; return r; }; /** * Internal rendering method. Renderer subclasses should override this * method to actually perform rendering. * @param {object} scene - The root mark of a scenegraph to render. */ prototype$40._render = function(/*scene*/) { // subclasses to override }; /** * Asynchronous rendering method. Similar to render, but returns a Promise * that resolves when all rendering is completed. Sometimes a renderer must * perform image loading to get a complete rendering. The returned * Promise will not resolve until this process completes. * @param {object} scene - The root mark of a scenegraph to render. * @return {Promise} - A Promise that resolves when rendering is complete. */ prototype$40.renderAsync = function(scene) { var r = this.render(scene); return this._ready ? this._ready.then(function() { return r; }) : Promise.resolve(r); }; /** * Internal method for asynchronous resource loading. * Proxies method calls to the ImageLoader, and tracks loading * progress to invoke a re-render once complete. * @param {string} method - The method name to invoke on the ImageLoader. * @param {string} uri - The URI for the requested resource. * @return {Promise} - A Promise that resolves to the requested resource. */ prototype$40._load = function(method, uri) { var r = this, p = r._loader[method](uri); if (!r._ready) { // re-render the scene when loading completes var call = r._call; r._ready = r._loader.ready() .then(function(redraw) { if (redraw) call(); r._ready = null; }); } return p; }; /** * Sanitize a URL to include as a hyperlink in the rendered scene. * This method proxies a call to ImageLoader.sanitizeURL, but also tracks * image loading progress and invokes a re-render once complete. * @param {string} uri - The URI string to sanitize. * @return {Promise} - A Promise that resolves to the sanitized URL. */ prototype$40.sanitizeURL = function(uri) { return this._load('sanitizeURL', uri); }; /** * Requests an image to include in the rendered scene. * This method proxies a call to ImageLoader.loadImage, but also tracks * image loading progress and invokes a re-render once complete. * @param {string} uri - The URI string of the image. * @return {Promise} - A Promise that resolves to the loaded Image. */ prototype$40.loadImage = function(uri) { return this._load('loadImage', uri); }; var point$4 = function(event, el) { var rect = el.getBoundingClientRect(); return [ event.clientX - rect.left - (el.clientLeft || 0), event.clientY - rect.top - (el.clientTop || 0) ]; }; function CanvasHandler(loader) { Handler.call(this, loader); this._down = null; this._touch = null; this._first = true; } var prototype$41 = inherits(CanvasHandler, Handler); prototype$41.initialize = function(el, origin, obj) { // add event listeners var canvas = this._canvas = el && domFind(el, 'canvas'); if (canvas) { var that = this; this.events.forEach(function(type) { canvas.addEventListener(type, function(evt) { if (prototype$41[type]) { prototype$41[type].call(that, evt); } else { that.fire(type, evt); } }); }); } return Handler.prototype.initialize.call(this, el, origin, obj); }; prototype$41.canvas = function() { return this._canvas; }; // retrieve the current canvas context prototype$41.context = function() { return this._canvas.getContext('2d'); }; // supported events prototype$41.events = [ 'keydown', 'keypress', 'keyup', 'dragenter', 'dragleave', 'dragover', 'mousedown', 'mouseup', 'mousemove', 'mouseout', 'mouseover', 'click', 'dblclick', 'wheel', 'mousewheel', 'touchstart', 'touchmove', 'touchend' ]; // to keep old versions of firefox happy prototype$41.DOMMouseScroll = function(evt) { this.fire('mousewheel', evt); }; function move(moveEvent, overEvent, outEvent) { return function(evt) { var a = this._active, p = this.pickEvent(evt); if (p === a) { // active item and picked item are the same this.fire(moveEvent, evt); // fire move } else { // active item and picked item are different if (!a || !a.exit) { // fire out for prior active item // suppress if active item was removed from scene this.fire(outEvent, evt); } this._active = p; // set new active item this.fire(overEvent, evt); // fire over for new active item this.fire(moveEvent, evt); // fire move for new active item } }; } function inactive(type) { return function(evt) { this.fire(type, evt); this._active = null; }; } prototype$41.mousemove = move('mousemove', 'mouseover', 'mouseout'); prototype$41.dragover = move('dragover', 'dragenter', 'dragleave'); prototype$41.mouseout = inactive('mouseout'); prototype$41.dragleave = inactive('dragleave'); prototype$41.mousedown = function(evt) { this._down = this._active; this.fire('mousedown', evt); }; prototype$41.click = function(evt) { if (this._down === this._active) { this.fire('click', evt); this._down = null; } }; prototype$41.touchstart = function(evt) { this._touch = this.pickEvent(evt.changedTouches[0]); if (this._first) { this._active = this._touch; this._first = false; } this.fire('touchstart', evt, true); }; prototype$41.touchmove = function(evt) { this.fire('touchmove', evt, true); }; prototype$41.touchend = function(evt) { this.fire('touchend', evt, true); this._touch = null; }; // fire an event prototype$41.fire = function(type, evt, touch) { var a = touch ? this._touch : this._active, h = this._handlers[type], i, len; // if hyperlinked, handle link first if (type === 'click' && a && a.href) { this.handleHref(evt, a, a.href); } else if ((type === 'mouseover' || type === 'mouseout') && a && a.tooltip) { this.handleTooltip(evt, a, type === 'mouseover' ? a.tooltip : null); } // invoke all registered handlers if (h) { evt.vegaType = type; for (i=0, len=h.length; i=0;) { if (h[i].type !== type) continue; if (!handler || h[i].handler === handler) h.splice(i, 1); } return this; }; prototype$41.pickEvent = function(evt) { var p = point$4(evt, this._canvas), o = this._origin; return this.pick(this._scene, p[0], p[1], p[0] - o[0], p[1] - o[1]); }; // find the scenegraph item at the current mouse position // x, y -- the absolute x, y mouse coordinates on the canvas element // gx, gy -- the relative coordinates within the current group prototype$41.pick = function(scene, x, y, gx, gy) { var g = this.context(), mark = marks[scene.marktype]; return mark.pick.call(this, g, scene, x, y, gx, gy); }; var clip$1 = function(context, scene) { var group = scene.group; context.save(); context.beginPath(); context.rect(0, 0, group.width || 0, group.height || 0); context.clip(); }; var devicePixelRatio = typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1; var resize = function(canvas, width, height, origin) { var scale = typeof HTMLElement !== 'undefined' && canvas instanceof HTMLElement && canvas.parentNode != null; var context = canvas.getContext('2d'), ratio = scale ? devicePixelRatio : 1; canvas.width = width * ratio; canvas.height = height * ratio; if (ratio !== 1) { canvas.style.width = width + 'px'; canvas.style.height = height + 'px'; } context.pixelRatio = ratio; context.setTransform( ratio, 0, 0, ratio, ratio * origin[0], ratio * origin[1] ); return canvas; }; function CanvasRenderer(loader) { Renderer.call(this, loader); this._redraw = false; this._dirty = new Bounds(); } var prototype$42 = inherits(CanvasRenderer, Renderer); var base = Renderer.prototype; var tempBounds$1 = new Bounds(); prototype$42.initialize = function(el, width, height, origin) { this._canvas = Canvas$1(1, 1); // instantiate a small canvas if (el) { domClear(el, 0).appendChild(this._canvas); this._canvas.setAttribute('class', 'marks'); } // this method will invoke resize to size the canvas appropriately return base.initialize.call(this, el, width, height, origin); }; prototype$42.resize = function(width, height, origin) { base.resize.call(this, width, height, origin); resize(this._canvas, this._width, this._height, this._origin); this._redraw = true; return this; }; prototype$42.canvas = function() { return this._canvas; }; prototype$42.context = function() { return this._canvas ? this._canvas.getContext('2d') : null; }; prototype$42.dirty = function(item) { var b = translate$1(item.bounds, item.mark.group); this._dirty.union(b); }; function clipToBounds(g, b, origin) { // expand bounds by 1 pixel, then round to pixel boundaries b.expand(1).round(); // to avoid artifacts translate if origin has fractional pixels b.translate(-(origin[0] % 1), -(origin[1] % 1)); // set clipping path g.beginPath(); g.rect(b.x1, b.y1, b.width(), b.height()); g.clip(); return b; } function translate$1(bounds, group) { if (group == null) return bounds; var b = tempBounds$1.clear().union(bounds); for (; group != null; group = group.mark.group) { b.translate(group.x || 0, group.y || 0); } return b; } prototype$42._render = function(scene) { var g = this.context(), o = this._origin, w = this._width, h = this._height, b = this._dirty; // setup g.save(); if (this._redraw || b.empty()) { this._redraw = false; b = null; } else { b = clipToBounds(g, b, o); } this.clear(-o[0], -o[1], w, h); // render this.draw(g, scene, b); // takedown g.restore(); this._dirty.clear(); return this; }; prototype$42.draw = function(ctx, scene, bounds) { var mark = marks[scene.marktype]; if (scene.clip) clip$1(ctx, scene); mark.draw.call(this, ctx, scene, bounds); if (scene.clip) ctx.restore(); }; prototype$42.clear = function(x, y, w, h) { var g = this.context(); g.clearRect(x, y, w, h); if (this._bgcolor != null) { g.fillStyle = this._bgcolor; g.fillRect(x, y, w, h); } }; function SVGHandler(loader) { Handler.call(this, loader); var h = this; h._hrefHandler = listener(h, function(evt, item) { if (item && item.href) h.handleHref(evt, item, item.href); }); h._tooltipHandler = listener(h, function(evt, item) { if (item && item.tooltip) { h.handleTooltip(evt, item, evt.type === 'mouseover' ? item.tooltip : null); } }); } var prototype$43 = inherits(SVGHandler, Handler); prototype$43.initialize = function(el, origin, obj) { var svg = this._svg; if (svg) { svg.removeEventListener('click', this._hrefHandler); svg.removeEventListener('mouseover', this._tooltipHandler); svg.removeEventListener('mouseout', this._tooltipHandler); } this._svg = svg = el && domFind(el, 'svg'); if (svg) { svg.addEventListener('click', this._hrefHandler); svg.addEventListener('mouseover', this._tooltipHandler); svg.addEventListener('mouseout', this._tooltipHandler); } return Handler.prototype.initialize.call(this, el, origin, obj); }; prototype$43.svg = function() { return this._svg; }; // wrap an event listener for the SVG DOM function listener(context, handler) { return function(evt) { var target = evt.target, item = target.__data__; evt.vegaType = evt.type; item = Array.isArray(item) ? item[0] : item; handler.call(context._obj, evt, item); }; } // add an event handler prototype$43.on = function(type, handler) { var name = this.eventName(type), h = this._handlers, x = { type: type, handler: handler, listener: listener(this, handler) }; (h[name] || (h[name] = [])).push(x); if (this._svg) { this._svg.addEventListener(name, x.listener); } return this; }; // remove an event handler prototype$43.off = function(type, handler) { var name = this.eventName(type), svg = this._svg, h = this._handlers[name], i; if (!h) return; for (i=h.length; --i>=0;) { if (h[i].type === type && !handler || h[i].handler === handler) { if (this._svg) { svg.removeEventListener(name, h[i].listener); } h.splice(i, 1); } } return this; }; // generate string for an opening xml tag // tag: the name of the xml tag // attr: hash of attribute name-value pairs to include // raw: additional raw string to include in tag markup function openTag(tag, attr, raw) { var s = '<' + tag, key, val; if (attr) { for (key in attr) { val = attr[key]; if (val != null) { s += ' ' + key + '="' + val + '"'; } } } if (raw) s += ' ' + raw; return s + '>'; } // generate string for closing xml tag // tag: the name of the xml tag function closeTag(tag) { return ''; } var metadata = { 'version': '1.1', 'xmlns': 'http://www.w3.org/2000/svg', 'xmlns:xlink': 'http://www.w3.org/1999/xlink' }; var styles = { 'fill': 'fill', 'fillOpacity': 'fill-opacity', 'stroke': 'stroke', 'strokeWidth': 'stroke-width', 'strokeOpacity': 'stroke-opacity', 'strokeCap': 'stroke-linecap', 'strokeJoin': 'stroke-linejoin', 'strokeDash': 'stroke-dasharray', 'strokeDashOffset': 'stroke-dashoffset', 'strokeMiterLimit': 'stroke-miterlimit', 'opacity': 'opacity' }; var styleProperties = Object.keys(styles); var ns = metadata.xmlns; function SVGRenderer(loader) { Renderer.call(this, loader); this._dirtyID = 1; this._dirty = []; this._svg = null; this._root = null; this._defs = null; } var prototype$44 = inherits(SVGRenderer, Renderer); var base$1 = Renderer.prototype; prototype$44.initialize = function(el, width, height, padding) { if (el) { this._svg = domChild(el, 0, 'svg', ns); this._svg.setAttribute('class', 'marks'); domClear(el, 1); // set the svg root group this._root = domChild(this._svg, 0, 'g', ns); domClear(this._svg, 1); } // create the svg definitions cache this._defs = { gradient: {}, clipping: {} }; // set background color if defined this.background(this._bgcolor); return base$1.initialize.call(this, el, width, height, padding); }; prototype$44.background = function(bgcolor) { if (arguments.length && this._svg) { this._svg.style.setProperty('background-color', bgcolor); } return base$1.background.apply(this, arguments); }; prototype$44.resize = function(width, height, origin) { base$1.resize.call(this, width, height, origin); if (this._svg) { this._svg.setAttribute('width', this._width); this._svg.setAttribute('height', this._height); this._svg.setAttribute('viewBox', '0 0 ' + this._width + ' ' + this._height); this._root.setAttribute('transform', 'translate(' + this._origin + ')'); } this._dirty = []; return this; }; prototype$44.svg = function() { if (!this._svg) return null; var attr = { 'class': 'marks', 'width': this._width, 'height': this._height, 'viewBox': '0 0 ' + this._width + ' ' + this._height }; for (var key$$1 in metadata) { attr[key$$1] = metadata[key$$1]; } return openTag('svg', attr) + this._svg.innerHTML + closeTag('svg'); }; // -- Render entry point -- prototype$44._render = function(scene) { // perform spot updates and re-render markup if (this._dirtyCheck()) { if (this._dirtyAll) this._resetDefs(); this.draw(this._root, scene); domClear(this._root, 1); } this.updateDefs(); this._dirty = []; ++this._dirtyID; return this; }; // -- Manage SVG definitions ('defs') block -- prototype$44.updateDefs = function() { var svg = this._svg, defs = this._defs, el = defs.el, index = 0, id$$1; for (id$$1 in defs.gradient) { if (!el) defs.el = (el = domChild(svg, 0, 'defs', ns)); updateGradient(el, defs.gradient[id$$1], index++); } for (id$$1 in defs.clipping) { if (!el) defs.el = (el = domChild(svg, 0, 'defs', ns)); updateClipping(el, defs.clipping[id$$1], index++); } // clean-up if (el) { if (index === 0) { svg.removeChild(el); defs.el = null; } else { domClear(el, index); } } }; function updateGradient(el, grad, index) { var i, n, stop; el = domChild(el, index, 'linearGradient', ns); el.setAttribute('id', grad.id); el.setAttribute('x1', grad.x1); el.setAttribute('x2', grad.x2); el.setAttribute('y1', grad.y1); el.setAttribute('y2', grad.y2); for (i=0, n=grad.stops.length; i 0) ? openTag('defs') + defs + closeTag('defs') : ''; }; var object$1; function emit$1(name, value, ns, prefixed) { object$1[prefixed || name] = value; } prototype$45.attributes = function(attr, item) { object$1 = {}; attr(emit$1, item, this); return object$1; }; prototype$45.href = function(item) { var that = this, href = item.href, attr; if (href) { if (attr = that._hrefs && that._hrefs[href]) { return attr; } else { that.sanitizeURL(href).then(function(attr) { // rewrite to use xlink namespace // note that this will be deprecated in SVG 2.0 attr['xlink:href'] = attr.href; attr.href = null; (that._hrefs || (that._hrefs = {}))[href] = attr; }); } } return null; }; prototype$45.mark = function(scene) { var renderer = this, mdef = marks[scene.marktype], tag = mdef.tag, defs = this._defs, str = '', style; if (tag !== 'g' && scene.interactive === false) { style = 'style="pointer-events: none;"'; } // render opening group tag str += openTag('g', { 'class': cssClass(scene), 'clip-path': scene.clip ? clip(renderer, scene, scene.group) : null }, style); // render contained elements function process(item) { var href = renderer.href(item); if (href) str += openTag('a', href); style = (tag !== 'g') ? applyStyles(item, scene, tag, defs) : null; str += openTag(tag, renderer.attributes(mdef.attr, item), style); if (tag === 'text') { str += escape_text(textValue(item)); } else if (tag === 'g') { str += openTag('path', renderer.attributes(mdef.background, item), applyStyles(item, scene, 'bgrect', defs)) + closeTag('path'); str += openTag('g', renderer.attributes(mdef.foreground, item)) + renderer.markGroup(item) + closeTag('g'); } str += closeTag(tag); if (href) str += closeTag('a'); } if (mdef.nested) { if (scene.items && scene.items.length) process(scene.items[0]); } else { visit(scene, process); } // render closing group tag return str + closeTag('g'); }; prototype$45.markGroup = function(scene) { var renderer = this, str = ''; visit(scene, function(item) { str += renderer.mark(item); }); return str; }; function applyStyles(o, mark, tag, defs) { if (o == null) return ''; var i, n, prop, name, value, s = ''; if (tag === 'bgrect' && mark.interactive === false) { s += 'pointer-events: none;'; } if (tag === 'text') { s += 'font: ' + font(o) + ';'; } for (i=0, n=styleProperties.length; i/g, '>'); } var Canvas$2 = 'canvas'; var PNG = 'png'; var SVG = 'svg'; var None$1 = 'none'; var RenderType = { Canvas: Canvas$2, PNG: PNG, SVG: SVG, None: None$1 }; var modules = {}; modules[Canvas$2] = modules[PNG] = { renderer: CanvasRenderer, headless: CanvasRenderer, handler: CanvasHandler }; modules[SVG] = { renderer: SVGRenderer, headless: SVGStringRenderer, handler: SVGHandler }; modules[None$1] = {}; function renderModule(name, _) { name = String(name || '').toLowerCase(); if (arguments.length > 1) { modules[name] = _; return this; } else { return modules[name]; } } var TOLERANCE = 1e-9; function sceneEqual(a, b, key$$1) { return (a === b) ? true : (key$$1 === 'path') ? pathEqual(a, b) : (a instanceof Date && b instanceof Date) ? +a === +b : (isNumber(a) && isNumber(b)) ? Math.abs(a - b) <= TOLERANCE : (!a || !b || !isObject(a) && !isObject(b)) ? a == b : (a == null || b == null) ? false : objectEqual(a, b); } function pathEqual(a, b) { return sceneEqual(pathParse(a), pathParse(b)); } function objectEqual(a, b) { var ka = Object.keys(a), kb = Object.keys(b), key$$1, i; if (ka.length !== kb.length) return false; ka.sort(); kb.sort(); for (i = ka.length - 1; i >= 0; i--) { if (ka[i] != kb[i]) return false; } for (i = ka.length - 1; i >= 0; i--) { key$$1 = ka[i]; if (!sceneEqual(a[key$$1], b[key$$1], key$$1)) return false; } return typeof a === typeof b; } /** * Calculate bounding boxes for scenegraph items. * @constructor * @param {object} params - The parameters for this operator. * @param {object} params.mark - The scenegraph mark instance to bound. */ function Bound(params) { Transform.call(this, null, params); } var prototype$35 = inherits(Bound, Transform); var temp = new Bounds(); prototype$35.transform = function(_, pulse) { var view = pulse.dataflow, mark = _.mark, type = mark.marktype, entry = marks[type], bound = entry.bound, clip = mark.clip, markBounds = mark.bounds, rebound; if (entry.nested) { // multi-item marks have a single bounds instance if (mark.items.length) view.dirty(mark.items[0]); markBounds = boundItem(mark, bound); mark.items.forEach(function(item) { item.bounds.clear().union(markBounds); }); } else if (type === 'group' || _.modified()) { // operator parameters modified -> re-bound all items // updates group bounds in response to modified group content pulse.visit(pulse.MOD, function(item) { view.dirty(item); }); markBounds.clear(); mark.items.forEach(function(item) { markBounds.union(boundItem(item, bound)); }); } else { // incrementally update bounds, re-bound mark as needed rebound = pulse.changed(pulse.REM); pulse.visit(pulse.ADD, function(item) { markBounds.union(boundItem(item, bound)); }); pulse.visit(pulse.MOD, function(item) { rebound = rebound || markBounds.alignsWith(item.bounds); view.dirty(item); markBounds.union(boundItem(item, bound)); }); if (rebound && !clip) { markBounds.clear(); mark.items.forEach(function(item) { markBounds.union(item.bounds); }); } } if (clip) { markBounds.intersect(temp.set(0, 0, mark.group.width, mark.group.height)); } return pulse.modifies('bounds'); }; function boundItem(item, bound, opt) { return bound(item.bounds.clear(), item, opt); } var COUNTER_NAME = ':vega_identifier:'; /** * Adds a unique identifier to all added tuples. * This transform creates a new signal that serves as an id counter. * As a result, the id counter is shared across all instances of this * transform, generating unique ids across multiple data streams. In * addition, this signal value can be included in a snapshot of the * dataflow state, enabling correct resumption of id allocation. * @constructor * @param {object} params - The parameters for this operator. * @param {string} params.as - The field name for the generated identifier. */ function Identifier(params) { Transform.call(this, 0, params); } Identifier.Definition = { "type": "Identifier", "metadata": {"modifies": true}, "params": [ { "name": "as", "type": "string", "required": true } ] }; var prototype$46 = inherits(Identifier, Transform); prototype$46.transform = function(_, pulse) { var counter = getCounter(pulse.dataflow), id$$1 = counter.value, as = _.as; pulse.visit(pulse.ADD, function(t) { if (!t[as]) t[as] = ++id$$1; }); counter.set(this.value = id$$1); return pulse; }; function getCounter(view) { var counter = view._signals[COUNTER_NAME]; if (!counter) { view._signals[COUNTER_NAME] = (counter = view.add(0)); } return counter; } /** * Bind scenegraph items to a scenegraph mark instance. * @constructor * @param {object} params - The parameters for this operator. * @param {object} params.markdef - The mark definition for creating the mark. * This is an object of legal scenegraph mark properties which *must* include * the 'marktype' property. * @param {Array} params.scenepath - Scenegraph tree coordinates for the mark. * The path is an array of integers, each indicating the index into * a successive chain of items arrays. */ function Mark(params) { Transform.call(this, null, params); } var prototype$47 = inherits(Mark, Transform); prototype$47.transform = function(_, pulse) { var mark = this.value; // acquire mark on first invocation, bind context and group if (!mark) { mark = pulse.dataflow.scenegraph().mark(_.markdef, lookup$1(_), _.index); mark.group.context = _.context; if (!_.context.group) _.context.group = mark.group; mark.source = this; this.value = mark; } // initialize entering items var Init = mark.marktype === 'group' ? GroupItem : Item; pulse.visit(pulse.ADD, function(item) { Init.call(item, mark); }); // bind items array to scenegraph mark mark.items = pulse.source; return pulse; }; function lookup$1(_) { var g = _.groups, p = _.parent; return g && g.size === 1 ? g.get(Object.keys(g.object)[0]) : g && p ? g.lookup(p) : null; } /** * Analyze items for overlap, changing opacity to hide items with * overlapping bounding boxes. This transform will preserve at least * two items (e.g., first and last) even if overlap persists. * @param {object} params - The parameters for this operator. * @param {object} params.method - The overlap removal method to apply. * One of 'parity' (default, hide every other item until there is no * more overlap) or 'greedy' (sequentially scan and hide and items that * overlap with the last visible item). * @constructor */ function Overlap(params) { Transform.call(this, null, params); } var prototype$48 = inherits(Overlap, Transform); var methods = { parity: function(items) { return items.filter(function(item, i) { return i % 2 ? (item.opacity = 0) : 1; }); }, greedy: function(items) { var a; return items.filter(function(b, i) { if (!i || !intersect$1(a.bounds, b.bounds)) { a = b; return 1; } else { return b.opacity = 0; } }); } }; // compute bounding box intersection // allow 1 pixel of overlap tolerance function intersect$1(a, b) { return !( a.x2 - 1 < b.x1 || a.x1 + 1 > b.x2 || a.y2 - 1 < b.y1 || a.y1 + 1 > b.y2 ); } function hasOverlap(items) { for (var i=1, n=items.length, a=items[0].bounds, b; i 1 && b.height() > 1; } prototype$48.transform = function(_, pulse) { var reduce = methods[_.method] || methods.parity, source = pulse.materialize(pulse.SOURCE).source, items = source; if (!items) return; if (_.method === 'greedy') { items = source = source.filter(hasBounds); } if (items.length >= 3 && hasOverlap(items)) { pulse = pulse.reflow(_.modified()).modifies('opacity'); do { items = reduce(items); } while (items.length >= 3 && hasOverlap(items)); if (items.length < 3 && !peek(source).opacity) { if (items.length > 1) peek(items).opacity = 0; peek(source).opacity = 1; } } return pulse; }; /** * Queue modified scenegraph items for rendering. * @constructor */ function Render(params) { Transform.call(this, null, params); } var prototype$49 = inherits(Render, Transform); prototype$49.transform = function(_, pulse) { var view = pulse.dataflow; pulse.visit(pulse.ALL, function(item) { view.dirty(item); }); // set z-index dirty flag as needed if (pulse.fields && pulse.fields['zindex']) { var item = pulse.source && pulse.source[0]; if (item) item.mark.zdirty = true; } }; var AxisRole$1 = 'axis'; var LegendRole$1 = 'legend'; var RowHeader$1 = 'row-header'; var RowFooter$1 = 'row-footer'; var RowTitle = 'row-title'; var ColHeader$1 = 'column-header'; var ColFooter$1 = 'column-footer'; var ColTitle = 'column-title'; function extractGroups(group) { var groups = group.items, n = groups.length, i = 0, mark, items; var views = { marks: [], rowheaders: [], rowfooters: [], colheaders: [], colfooters: [], rowtitle: null, coltitle: null }; // layout axes, gather legends, collect bounds for (; i limit) { view.warn('Grid headers exceed limit: ' + limit); headers = headers.slice(0, limit); } // apply offset init += offset; // clear mark bounds for all headers for (j=0, m=headers.length; j -1) bounds.union(item.items[i].bounds); if ((i=indices[1]) > -1) bounds.union(item.items[i].bounds); // position axis group and title switch (orient) { case Top: x = position || 0; y = -offset; s = Math.max(minExtent, Math.min(maxExtent, -bounds.y1)); if (title) { if (title.auto) { s += titlePadding; title.y = -s; s += title.bounds.height(); } else { bounds.union(title.bounds); } } bounds.add(0, -s).add(range, 0); break; case Left: x = -offset; y = position || 0; s = Math.max(minExtent, Math.min(maxExtent, -bounds.x1)); if (title) { if (title.auto) { s += titlePadding; title.x = -s; s += title.bounds.width(); } else { bounds.union(title.bounds); } } bounds.add(-s, 0).add(0, range); break; case Right: x = width + offset; y = position || 0; s = Math.max(minExtent, Math.min(maxExtent, bounds.x2)); if (title) { if (title.auto) { s += titlePadding; title.x = s; s += title.bounds.width(); } else { bounds.union(title.bounds); } } bounds.add(0, 0).add(s, range); break; case Bottom: x = position || 0; y = height + offset; s = Math.max(minExtent, Math.min(maxExtent, bounds.y2)); if (title) if (title.auto) { s += titlePadding; title.y = s; s += title.bounds.height(); } else { bounds.union(title.bounds); } bounds.add(0, 0).add(range, s); break; default: x = item.x; y = item.y; } // update bounds boundStroke(bounds.translate(x, y), item); if (set$3(item, 'x', x + AxisOffset) | set$3(item, 'y', y + AxisOffset)) { item.bounds = tempBounds$2; view.dirty(item); item.bounds = bounds; view.dirty(item); } return item.mark.bounds.clear().union(bounds); } function layoutTitle(view, title, axisBounds) { var item = title.items[0], datum = item.datum, orient = datum.orient, offset = item.offset, bounds = item.bounds, x = 0, y = 0; tempBounds$2.clear().union(bounds); // position axis group and title switch (orient) { case Top: x = item.x; y = axisBounds.y1 - offset; break; case Left: x = axisBounds.x1 - offset; y = item.y; break; case Right: x = axisBounds.x2 + offset; y = item.y; break; case Bottom: x = item.x; y = axisBounds.y2 + offset; break; default: x = item.x; y = item.y; } bounds.translate(x - item.x, y - item.y); if (set$3(item, 'x', x) | set$3(item, 'y', y)) { item.bounds = tempBounds$2; view.dirty(item); item.bounds = bounds; view.dirty(item); } // update bounds return title.bounds.clear().union(bounds); } function layoutLegend(view, legend, flow, xBounds, yBounds, width, height) { var item = legend.items[0], datum = item.datum, orient = datum.orient, offset = item.offset, bounds = item.bounds, x = 0, y = 0, w, h, axisBounds; if (orient === Top || orient === Bottom) { axisBounds = yBounds, x = flow[orient]; } else if (orient === Left || orient === Right) { axisBounds = xBounds; y = flow[orient]; } tempBounds$2.clear().union(bounds); bounds.clear(); // aggregate bounds to determine size // shave off 1 pixel because it looks better... item.items.forEach(function(_) { bounds.union(_.bounds); }); w = Math.round(bounds.width()) + 2 * item.padding - 1; h = Math.round(bounds.height()) + 2 * item.padding - 1; switch (orient) { case Left: x -= w + offset - Math.floor(axisBounds.x1); flow.left += h + flow.margin; break; case Right: x += offset + Math.ceil(axisBounds.x2); flow.right += h + flow.margin; break; case Top: y -= h + offset - Math.floor(axisBounds.y1); flow.top += w + flow.margin; break; case Bottom: y += offset + Math.ceil(axisBounds.y2); flow.bottom += w + flow.margin; break; case 'top-left': x += offset; y += offset; break; case 'top-right': x += width - w - offset; y += offset; break; case 'bottom-left': x += offset; y += height - h - offset; break; case 'bottom-right': x += width - w - offset; y += height - h - offset; break; default: x = item.x; y = item.y; } // update bounds boundStroke(bounds.set(x, y, x + w, y + h), item); // update legend layout if (set$3(item, 'x', x) | set$3(item, 'width', w) | set$3(item, 'y', y) | set$3(item, 'height', h)) { item.bounds = tempBounds$2; view.dirty(item); item.bounds = bounds; view.dirty(item); } return item.mark.bounds.clear().union(bounds); } function layoutSize(view, group, viewBounds, _) { var auto = _.autosize || {}, type = auto.type, viewWidth = view._width, viewHeight = view._height, padding = view.padding(); if (view._autosize < 1 || !type) return; var width = Math.max(0, group.width || 0), left = Math.max(0, Math.ceil(-viewBounds.x1)), right = Math.max(0, Math.ceil(viewBounds.x2 - width)), height = Math.max(0, group.height || 0), top = Math.max(0, Math.ceil(-viewBounds.y1)), bottom = Math.max(0, Math.ceil(viewBounds.y2 - height)); if (auto.contains === Padding) { viewWidth -= padding.left + padding.right; viewHeight -= padding.top + padding.bottom; } if (type === None$2) { left = 0; top = 0; width = viewWidth; height = viewHeight; } else if (type === Fit) { width = Math.max(0, viewWidth - left - right); height = Math.max(0, viewHeight - top - bottom); } else if (type === Pad) { viewWidth = width + left + right; viewHeight = height + top + bottom; } view._resizeView( viewWidth, viewHeight, width, height, [left, top], auto.resize ); } var vtx = Object.freeze({ bound: Bound, identifier: Identifier, mark: Mark, overlap: Overlap, render: Render, viewlayout: ViewLayout }); var Log = 'log'; var Pow = 'pow'; var Sqrt = 'sqrt'; var Band = 'band'; var Point = 'point'; var Linear$1 = 'linear'; var Ordinal = 'ordinal'; var Quantile = 'quantile'; var Quantize = 'quantize'; var Threshold = 'threshold'; var BinLinear = 'bin-linear'; var BinOrdinal = 'bin-ordinal'; var Sequential = 'sequential'; var invertRange = function(scale) { return function(_) { var lo = _[0], hi = _[1], t; if (hi < lo) { t = lo; lo = hi; hi = t; } return [ scale.invert(lo), scale.invert(hi) ]; } }; var invertRangeExtent = function(scale) { return function(_) { var range = scale.range(), lo = _[0], hi = _[1], min = -1, max, t, i, n; if (hi < lo) { t = lo; lo = hi; hi = t; } for (i=0, n=range.length; i= lo && range[i] <= hi) { if (min < 0) min = i; max = i; } } if (min < 0) return undefined; lo = scale.invertExtent(range[min]); hi = scale.invertExtent(range[max]); return [ lo[0] === undefined ? lo[1] : lo[0], hi[1] === undefined ? hi[0] : hi[1] ]; } }; var bandSpace = function(count, paddingInner, paddingOuter) { var space = count - paddingInner + paddingOuter * 2; return count ? (space > 0 ? space : 1) : 0; }; var array$2 = Array.prototype; var map$3 = array$2.map; var slice$2 = array$2.slice; var implicit = {name: "implicit"}; function ordinal(range) { var index = map(), domain = [], unknown = implicit; range = range == null ? [] : slice$2.call(range); function scale(d) { var key = d + "", i = index.get(key); if (!i) { if (unknown !== implicit) return unknown; index.set(key, i = domain.push(d)); } return range[(i - 1) % range.length]; } scale.domain = function(_) { if (!arguments.length) return domain.slice(); domain = [], index = map(); var i = -1, n = _.length, d, key; while (++i < n) if (!index.has(key = (d = _[i]) + "")) index.set(key, domain.push(d)); return scale; }; scale.range = function(_) { return arguments.length ? (range = slice$2.call(_), scale) : range.slice(); }; scale.unknown = function(_) { return arguments.length ? (unknown = _, scale) : unknown; }; scale.copy = function() { return ordinal() .domain(domain) .range(range) .unknown(unknown); }; return scale; } var define = function(constructor, factory, prototype) { constructor.prototype = factory.prototype = prototype; prototype.constructor = constructor; }; function extend$1(parent, definition) { var prototype = Object.create(parent.prototype); for (var key in definition) prototype[key] = definition[key]; return prototype; } function Color() {} var darker = 0.7; var brighter = 1 / darker; var reI = "\\s*([+-]?\\d+)\\s*"; var reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*"; var reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*"; var reHex3 = /^#([0-9a-f]{3})$/; var reHex6 = /^#([0-9a-f]{6})$/; var reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$"); var reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$"); var reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$"); var reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$"); var reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$"); var reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$"); var named = { aliceblue: 0xf0f8ff, antiquewhite: 0xfaebd7, aqua: 0x00ffff, aquamarine: 0x7fffd4, azure: 0xf0ffff, beige: 0xf5f5dc, bisque: 0xffe4c4, black: 0x000000, blanchedalmond: 0xffebcd, blue: 0x0000ff, blueviolet: 0x8a2be2, brown: 0xa52a2a, burlywood: 0xdeb887, cadetblue: 0x5f9ea0, chartreuse: 0x7fff00, chocolate: 0xd2691e, coral: 0xff7f50, cornflowerblue: 0x6495ed, cornsilk: 0xfff8dc, crimson: 0xdc143c, cyan: 0x00ffff, darkblue: 0x00008b, darkcyan: 0x008b8b, darkgoldenrod: 0xb8860b, darkgray: 0xa9a9a9, darkgreen: 0x006400, darkgrey: 0xa9a9a9, darkkhaki: 0xbdb76b, darkmagenta: 0x8b008b, darkolivegreen: 0x556b2f, darkorange: 0xff8c00, darkorchid: 0x9932cc, darkred: 0x8b0000, darksalmon: 0xe9967a, darkseagreen: 0x8fbc8f, darkslateblue: 0x483d8b, darkslategray: 0x2f4f4f, darkslategrey: 0x2f4f4f, darkturquoise: 0x00ced1, darkviolet: 0x9400d3, deeppink: 0xff1493, deepskyblue: 0x00bfff, dimgray: 0x696969, dimgrey: 0x696969, dodgerblue: 0x1e90ff, firebrick: 0xb22222, floralwhite: 0xfffaf0, forestgreen: 0x228b22, fuchsia: 0xff00ff, gainsboro: 0xdcdcdc, ghostwhite: 0xf8f8ff, gold: 0xffd700, goldenrod: 0xdaa520, gray: 0x808080, green: 0x008000, greenyellow: 0xadff2f, grey: 0x808080, honeydew: 0xf0fff0, hotpink: 0xff69b4, indianred: 0xcd5c5c, indigo: 0x4b0082, ivory: 0xfffff0, khaki: 0xf0e68c, lavender: 0xe6e6fa, lavenderblush: 0xfff0f5, lawngreen: 0x7cfc00, lemonchiffon: 0xfffacd, lightblue: 0xadd8e6, lightcoral: 0xf08080, lightcyan: 0xe0ffff, lightgoldenrodyellow: 0xfafad2, lightgray: 0xd3d3d3, lightgreen: 0x90ee90, lightgrey: 0xd3d3d3, lightpink: 0xffb6c1, lightsalmon: 0xffa07a, lightseagreen: 0x20b2aa, lightskyblue: 0x87cefa, lightslategray: 0x778899, lightslategrey: 0x778899, lightsteelblue: 0xb0c4de, lightyellow: 0xffffe0, lime: 0x00ff00, limegreen: 0x32cd32, linen: 0xfaf0e6, magenta: 0xff00ff, maroon: 0x800000, mediumaquamarine: 0x66cdaa, mediumblue: 0x0000cd, mediumorchid: 0xba55d3, mediumpurple: 0x9370db, mediumseagreen: 0x3cb371, mediumslateblue: 0x7b68ee, mediumspringgreen: 0x00fa9a, mediumturquoise: 0x48d1cc, mediumvioletred: 0xc71585, midnightblue: 0x191970, mintcream: 0xf5fffa, mistyrose: 0xffe4e1, moccasin: 0xffe4b5, navajowhite: 0xffdead, navy: 0x000080, oldlace: 0xfdf5e6, olive: 0x808000, olivedrab: 0x6b8e23, orange: 0xffa500, orangered: 0xff4500, orchid: 0xda70d6, palegoldenrod: 0xeee8aa, palegreen: 0x98fb98, paleturquoise: 0xafeeee, palevioletred: 0xdb7093, papayawhip: 0xffefd5, peachpuff: 0xffdab9, peru: 0xcd853f, pink: 0xffc0cb, plum: 0xdda0dd, powderblue: 0xb0e0e6, purple: 0x800080, rebeccapurple: 0x663399, red: 0xff0000, rosybrown: 0xbc8f8f, royalblue: 0x4169e1, saddlebrown: 0x8b4513, salmon: 0xfa8072, sandybrown: 0xf4a460, seagreen: 0x2e8b57, seashell: 0xfff5ee, sienna: 0xa0522d, silver: 0xc0c0c0, skyblue: 0x87ceeb, slateblue: 0x6a5acd, slategray: 0x708090, slategrey: 0x708090, snow: 0xfffafa, springgreen: 0x00ff7f, steelblue: 0x4682b4, tan: 0xd2b48c, teal: 0x008080, thistle: 0xd8bfd8, tomato: 0xff6347, turquoise: 0x40e0d0, violet: 0xee82ee, wheat: 0xf5deb3, white: 0xffffff, whitesmoke: 0xf5f5f5, yellow: 0xffff00, yellowgreen: 0x9acd32 }; define(Color, color$1, { displayable: function() { return this.rgb().displayable(); }, toString: function() { return this.rgb() + ""; } }); function color$1(format) { var m; format = (format + "").trim().toLowerCase(); return (m = reHex3.exec(format)) ? (m = parseInt(m[1], 16), new Rgb((m >> 8 & 0xf) | (m >> 4 & 0x0f0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1)) // #f00 : (m = reHex6.exec(format)) ? rgbn(parseInt(m[1], 16)) // #ff0000 : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0) : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%) : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1) : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1) : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%) : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1) : named.hasOwnProperty(format) ? rgbn(named[format]) : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null; } function rgbn(n) { return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1); } function rgba(r, g, b, a) { if (a <= 0) r = g = b = NaN; return new Rgb(r, g, b, a); } function rgbConvert(o) { if (!(o instanceof Color)) o = color$1(o); if (!o) return new Rgb; o = o.rgb(); return new Rgb(o.r, o.g, o.b, o.opacity); } function rgb(r, g, b, opacity) { return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity); } function Rgb(r, g, b, opacity) { this.r = +r; this.g = +g; this.b = +b; this.opacity = +opacity; } define(Rgb, rgb, extend$1(Color, { brighter: function(k) { k = k == null ? brighter : Math.pow(brighter, k); return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity); }, darker: function(k) { k = k == null ? darker : Math.pow(darker, k); return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity); }, rgb: function() { return this; }, displayable: function() { return (0 <= this.r && this.r <= 255) && (0 <= this.g && this.g <= 255) && (0 <= this.b && this.b <= 255) && (0 <= this.opacity && this.opacity <= 1); }, toString: function() { var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a)); return (a === 1 ? "rgb(" : "rgba(") + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", " + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", " + Math.max(0, Math.min(255, Math.round(this.b) || 0)) + (a === 1 ? ")" : ", " + a + ")"); } })); function hsla(h, s, l, a) { if (a <= 0) h = s = l = NaN; else if (l <= 0 || l >= 1) h = s = NaN; else if (s <= 0) h = NaN; return new Hsl(h, s, l, a); } function hslConvert(o) { if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity); if (!(o instanceof Color)) o = color$1(o); if (!o) return new Hsl; if (o instanceof Hsl) return o; o = o.rgb(); var r = o.r / 255, g = o.g / 255, b = o.b / 255, min = Math.min(r, g, b), max = Math.max(r, g, b), h = NaN, s = max - min, l = (max + min) / 2; if (s) { if (r === max) h = (g - b) / s + (g < b) * 6; else if (g === max) h = (b - r) / s + 2; else h = (r - g) / s + 4; s /= l < 0.5 ? max + min : 2 - max - min; h *= 60; } else { s = l > 0 && l < 1 ? 0 : h; } return new Hsl(h, s, l, o.opacity); } function hsl(h, s, l, opacity) { return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity); } function Hsl(h, s, l, opacity) { this.h = +h; this.s = +s; this.l = +l; this.opacity = +opacity; } define(Hsl, hsl, extend$1(Color, { brighter: function(k) { k = k == null ? brighter : Math.pow(brighter, k); return new Hsl(this.h, this.s, this.l * k, this.opacity); }, darker: function(k) { k = k == null ? darker : Math.pow(darker, k); return new Hsl(this.h, this.s, this.l * k, this.opacity); }, rgb: function() { var h = this.h % 360 + (this.h < 0) * 360, s = isNaN(h) || isNaN(this.s) ? 0 : this.s, l = this.l, m2 = l + (l < 0.5 ? l : 1 - l) * s, m1 = 2 * l - m2; return new Rgb( hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2), hsl2rgb(h, m1, m2), hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2), this.opacity ); }, displayable: function() { return (0 <= this.s && this.s <= 1 || isNaN(this.s)) && (0 <= this.l && this.l <= 1) && (0 <= this.opacity && this.opacity <= 1); } })); /* From FvD 13.37, CSS Color Module Level 3 */ function hsl2rgb(h, m1, m2) { return (h < 60 ? m1 + (m2 - m1) * h / 60 : h < 180 ? m2 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 : m1) * 255; } var deg2rad = Math.PI / 180; var rad2deg = 180 / Math.PI; var Kn = 18; var Xn = 0.950470; var Yn = 1; var Zn = 1.088830; var t0$1 = 4 / 29; var t1$1 = 6 / 29; var t2 = 3 * t1$1 * t1$1; var t3 = t1$1 * t1$1 * t1$1; function labConvert(o) { if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity); if (o instanceof Hcl) { var h = o.h * deg2rad; return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity); } if (!(o instanceof Rgb)) o = rgbConvert(o); var b = rgb2xyz(o.r), a = rgb2xyz(o.g), l = rgb2xyz(o.b), x = xyz2lab((0.4124564 * b + 0.3575761 * a + 0.1804375 * l) / Xn), y = xyz2lab((0.2126729 * b + 0.7151522 * a + 0.0721750 * l) / Yn), z = xyz2lab((0.0193339 * b + 0.1191920 * a + 0.9503041 * l) / Zn); return new Lab(116 * y - 16, 500 * (x - y), 200 * (y - z), o.opacity); } function lab(l, a, b, opacity) { return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity); } function Lab(l, a, b, opacity) { this.l = +l; this.a = +a; this.b = +b; this.opacity = +opacity; } define(Lab, lab, extend$1(Color, { brighter: function(k) { return new Lab(this.l + Kn * (k == null ? 1 : k), this.a, this.b, this.opacity); }, darker: function(k) { return new Lab(this.l - Kn * (k == null ? 1 : k), this.a, this.b, this.opacity); }, rgb: function() { var y = (this.l + 16) / 116, x = isNaN(this.a) ? y : y + this.a / 500, z = isNaN(this.b) ? y : y - this.b / 200; y = Yn * lab2xyz(y); x = Xn * lab2xyz(x); z = Zn * lab2xyz(z); return new Rgb( xyz2rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z), // D65 -> sRGB xyz2rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z), xyz2rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z), this.opacity ); } })); function xyz2lab(t) { return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0$1; } function lab2xyz(t) { return t > t1$1 ? t * t * t : t2 * (t - t0$1); } function xyz2rgb(x) { return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055); } function rgb2xyz(x) { return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4); } function hclConvert(o) { if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity); if (!(o instanceof Lab)) o = labConvert(o); var h = Math.atan2(o.b, o.a) * rad2deg; return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity); } function hcl(h, c, l, opacity) { return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity); } function Hcl(h, c, l, opacity) { this.h = +h; this.c = +c; this.l = +l; this.opacity = +opacity; } define(Hcl, hcl, extend$1(Color, { brighter: function(k) { return new Hcl(this.h, this.c, this.l + Kn * (k == null ? 1 : k), this.opacity); }, darker: function(k) { return new Hcl(this.h, this.c, this.l - Kn * (k == null ? 1 : k), this.opacity); }, rgb: function() { return labConvert(this).rgb(); } })); var A = -0.14861; var B = +1.78277; var C = -0.29227; var D = -0.90649; var E = +1.97294; var ED = E * D; var EB = E * B; var BC_DA = B * C - D * A; function cubehelixConvert(o) { if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity); if (!(o instanceof Rgb)) o = rgbConvert(o); var r = o.r / 255, g = o.g / 255, b = o.b / 255, l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB), bl = b - l, k = (E * (g - l) - C * bl) / D, s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), // NaN if l=0 or l=1 h = s ? Math.atan2(k, bl) * rad2deg - 120 : NaN; return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity); } function cubehelix(h, s, l, opacity) { return arguments.length === 1 ? cubehelixConvert(h) : new Cubehelix(h, s, l, opacity == null ? 1 : opacity); } function Cubehelix(h, s, l, opacity) { this.h = +h; this.s = +s; this.l = +l; this.opacity = +opacity; } define(Cubehelix, cubehelix, extend$1(Color, { brighter: function(k) { k = k == null ? brighter : Math.pow(brighter, k); return new Cubehelix(this.h, this.s, this.l * k, this.opacity); }, darker: function(k) { k = k == null ? darker : Math.pow(darker, k); return new Cubehelix(this.h, this.s, this.l * k, this.opacity); }, rgb: function() { var h = isNaN(this.h) ? 0 : (this.h + 120) * deg2rad, l = +this.l, a = isNaN(this.s) ? 0 : this.s * l * (1 - l), cosh = Math.cos(h), sinh = Math.sin(h); return new Rgb( 255 * (l + a * (A * cosh + B * sinh)), 255 * (l + a * (C * cosh + D * sinh)), 255 * (l + a * (E * cosh)), this.opacity ); } })); function basis(t1, v0, v1, v2, v3) { var t2 = t1 * t1, t3 = t2 * t1; return ((1 - 3 * t1 + 3 * t2 - t3) * v0 + (4 - 6 * t2 + 3 * t3) * v1 + (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2 + t3 * v3) / 6; } var basis$1 = function(values) { var n = values.length - 1; return function(t) { var i = t <= 0 ? (t = 0) : t >= 1 ? (t = 1, n - 1) : Math.floor(t * n), v1 = values[i], v2 = values[i + 1], v0 = i > 0 ? values[i - 1] : 2 * v1 - v2, v3 = i < n - 1 ? values[i + 2] : 2 * v2 - v1; return basis((t - i / n) * n, v0, v1, v2, v3); }; }; var basisClosed = function(values) { var n = values.length; return function(t) { var i = Math.floor(((t %= 1) < 0 ? ++t : t) * n), v0 = values[(i + n - 1) % n], v1 = values[i % n], v2 = values[(i + 1) % n], v3 = values[(i + 2) % n]; return basis((t - i / n) * n, v0, v1, v2, v3); }; }; var constant$4 = function(x) { return function() { return x; }; }; function linear$1(a, d) { return function(t) { return a + t * d; }; } function exponential(a, b, y) { return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) { return Math.pow(a + t * b, y); }; } function hue(a, b) { var d = b - a; return d ? linear$1(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant$4(isNaN(a) ? b : a); } function gamma(y) { return (y = +y) === 1 ? nogamma : function(a, b) { return b - a ? exponential(a, b, y) : constant$4(isNaN(a) ? b : a); }; } function nogamma(a, b) { var d = b - a; return d ? linear$1(a, d) : constant$4(isNaN(a) ? b : a); } var rgb$1 = (function rgbGamma(y) { var color$$1 = gamma(y); function rgb$$1(start, end) { var r = color$$1((start = rgb(start)).r, (end = rgb(end)).r), g = color$$1(start.g, end.g), b = color$$1(start.b, end.b), opacity = nogamma(start.opacity, end.opacity); return function(t) { start.r = r(t); start.g = g(t); start.b = b(t); start.opacity = opacity(t); return start + ""; }; } rgb$$1.gamma = rgbGamma; return rgb$$1; })(1); function rgbSpline(spline) { return function(colors) { var n = colors.length, r = new Array(n), g = new Array(n), b = new Array(n), i, color$$1; for (i = 0; i < n; ++i) { color$$1 = rgb(colors[i]); r[i] = color$$1.r || 0; g[i] = color$$1.g || 0; b[i] = color$$1.b || 0; } r = spline(r); g = spline(g); b = spline(b); color$$1.opacity = 1; return function(t) { color$$1.r = r(t); color$$1.g = g(t); color$$1.b = b(t); return color$$1 + ""; }; }; } var rgbBasis = rgbSpline(basis$1); var rgbBasisClosed = rgbSpline(basisClosed); var array$3 = function(a, b) { var nb = b ? b.length : 0, na = a ? Math.min(nb, a.length) : 0, x = new Array(nb), c = new Array(nb), i; for (i = 0; i < na; ++i) x[i] = interpolate(a[i], b[i]); for (; i < nb; ++i) c[i] = b[i]; return function(t) { for (i = 0; i < na; ++i) c[i] = x[i](t); return c; }; }; var date = function(a, b) { var d = new Date; return a = +a, b -= a, function(t) { return d.setTime(a + b * t), d; }; }; var reinterpolate = function(a, b) { return a = +a, b -= a, function(t) { return a + b * t; }; }; var object$2 = function(a, b) { var i = {}, c = {}, k; if (a === null || typeof a !== "object") a = {}; if (b === null || typeof b !== "object") b = {}; for (k in b) { if (k in a) { i[k] = interpolate(a[k], b[k]); } else { c[k] = b[k]; } } return function(t) { for (k in i) c[k] = i[k](t); return c; }; }; var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g; var reB = new RegExp(reA.source, "g"); function zero$1(b) { return function() { return b; }; } function one$1(b) { return function(t) { return b(t) + ""; }; } var string = function(a, b) { var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b am, // current match in a bm, // current match in b bs, // string preceding current number in b, if any i = -1, // index in s s = [], // string constants and placeholders q = []; // number interpolators // Coerce inputs to strings. a = a + "", b = b + ""; // Interpolate pairs of numbers in a & b. while ((am = reA.exec(a)) && (bm = reB.exec(b))) { if ((bs = bm.index) > bi) { // a string precedes the next number in b bs = b.slice(bi, bs); if (s[i]) s[i] += bs; // coalesce with previous string else s[++i] = bs; } if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match if (s[i]) s[i] += bm; // coalesce with previous string else s[++i] = bm; } else { // interpolate non-matching numbers s[++i] = null; q.push({i: i, x: reinterpolate(am, bm)}); } bi = reB.lastIndex; } // Add remains of b. if (bi < b.length) { bs = b.slice(bi); if (s[i]) s[i] += bs; // coalesce with previous string else s[++i] = bs; } // Special optimization for only a single match. // Otherwise, interpolate each of the numbers and rejoin the string. return s.length < 2 ? (q[0] ? one$1(q[0].x) : zero$1(b)) : (b = q.length, function(t) { for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t); return s.join(""); }); }; var interpolate = function(a, b) { var t = typeof b, c; return b == null || t === "boolean" ? constant$4(b) : (t === "number" ? reinterpolate : t === "string" ? ((c = color$1(b)) ? (b = c, rgb$1) : string) : b instanceof color$1 ? rgb$1 : b instanceof Date ? date : Array.isArray(b) ? array$3 : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object$2 : reinterpolate)(a, b); }; var interpolateRound = function(a, b) { return a = +a, b -= a, function(t) { return Math.round(a + b * t); }; }; var degrees = 180 / Math.PI; var identity$4 = { translateX: 0, translateY: 0, rotate: 0, skewX: 0, scaleX: 1, scaleY: 1 }; var decompose = function(a, b, c, d, e, f) { var scaleX, scaleY, skewX; if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX; if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX; if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY; if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX; return { translateX: e, translateY: f, rotate: Math.atan2(b, a) * degrees, skewX: Math.atan(skewX) * degrees, scaleX: scaleX, scaleY: scaleY }; }; var cssNode; var cssRoot; var cssView; var svgNode; function parseCss(value) { if (value === "none") return identity$4; if (!cssNode) cssNode = document.createElement("DIV"), cssRoot = document.documentElement, cssView = document.defaultView; cssNode.style.transform = value; value = cssView.getComputedStyle(cssRoot.appendChild(cssNode), null).getPropertyValue("transform"); cssRoot.removeChild(cssNode); value = value.slice(7, -1).split(","); return decompose(+value[0], +value[1], +value[2], +value[3], +value[4], +value[5]); } function parseSvg(value) { if (value == null) return identity$4; if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g"); svgNode.setAttribute("transform", value); if (!(value = svgNode.transform.baseVal.consolidate())) return identity$4; value = value.matrix; return decompose(value.a, value.b, value.c, value.d, value.e, value.f); } function interpolateTransform(parse, pxComma, pxParen, degParen) { function pop(s) { return s.length ? s.pop() + " " : ""; } function translate(xa, ya, xb, yb, s, q) { if (xa !== xb || ya !== yb) { var i = s.push("translate(", null, pxComma, null, pxParen); q.push({i: i - 4, x: reinterpolate(xa, xb)}, {i: i - 2, x: reinterpolate(ya, yb)}); } else if (xb || yb) { s.push("translate(" + xb + pxComma + yb + pxParen); } } function rotate(a, b, s, q) { if (a !== b) { if (a - b > 180) b += 360; else if (b - a > 180) a += 360; // shortest path q.push({i: s.push(pop(s) + "rotate(", null, degParen) - 2, x: reinterpolate(a, b)}); } else if (b) { s.push(pop(s) + "rotate(" + b + degParen); } } function skewX(a, b, s, q) { if (a !== b) { q.push({i: s.push(pop(s) + "skewX(", null, degParen) - 2, x: reinterpolate(a, b)}); } else if (b) { s.push(pop(s) + "skewX(" + b + degParen); } } function scale(xa, ya, xb, yb, s, q) { if (xa !== xb || ya !== yb) { var i = s.push(pop(s) + "scale(", null, ",", null, ")"); q.push({i: i - 4, x: reinterpolate(xa, xb)}, {i: i - 2, x: reinterpolate(ya, yb)}); } else if (xb !== 1 || yb !== 1) { s.push(pop(s) + "scale(" + xb + "," + yb + ")"); } } return function(a, b) { var s = [], // string constants and placeholders q = []; // number interpolators a = parse(a), b = parse(b); translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q); rotate(a.rotate, b.rotate, s, q); skewX(a.skewX, b.skewX, s, q); scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q); a = b = null; // gc return function(t) { var i = -1, n = q.length, o; while (++i < n) s[(o = q[i]).i] = o.x(t); return s.join(""); }; }; } var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)"); var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")"); var rho = Math.SQRT2; var rho2 = 2; var rho4 = 4; var epsilon2 = 1e-12; function cosh(x) { return ((x = Math.exp(x)) + 1 / x) / 2; } function sinh(x) { return ((x = Math.exp(x)) - 1 / x) / 2; } function tanh(x) { return ((x = Math.exp(2 * x)) - 1) / (x + 1); } // p0 = [ux0, uy0, w0] // p1 = [ux1, uy1, w1] var zoom = function(p0, p1) { var ux0 = p0[0], uy0 = p0[1], w0 = p0[2], ux1 = p1[0], uy1 = p1[1], w1 = p1[2], dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, i, S; // Special case for u0 ≅ u1. if (d2 < epsilon2) { S = Math.log(w1 / w0) / rho; i = function(t) { return [ ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(rho * t * S) ]; }; } // General case. else { var d1 = Math.sqrt(d2), b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1), b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1), r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1); S = (r1 - r0) / rho; i = function(t) { var s = t * S, coshr0 = cosh(r0), u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0)); return [ ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / cosh(rho * s + r0) ]; }; } i.duration = S * 1000; return i; }; function hsl$1(hue$$1) { return function(start, end) { var h = hue$$1((start = hsl(start)).h, (end = hsl(end)).h), s = nogamma(start.s, end.s), l = nogamma(start.l, end.l), opacity = nogamma(start.opacity, end.opacity); return function(t) { start.h = h(t); start.s = s(t); start.l = l(t); start.opacity = opacity(t); return start + ""; }; } } var hsl$2 = hsl$1(hue); var hslLong = hsl$1(nogamma); function lab$1(start, end) { var l = nogamma((start = lab(start)).l, (end = lab(end)).l), a = nogamma(start.a, end.a), b = nogamma(start.b, end.b), opacity = nogamma(start.opacity, end.opacity); return function(t) { start.l = l(t); start.a = a(t); start.b = b(t); start.opacity = opacity(t); return start + ""; }; } function hcl$1(hue$$1) { return function(start, end) { var h = hue$$1((start = hcl(start)).h, (end = hcl(end)).h), c = nogamma(start.c, end.c), l = nogamma(start.l, end.l), opacity = nogamma(start.opacity, end.opacity); return function(t) { start.h = h(t); start.c = c(t); start.l = l(t); start.opacity = opacity(t); return start + ""; }; } } var hcl$2 = hcl$1(hue); var hclLong = hcl$1(nogamma); function cubehelix$1(hue$$1) { return (function cubehelixGamma(y) { y = +y; function cubehelix$$1(start, end) { var h = hue$$1((start = cubehelix(start)).h, (end = cubehelix(end)).h), s = nogamma(start.s, end.s), l = nogamma(start.l, end.l), opacity = nogamma(start.opacity, end.opacity); return function(t) { start.h = h(t); start.s = s(t); start.l = l(Math.pow(t, y)); start.opacity = opacity(t); return start + ""; }; } cubehelix$$1.gamma = cubehelixGamma; return cubehelix$$1; })(1); } var cubehelix$2 = cubehelix$1(hue); var cubehelixLong = cubehelix$1(nogamma); var quantize = function(interpolator, n) { var samples = new Array(n); for (var i = 0; i < n; ++i) samples[i] = interpolator(i / (n - 1)); return samples; }; var $$1 = Object.freeze({ interpolate: interpolate, interpolateArray: array$3, interpolateBasis: basis$1, interpolateBasisClosed: basisClosed, interpolateDate: date, interpolateNumber: reinterpolate, interpolateObject: object$2, interpolateRound: interpolateRound, interpolateString: string, interpolateTransformCss: interpolateTransformCss, interpolateTransformSvg: interpolateTransformSvg, interpolateZoom: zoom, interpolateRgb: rgb$1, interpolateRgbBasis: rgbBasis, interpolateRgbBasisClosed: rgbBasisClosed, interpolateHsl: hsl$2, interpolateHslLong: hslLong, interpolateLab: lab$1, interpolateHcl: hcl$2, interpolateHclLong: hclLong, interpolateCubehelix: cubehelix$2, interpolateCubehelixLong: cubehelixLong, quantize: quantize }); var constant$5 = function(x) { return function() { return x; }; }; var number$2 = function(x) { return +x; }; var unit = [0, 1]; function deinterpolateLinear(a, b) { return (b -= (a = +a)) ? function(x) { return (x - a) / b; } : constant$5(b); } function deinterpolateClamp(deinterpolate) { return function(a, b) { var d = deinterpolate(a = +a, b = +b); return function(x) { return x <= a ? 0 : x >= b ? 1 : d(x); }; }; } function reinterpolateClamp(reinterpolate$$1) { return function(a, b) { var r = reinterpolate$$1(a = +a, b = +b); return function(t) { return t <= 0 ? a : t >= 1 ? b : r(t); }; }; } function bimap(domain, range, deinterpolate, reinterpolate$$1) { var d0 = domain[0], d1 = domain[1], r0 = range[0], r1 = range[1]; if (d1 < d0) d0 = deinterpolate(d1, d0), r0 = reinterpolate$$1(r1, r0); else d0 = deinterpolate(d0, d1), r0 = reinterpolate$$1(r0, r1); return function(x) { return r0(d0(x)); }; } function polymap(domain, range, deinterpolate, reinterpolate$$1) { var j = Math.min(domain.length, range.length) - 1, d = new Array(j), r = new Array(j), i = -1; // Reverse descending domains. if (domain[j] < domain[0]) { domain = domain.slice().reverse(); range = range.slice().reverse(); } while (++i < j) { d[i] = deinterpolate(domain[i], domain[i + 1]); r[i] = reinterpolate$$1(range[i], range[i + 1]); } return function(x) { var i = bisectRight(domain, x, 1, j) - 1; return r[i](d[i](x)); }; } function copy(source, target) { return target .domain(source.domain()) .range(source.range()) .interpolate(source.interpolate()) .clamp(source.clamp()); } // deinterpolate(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1]. // reinterpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding domain value x in [a,b]. function continuous(deinterpolate, reinterpolate$$1) { var domain = unit, range = unit, interpolate$$1 = interpolate, clamp = false, piecewise, output, input; function rescale() { piecewise = Math.min(domain.length, range.length) > 2 ? polymap : bimap; output = input = null; return scale; } function scale(x) { return (output || (output = piecewise(domain, range, clamp ? deinterpolateClamp(deinterpolate) : deinterpolate, interpolate$$1)))(+x); } scale.invert = function(y) { return (input || (input = piecewise(range, domain, deinterpolateLinear, clamp ? reinterpolateClamp(reinterpolate$$1) : reinterpolate$$1)))(+y); }; scale.domain = function(_) { return arguments.length ? (domain = map$3.call(_, number$2), rescale()) : domain.slice(); }; scale.range = function(_) { return arguments.length ? (range = slice$2.call(_), rescale()) : range.slice(); }; scale.rangeRound = function(_) { return range = slice$2.call(_), interpolate$$1 = interpolateRound, rescale(); }; scale.clamp = function(_) { return arguments.length ? (clamp = !!_, rescale()) : clamp; }; scale.interpolate = function(_) { return arguments.length ? (interpolate$$1 = _, rescale()) : interpolate$$1; }; return rescale(); } // 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, formatDecimal(1.23) returns ["123", 0]. var formatDecimal = function(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) ]; }; var exponent = function(x) { return x = formatDecimal(Math.abs(x)), x ? x[1] : NaN; }; var formatGroup = function(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); }; }; var formatNumerals = function(numerals) { return function(value) { return value.replace(/[0-9]/g, function(i) { return numerals[+i]; }); }; }; var formatDefault = function(x, p) { x = x.toPrecision(p); out: for (var n = x.length, i = 1, i0 = -1, i1; i < n; ++i) { switch (x[i]) { case ".": i0 = i1 = i; break; case "0": if (i0 === 0) i0 = i; i1 = i; break; case "e": break out; default: if (i0 > 0) i0 = 0; break; } } return i0 > 0 ? x.slice(0, i0) + x.slice(i1 + 1) : x; }; var prefixExponent; var formatPrefixAuto = function(x, p) { var d = formatDecimal(x, p); if (!d) return x + ""; var coefficient = d[0], exponent = d[1], i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1, n = coefficient.length; return i === n ? coefficient : i > n ? coefficient + new Array(i - n + 1).join("0") : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i) : "0." + new Array(1 - i).join("0") + formatDecimal(x, Math.max(0, p + i - 1))[0]; // less than 1y! }; var formatRounded = function(x, p) { var d = formatDecimal(x, p); if (!d) return x + ""; var coefficient = d[0], exponent = d[1]; return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1) : coefficient + new Array(exponent - coefficient.length + 2).join("0"); }; var formatTypes = { "": formatDefault, "%": function(x, p) { return (x * 100).toFixed(p); }, "b": function(x) { return Math.round(x).toString(2); }, "c": function(x) { return x + ""; }, "d": function(x) { return Math.round(x).toString(10); }, "e": function(x, p) { return x.toExponential(p); }, "f": function(x, p) { return x.toFixed(p); }, "g": function(x, p) { return x.toPrecision(p); }, "o": function(x) { return Math.round(x).toString(8); }, "p": function(x, p) { return formatRounded(x * 100, p); }, "r": formatRounded, "s": formatPrefixAuto, "X": function(x) { return Math.round(x).toString(16).toUpperCase(); }, "x": function(x) { return Math.round(x).toString(16); } }; // [[fill]align][sign][symbol][0][width][,][.precision][type] var re = /^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i; function formatSpecifier(specifier) { return new FormatSpecifier(specifier); } formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof function FormatSpecifier(specifier) { if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier); var match, fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "-", symbol = match[4] || "", zero = !!match[5], width = match[6] && +match[6], comma = !!match[7], precision = match[8] && +match[8].slice(1), type = match[9] || ""; // The "n" type is an alias for ",g". if (type === "n") comma = true, type = "g"; // Map invalid types to the default format. else if (!formatTypes[type]) type = ""; // If zero fill is specified, padding goes after sign and before digits. if (zero || (fill === "0" && align === "=")) zero = true, fill = "0", align = "="; this.fill = fill; this.align = align; this.sign = sign; this.symbol = symbol; this.zero = zero; this.width = width; this.comma = comma; this.precision = precision; this.type = type; } FormatSpecifier.prototype.toString = function() { return this.fill + this.align + this.sign + this.symbol + (this.zero ? "0" : "") + (this.width == null ? "" : Math.max(1, this.width | 0)) + (this.comma ? "," : "") + (this.precision == null ? "" : "." + Math.max(0, this.precision | 0)) + this.type; }; var identity$5 = function(x) { return x; }; var prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"]; var formatLocale$1 = function(locale) { var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity$5, currency = locale.currency, decimal = locale.decimal, numerals = locale.numerals ? formatNumerals(locale.numerals) : identity$5, percent = locale.percent || "%"; function newFormat(specifier) { specifier = formatSpecifier(specifier); var fill = specifier.fill, align = specifier.align, sign = specifier.sign, symbol = specifier.symbol, zero = specifier.zero, width = specifier.width, comma = specifier.comma, precision = specifier.precision, type = specifier.type; // Compute the prefix and suffix. // For SI-prefix, the suffix is lazily computed. var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "", suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? percent : ""; // What format function should we use? // Is this an integer type? // Can this type generate exponential notation? var formatType = formatTypes[type], maybeSuffix = !type || /[defgprs%]/.test(type); // Set the default precision if not specified, // or clamp the specified precision to the supported range. // For significant precision, it must be in [1, 21]. // For fixed precision, it must be in [0, 20]. precision = precision == null ? (type ? 6 : 12) : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision)) : Math.max(0, Math.min(20, precision)); function format(value) { var valuePrefix = prefix, valueSuffix = suffix, i, n, c; if (type === "c") { valueSuffix = formatType(value) + valueSuffix; value = ""; } else { value = +value; // Perform the initial formatting. var valueNegative = value < 0; value = formatType(Math.abs(value), precision); // If a negative value rounds to zero during formatting, treat as positive. if (valueNegative && +value === 0) valueNegative = false; // Compute the prefix and suffix. valuePrefix = (valueNegative ? (sign === "(" ? sign : "-") : sign === "-" || sign === "(" ? "" : sign) + valuePrefix; valueSuffix = valueSuffix + (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + (valueNegative && sign === "(" ? ")" : ""); // Break the formatted value into the integer “value” part that can be // grouped, and fractional or exponential “suffix” part that is not. if (maybeSuffix) { i = -1, n = value.length; while (++i < n) { if (c = value.charCodeAt(i), 48 > c || c > 57) { valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix; value = value.slice(0, i); break; } } } } // If the fill character is not "0", grouping is applied before padding. if (comma && !zero) value = group(value, Infinity); // Compute the padding. var length = valuePrefix.length + value.length + valueSuffix.length, padding = length < width ? new Array(width - length + 1).join(fill) : ""; // If the fill character is "0", grouping is applied after padding. if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = ""; // Reconstruct the final output based on the desired alignment. switch (align) { case "<": value = valuePrefix + value + valueSuffix + padding; break; case "=": value = valuePrefix + padding + value + valueSuffix; break; case "^": value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length); break; default: value = padding + valuePrefix + value + valueSuffix; break; } return numerals(value); } format.toString = function() { return specifier + ""; }; return format; } function formatPrefix(specifier, value) { var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)), e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3, k = Math.pow(10, -e), prefix = prefixes[8 + e / 3]; return function(value) { return f(k * value) + prefix; }; } return { format: newFormat, formatPrefix: formatPrefix }; }; var locale$2; var format; var formatPrefix; defaultLocale$1({ decimal: ".", thousands: ",", grouping: [3], currency: ["$", ""] }); function defaultLocale$1(definition) { locale$2 = formatLocale$1(definition); format = locale$2.format; formatPrefix = locale$2.formatPrefix; return locale$2; } var precisionFixed = function(step) { return Math.max(0, -exponent(Math.abs(step))); }; var precisionPrefix = function(step, value) { return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step))); }; var precisionRound = function(step, max) { step = Math.abs(step), max = Math.abs(max) - step; return Math.max(0, exponent(max) - exponent(step)) + 1; }; var tickFormat$1 = function(domain, count, specifier) { var start = domain[0], stop = domain[domain.length - 1], step = tickStep(start, stop, count == null ? 10 : count), precision; specifier = formatSpecifier(specifier == null ? ",f" : specifier); switch (specifier.type) { case "s": { var value = Math.max(Math.abs(start), Math.abs(stop)); if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision; return formatPrefix(specifier, value); } case "": case "e": case "g": case "p": case "r": { if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e"); break; } case "f": case "%": { if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2; break; } } return format(specifier); }; function linearish(scale) { var domain = scale.domain; scale.ticks = function(count) { var d = domain(); return ticks(d[0], d[d.length - 1], count == null ? 10 : count); }; scale.tickFormat = function(count, specifier) { return tickFormat$1(domain(), count, specifier); }; scale.nice = function(count) { if (count == null) count = 10; var d = domain(), i0 = 0, i1 = d.length - 1, start = d[i0], stop = d[i1], step; if (stop < start) { step = start, start = stop, stop = step; step = i0, i0 = i1, i1 = step; } step = tickIncrement(start, stop, count); if (step > 0) { start = Math.floor(start / step) * step; stop = Math.ceil(stop / step) * step; step = tickIncrement(start, stop, count); } else if (step < 0) { start = Math.ceil(start * step) / step; stop = Math.floor(stop * step) / step; step = tickIncrement(start, stop, count); } if (step > 0) { d[i0] = Math.floor(start / step) * step; d[i1] = Math.ceil(stop / step) * step; domain(d); } else if (step < 0) { d[i0] = Math.ceil(start * step) / step; d[i1] = Math.floor(stop * step) / step; domain(d); } return scale; }; return scale; } function linear() { var scale = continuous(deinterpolateLinear, reinterpolate); scale.copy = function() { return copy(scale, linear()); }; return linearish(scale); } function identity$3() { var domain = [0, 1]; function scale(x) { return +x; } scale.invert = scale; scale.domain = scale.range = function(_) { return arguments.length ? (domain = map$3.call(_, number$2), scale) : domain.slice(); }; scale.copy = function() { return identity$3().domain(domain); }; return linearish(scale); } var nice = function(domain, interval) { domain = domain.slice(); var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], t; if (x1 < x0) { t = i0, i0 = i1, i1 = t; t = x0, x0 = x1, x1 = t; } domain[i0] = interval.floor(x0); domain[i1] = interval.ceil(x1); return domain; }; function deinterpolate(a, b) { return (b = Math.log(b / a)) ? function(x) { return Math.log(x / a) / b; } : constant$5(b); } function reinterpolate$1(a, b) { return a < 0 ? function(t) { return -Math.pow(-b, t) * Math.pow(-a, 1 - t); } : function(t) { return Math.pow(b, t) * Math.pow(a, 1 - t); }; } function pow10(x) { return isFinite(x) ? +("1e" + x) : x < 0 ? 0 : x; } function powp(base) { return base === 10 ? pow10 : base === Math.E ? Math.exp : function(x) { return 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; }); } function reflect(f) { return function(x) { return -f(-x); }; } function log$1() { var scale = continuous(deinterpolate, reinterpolate$1).domain([1, 10]), domain = scale.domain, base = 10, logs = logp(10), pows = powp(10); function rescale() { logs = logp(base), pows = powp(base); if (domain()[0] < 0) logs = reflect(logs), pows = reflect(pows); return scale; } scale.base = function(_) { return arguments.length ? (base = +_, rescale()) : base; }; 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; if (r = v < u) i = u, u = v, v = i; var i = logs(u), j = logs(v), p, k, t, n = count == null ? 10 : +count, z = []; if (!(base % 1) && j - i < n) { i = Math.round(i) - 1, j = Math.round(j) + 1; if (u > 0) for (; i < j; ++i) { for (k = 1, p = pows(i); k < base; ++k) { t = p * k; 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; if (t < u) continue; if (t > v) break; z.push(t); } } } 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 = format(specifier); if (count === Infinity) return 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 (i * base < base - 0.5) i *= base; return i <= k ? specifier(d) : ""; }; }; scale.nice = function() { return domain(nice(domain(), { floor: function(x) { return pows(Math.floor(logs(x))); }, ceil: function(x) { return pows(Math.ceil(logs(x))); } })); }; scale.copy = function() { return copy(scale, log$1().base(base)); }; return scale; } function raise(x, exponent) { return x < 0 ? -Math.pow(-x, exponent) : Math.pow(x, exponent); } function pow() { var exponent = 1, scale = continuous(deinterpolate, reinterpolate), domain = scale.domain; function deinterpolate(a, b) { return (b = raise(b, exponent) - (a = raise(a, exponent))) ? function(x) { return (raise(x, exponent) - a) / b; } : constant$5(b); } function reinterpolate(a, b) { b = raise(b, exponent) - (a = raise(a, exponent)); return function(t) { return raise(a + b * t, 1 / exponent); }; } scale.exponent = function(_) { return arguments.length ? (exponent = +_, domain(domain())) : exponent; }; scale.copy = function() { return copy(scale, pow().exponent(exponent)); }; return linearish(scale); } function sqrt$1() { return pow().exponent(0.5); } function quantile() { var domain = [], range = [], thresholds = []; function rescale() { var i = 0, n = Math.max(1, range.length); thresholds = new Array(n - 1); while (++i < n) thresholds[i - 1] = threshold(domain, i / n); return scale; } function scale(x) { if (!isNaN(x = +x)) return range[bisectRight(thresholds, x)]; } scale.invertExtent = function(y) { var i = range.indexOf(y); return i < 0 ? [NaN, NaN] : [ i > 0 ? thresholds[i - 1] : domain[0], i < thresholds.length ? thresholds[i] : domain[domain.length - 1] ]; }; scale.domain = function(_) { if (!arguments.length) return domain.slice(); domain = []; for (var i = 0, n = _.length, d; i < n; ++i) if (d = _[i], d != null && !isNaN(d = +d)) domain.push(d); domain.sort(ascending); return rescale(); }; scale.range = function(_) { return arguments.length ? (range = slice$2.call(_), rescale()) : range.slice(); }; scale.quantiles = function() { return thresholds.slice(); }; scale.copy = function() { return quantile() .domain(domain) .range(range); }; return scale; } function quantize$1() { var x0 = 0, x1 = 1, n = 1, domain = [0.5], range = [0, 1]; function scale(x) { if (x <= x) return range[bisectRight(domain, x, 0, n)]; } function rescale() { var i = -1; domain = new Array(n); while (++i < n) domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1); return scale; } scale.domain = function(_) { return arguments.length ? (x0 = +_[0], x1 = +_[1], rescale()) : [x0, x1]; }; scale.range = function(_) { return arguments.length ? (n = (range = slice$2.call(_)).length - 1, rescale()) : range.slice(); }; scale.invertExtent = function(y) { var i = range.indexOf(y); return i < 0 ? [NaN, NaN] : i < 1 ? [x0, domain[0]] : i >= n ? [domain[n - 1], x1] : [domain[i - 1], domain[i]]; }; scale.copy = function() { return quantize$1() .domain([x0, x1]) .range(range); }; return linearish(scale); } function threshold$1() { var domain = [0.5], range = [0, 1], n = 1; function scale(x) { if (x <= x) return range[bisectRight(domain, x, 0, n)]; } scale.domain = function(_) { return arguments.length ? (domain = slice$2.call(_), n = Math.min(domain.length, range.length - 1), scale) : domain.slice(); }; scale.range = function(_) { return arguments.length ? (range = slice$2.call(_), n = Math.min(domain.length, range.length - 1), scale) : range.slice(); }; scale.invertExtent = function(y) { var i = range.indexOf(y); return [domain[i - 1], domain[i]]; }; scale.copy = function() { return threshold$1() .domain(domain) .range(range); }; return scale; } var durationSecond$1 = 1000; var durationMinute$1 = durationSecond$1 * 60; var durationHour$1 = durationMinute$1 * 60; var durationDay$1 = durationHour$1 * 24; var durationWeek$1 = durationDay$1 * 7; var durationMonth = durationDay$1 * 30; var durationYear = durationDay$1 * 365; function date$1(t) { return new Date(t); } function number$3(t) { return t instanceof Date ? +t : +new Date(+t); } function calendar(year$$1, month$$1, week, day$$1, hour$$1, minute$$1, second$$1, millisecond$$1, format) { var scale = continuous(deinterpolateLinear, reinterpolate), invert = scale.invert, domain = scale.domain; var formatMillisecond = format(".%L"), formatSecond = format(":%S"), formatMinute = format("%I:%M"), formatHour = format("%I %p"), formatDay = format("%a %d"), formatWeek = format("%b %d"), formatMonth = format("%B"), formatYear = format("%Y"); var tickIntervals = [ [second$$1, 1, durationSecond$1], [second$$1, 5, 5 * durationSecond$1], [second$$1, 15, 15 * durationSecond$1], [second$$1, 30, 30 * durationSecond$1], [minute$$1, 1, durationMinute$1], [minute$$1, 5, 5 * durationMinute$1], [minute$$1, 15, 15 * durationMinute$1], [minute$$1, 30, 30 * durationMinute$1], [ hour$$1, 1, durationHour$1 ], [ hour$$1, 3, 3 * durationHour$1 ], [ hour$$1, 6, 6 * durationHour$1 ], [ hour$$1, 12, 12 * durationHour$1 ], [ day$$1, 1, durationDay$1 ], [ day$$1, 2, 2 * durationDay$1 ], [ week, 1, durationWeek$1 ], [ month$$1, 1, durationMonth ], [ month$$1, 3, 3 * durationMonth ], [ year$$1, 1, durationYear ] ]; function tickFormat(date$$1) { return (second$$1(date$$1) < date$$1 ? formatMillisecond : minute$$1(date$$1) < date$$1 ? formatSecond : hour$$1(date$$1) < date$$1 ? formatMinute : day$$1(date$$1) < date$$1 ? formatHour : month$$1(date$$1) < date$$1 ? (week(date$$1) < date$$1 ? formatDay : formatWeek) : year$$1(date$$1) < date$$1 ? formatMonth : formatYear)(date$$1); } function tickInterval(interval, start, stop, step) { if (interval == null) interval = 10; // If a desired tick count is specified, pick a reasonable tick interval // based on the extent of the domain and a rough estimate of tick size. // Otherwise, assume interval is already a time interval and use it. if (typeof interval === "number") { var target = Math.abs(stop - start) / interval, i = bisector(function(i) { return i[2]; }).right(tickIntervals, target); if (i === tickIntervals.length) { step = tickStep(start / durationYear, stop / durationYear, interval); interval = year$$1; } else if (i) { i = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i]; step = i[1]; interval = i[0]; } else { step = tickStep(start, stop, interval); interval = millisecond$$1; } } return step == null ? interval : interval.every(step); } scale.invert = function(y) { return new Date(invert(y)); }; scale.domain = function(_) { return arguments.length ? domain(map$3.call(_, number$3)) : domain().map(date$1); }; scale.ticks = function(interval, step) { var d = domain(), t0 = d[0], t1 = d[d.length - 1], r = t1 < t0, t; if (r) t = t0, t0 = t1, t1 = t; t = tickInterval(interval, t0, t1, step); t = t ? t.range(t0, t1 + 1) : []; // inclusive stop return r ? t.reverse() : t; }; scale.tickFormat = function(count, specifier) { return specifier == null ? tickFormat : format(specifier); }; scale.nice = function(interval, step) { var d = domain(); return (interval = tickInterval(interval, d[0], d[d.length - 1], step)) ? domain(nice(d, interval)) : scale; }; scale.copy = function() { return copy(scale, calendar(year$$1, month$$1, week, day$$1, hour$$1, minute$$1, second$$1, millisecond$$1, format)); }; return scale; } var time = function() { return calendar(year, month, sunday, day, hour, minute, second, millisecond, timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]); }; var utcTime = function() { return calendar(utcYear, utcMonth, utcSunday, utcDay, utcHour, utcMinute, second, millisecond, utcFormat).domain([Date.UTC(2000, 0, 1), Date.UTC(2000, 0, 2)]); }; var colors = function(s) { return s.match(/.{6}/g).map(function(x) { return "#" + x; }); }; var category10 = colors("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf"); var category20b = colors("393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6"); var category20c = colors("3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9"); var category20 = colors("1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5"); cubehelixLong(cubehelix(300, 0.5, 0.0), cubehelix(-240, 0.5, 1.0)); var warm = cubehelixLong(cubehelix(-100, 0.75, 0.35), cubehelix(80, 1.50, 0.8)); var cool = cubehelixLong(cubehelix(260, 0.75, 0.35), cubehelix(80, 1.50, 0.8)); var rainbow = cubehelix(); function ramp(range) { var n = range.length; return function(t) { return range[Math.max(0, Math.min(n - 1, Math.floor(t * n)))]; }; } var viridis = ramp(colors("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")); var magma = ramp(colors("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")); var inferno = ramp(colors("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")); var plasma = ramp(colors("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921")); function band$$1() { var scale = ordinal().unknown(undefined), domain = scale.domain, ordinalRange = scale.range, range = [0, 1], step, bandwidth, round = false, paddingInner = 0, paddingOuter = 0, align = 0.5; delete scale.unknown; function rescale() { var n = domain().length, reverse = range[1] < range[0], start = range[reverse - 0], stop = range[1 - reverse], space = bandSpace(n, paddingInner, paddingOuter); step = (stop - start) / (space || 1); 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; }); return ordinalRange(reverse ? values.reverse() : values); } scale.domain = function(_) { if (arguments.length) { domain(_); return rescale(); } else { return domain(); } }; scale.range = function(_) { if (arguments.length) { range = [+_[0], +_[1]]; return rescale(); } else { return range.slice(); } }; scale.rangeRound = function(_) { range = [+_[0], +_[1]]; round = true; return rescale(); }; scale.bandwidth = function() { return bandwidth; }; scale.step = function() { return step; }; scale.round = function(_) { if (arguments.length) { round = !!_; return rescale(); } else { return round; } }; scale.padding = function(_) { if (arguments.length) { paddingOuter = Math.max(0, Math.min(1, _)); paddingInner = paddingOuter; return rescale(); } else { return paddingInner; } }; scale.paddingInner = function(_) { if (arguments.length) { paddingInner = Math.max(0, Math.min(1, _)); return rescale(); } else { return paddingInner; } }; scale.paddingOuter = function(_) { if (arguments.length) { paddingOuter = Math.max(0, Math.min(1, _)); return rescale(); } else { return paddingOuter; } }; scale.align = function(_) { if (arguments.length) { align = Math.max(0, Math.min(1, _)); return rescale(); } else { return align; } }; scale.invertRange = function(_) { // bail if range has null or undefined values if (_[0] == null || _[1] == null) return; var lo = +_[0], hi = +_[1], reverse = range[1] < range[0], values = reverse ? ordinalRange().reverse() : ordinalRange(), n = values.length - 1, a, b, t; // bail if either range endpoint is invalid if (lo !== lo || hi !== hi) return; // order range inputs, bail if outside of scale range if (hi < lo) { t = lo; lo = hi; hi = t; } if (hi < values[0] || lo > range[1-reverse]) return; // binary search to index into scale range a = Math.max(0, bisectRight(values, lo) - 1); b = lo===hi ? a : bisectRight(values, hi) - 1; // increment index a if lo is within padding gap if (lo - values[a] > bandwidth + 1e-10) ++a; if (reverse) { // map + swap t = a; a = n - b; b = n - t; } return (a > b) ? undefined : domain().slice(a, b+1); }; scale.invert = function(_) { var value = scale.invertRange([_, _]); return value ? value[0] : value; }; scale.copy = function() { return band$$1() .domain(domain()) .range(range) .round(round) .paddingInner(paddingInner) .paddingOuter(paddingOuter) .align(align); }; return rescale(); } function pointish(scale) { var copy = scale.copy; scale.padding = scale.paddingOuter; delete scale.paddingInner; scale.copy = function() { return pointish(copy()); }; return scale; } function point$5() { return pointish(band$$1().paddingInner(1)); } var map$4 = Array.prototype.map; var slice$3 = Array.prototype.slice; function numbers$1(_) { return map$4.call(_, function(x) { return +x; }); } function binLinear() { var linear$$1 = linear(), domain = []; function scale(x) { return linear$$1(x); } function setDomain(_) { domain = numbers$1(_); linear$$1.domain([domain[0], peek(domain)]); } scale.domain = function(_) { return arguments.length ? (setDomain(_), scale) : domain.slice(); }; scale.range = function(_) { return arguments.length ? (linear$$1.range(_), scale) : linear$$1.range(); }; scale.rangeRound = function(_) { return arguments.length ? (linear$$1.rangeRound(_), scale) : linear$$1.rangeRound(); }; scale.interpolate = function(_) { return arguments.length ? (linear$$1.interpolate(_), scale) : linear$$1.interpolate(); }; scale.invert = function(_) { return linear$$1.invert(_); }; scale.ticks = function(count) { var n = domain.length, stride = ~~(n / (count || n)); return stride < 2 ? scale.domain() : domain.filter(function(x, i) { return !(i % stride); }); }; scale.tickFormat = function() { return linear$$1.tickFormat.apply(linear$$1, arguments); }; scale.copy = function() { return binLinear().domain(scale.domain()).range(scale.range()); }; return scale; } function binOrdinal() { var domain = [], range = []; function scale(x) { return x == null || x !== x ? undefined : range[(bisectRight(domain, x) - 1) % range.length]; } scale.domain = function(_) { if (arguments.length) { domain = numbers$1(_); return scale; } else { return domain.slice(); } }; scale.range = function(_) { if (arguments.length) { range = slice$3.call(_); return scale; } else { return range.slice(); } }; scale.copy = function() { return binOrdinal().domain(scale.domain()).range(scale.range()); }; return scale; } function sequential$1(interpolator) { var linear$$1 = linear(), x0 = 0, dx = 1, clamp = false; function update() { var domain = linear$$1.domain(); x0 = domain[0]; dx = peek(domain) - x0; } function scale(x) { var t = (x - x0) / dx; return interpolator(clamp ? Math.max(0, Math.min(1, t)) : t); } scale.clamp = function(_) { if (arguments.length) { clamp = !!_; return scale; } else { return clamp; } }; scale.domain = function(_) { return arguments.length ? (linear$$1.domain(_), update(), scale) : linear$$1.domain(); }; scale.interpolator = function(_) { if (arguments.length) { interpolator = _; return scale; } else { return interpolator; } }; scale.copy = function() { return sequential$1().domain(linear$$1.domain()).clamp(clamp).interpolator(interpolator); }; scale.ticks = function(count) { return linear$$1.ticks(count); }; scale.tickFormat = function(count, specifier) { return linear$$1.tickFormat(count, specifier); }; scale.nice = function(count) { return linear$$1.nice(count), update(), scale; }; return scale; } /** * Augment scales with their type and needed inverse methods. */ function create(type, constructor) { return function scale() { var s = constructor(); if (!s.invertRange) { s.invertRange = s.invert ? invertRange(s) : s.invertExtent ? invertRangeExtent(s) : undefined; } s.type = type; return s; }; } function scale$1(type, scale) { if (arguments.length > 1) { scales[type] = create(type, scale); return this; } else { return scales.hasOwnProperty(type) ? scales[type] : undefined; } } var scales = { // base scale types identity: identity$3, linear: linear, log: log$1, ordinal: ordinal, pow: pow, sqrt: sqrt$1, quantile: quantile, quantize: quantize$1, threshold: threshold$1, time: time, utc: utcTime, // extended scale types band: band$$1, point: point$5, sequential: sequential$1, 'bin-linear': binLinear, 'bin-ordinal': binOrdinal }; for (var key$1 in scales) { scale$1(key$1, scales[key$1]); } function colors$1(specifier) { var n = specifier.length / 6 | 0, colors = new Array(n), i = 0; while (i < n) colors[i] = "#" + specifier.slice(i * 6, ++i * 6); return colors; } var tableau10 = colors$1( '4c78a8f58518e4575672b7b254a24beeca3bb279a2ff9da69d755dbab0ac' ); var tableau20 = colors$1( '4c78a89ecae9f58518ffbf7954a24b88d27ab79a20f2cf5b43989483bcb6e45756ff9d9879706ebab0acd67195fcbfd2b279a2d6a5c99e765fd8b5a5' ); var blueOrange = new Array(3).concat( "67a9cff7f7f7f1a340", "0571b092c5defdb863e66101", "0571b092c5def7f7f7fdb863e66101", "2166ac67a9cfd1e5f0fee0b6f1a340b35806", "2166ac67a9cfd1e5f0f7f7f7fee0b6f1a340b35806", "2166ac4393c392c5ded1e5f0fee0b6fdb863e08214b35806", "2166ac4393c392c5ded1e5f0f7f7f7fee0b6fdb863e08214b35806", "0530612166ac4393c392c5ded1e5f0fee0b6fdb863e08214b358067f3b08", "0530612166ac4393c392c5ded1e5f0f7f7f7fee0b6fdb863e08214b358067f3b08" ).map(colors$1); var colors$2 = function(specifier) { var n = specifier.length / 6 | 0, colors = new Array(n), i = 0; while (i < n) colors[i] = "#" + specifier.slice(i * 6, ++i * 6); return colors; }; var Accent = colors$2("7fc97fbeaed4fdc086ffff99386cb0f0027fbf5b17666666"); var Dark2 = colors$2("1b9e77d95f027570b3e7298a66a61ee6ab02a6761d666666"); var Paired = colors$2("a6cee31f78b4b2df8a33a02cfb9a99e31a1cfdbf6fff7f00cab2d66a3d9affff99b15928"); var Pastel1 = colors$2("fbb4aeb3cde3ccebc5decbe4fed9a6ffffcce5d8bdfddaecf2f2f2"); var Pastel2 = colors$2("b3e2cdfdcdaccbd5e8f4cae4e6f5c9fff2aef1e2cccccccc"); var Set1 = colors$2("e41a1c377eb84daf4a984ea3ff7f00ffff33a65628f781bf999999"); var Set2 = colors$2("66c2a5fc8d628da0cbe78ac3a6d854ffd92fe5c494b3b3b3"); var Set3 = colors$2("8dd3c7ffffb3bebadafb807280b1d3fdb462b3de69fccde5d9d9d9bc80bdccebc5ffed6f"); var ramp$1 = function(scheme) { return rgbBasis(scheme[scheme.length - 1]); }; var scheme = new Array(3).concat( "d8b365f5f5f55ab4ac", "a6611adfc27d80cdc1018571", "a6611adfc27df5f5f580cdc1018571", "8c510ad8b365f6e8c3c7eae55ab4ac01665e", "8c510ad8b365f6e8c3f5f5f5c7eae55ab4ac01665e", "8c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e", "8c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e", "5430058c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e003c30", "5430058c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e003c30" ).map(colors$2); var BrBG = ramp$1(scheme); var scheme$1 = new Array(3).concat( "af8dc3f7f7f77fbf7b", "7b3294c2a5cfa6dba0008837", "7b3294c2a5cff7f7f7a6dba0008837", "762a83af8dc3e7d4e8d9f0d37fbf7b1b7837", "762a83af8dc3e7d4e8f7f7f7d9f0d37fbf7b1b7837", "762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b7837", "762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b7837", "40004b762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b783700441b", "40004b762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b783700441b" ).map(colors$2); var PRGn = ramp$1(scheme$1); var scheme$2 = new Array(3).concat( "e9a3c9f7f7f7a1d76a", "d01c8bf1b6dab8e1864dac26", "d01c8bf1b6daf7f7f7b8e1864dac26", "c51b7de9a3c9fde0efe6f5d0a1d76a4d9221", "c51b7de9a3c9fde0eff7f7f7e6f5d0a1d76a4d9221", "c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221", "c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221", "8e0152c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221276419", "8e0152c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221276419" ).map(colors$2); var PiYG = ramp$1(scheme$2); var scheme$3 = new Array(3).concat( "998ec3f7f7f7f1a340", "5e3c99b2abd2fdb863e66101", "5e3c99b2abd2f7f7f7fdb863e66101", "542788998ec3d8daebfee0b6f1a340b35806", "542788998ec3d8daebf7f7f7fee0b6f1a340b35806", "5427888073acb2abd2d8daebfee0b6fdb863e08214b35806", "5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b35806", "2d004b5427888073acb2abd2d8daebfee0b6fdb863e08214b358067f3b08", "2d004b5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b358067f3b08" ).map(colors$2); var PuOr = ramp$1(scheme$3); var scheme$4 = new Array(3).concat( "ef8a62f7f7f767a9cf", "ca0020f4a58292c5de0571b0", "ca0020f4a582f7f7f792c5de0571b0", "b2182bef8a62fddbc7d1e5f067a9cf2166ac", "b2182bef8a62fddbc7f7f7f7d1e5f067a9cf2166ac", "b2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac", "b2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac", "67001fb2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac053061", "67001fb2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac053061" ).map(colors$2); var RdBu = ramp$1(scheme$4); var scheme$5 = new Array(3).concat( "ef8a62ffffff999999", "ca0020f4a582bababa404040", "ca0020f4a582ffffffbababa404040", "b2182bef8a62fddbc7e0e0e09999994d4d4d", "b2182bef8a62fddbc7ffffffe0e0e09999994d4d4d", "b2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d", "b2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d", "67001fb2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d1a1a1a", "67001fb2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d1a1a1a" ).map(colors$2); var RdGy = ramp$1(scheme$5); var scheme$6 = new Array(3).concat( "fc8d59ffffbf91bfdb", "d7191cfdae61abd9e92c7bb6", "d7191cfdae61ffffbfabd9e92c7bb6", "d73027fc8d59fee090e0f3f891bfdb4575b4", "d73027fc8d59fee090ffffbfe0f3f891bfdb4575b4", "d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4", "d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4", "a50026d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4313695", "a50026d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4313695" ).map(colors$2); var RdYlBu = ramp$1(scheme$6); var scheme$7 = new Array(3).concat( "fc8d59ffffbf91cf60", "d7191cfdae61a6d96a1a9641", "d7191cfdae61ffffbfa6d96a1a9641", "d73027fc8d59fee08bd9ef8b91cf601a9850", "d73027fc8d59fee08bffffbfd9ef8b91cf601a9850", "d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850", "d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850", "a50026d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850006837", "a50026d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850006837" ).map(colors$2); var RdYlGn = ramp$1(scheme$7); var scheme$8 = new Array(3).concat( "fc8d59ffffbf99d594", "d7191cfdae61abdda42b83ba", "d7191cfdae61ffffbfabdda42b83ba", "d53e4ffc8d59fee08be6f59899d5943288bd", "d53e4ffc8d59fee08bffffbfe6f59899d5943288bd", "d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd", "d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd", "9e0142d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd5e4fa2", "9e0142d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd5e4fa2" ).map(colors$2); var Spectral = ramp$1(scheme$8); var scheme$9 = new Array(3).concat( "e5f5f999d8c92ca25f", "edf8fbb2e2e266c2a4238b45", "edf8fbb2e2e266c2a42ca25f006d2c", "edf8fbccece699d8c966c2a42ca25f006d2c", "edf8fbccece699d8c966c2a441ae76238b45005824", "f7fcfde5f5f9ccece699d8c966c2a441ae76238b45005824", "f7fcfde5f5f9ccece699d8c966c2a441ae76238b45006d2c00441b" ).map(colors$2); var BuGn = ramp$1(scheme$9); var scheme$10 = new Array(3).concat( "e0ecf49ebcda8856a7", "edf8fbb3cde38c96c688419d", "edf8fbb3cde38c96c68856a7810f7c", "edf8fbbfd3e69ebcda8c96c68856a7810f7c", "edf8fbbfd3e69ebcda8c96c68c6bb188419d6e016b", "f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d6e016b", "f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d810f7c4d004b" ).map(colors$2); var BuPu = ramp$1(scheme$10); var scheme$11 = new Array(3).concat( "e0f3dba8ddb543a2ca", "f0f9e8bae4bc7bccc42b8cbe", "f0f9e8bae4bc7bccc443a2ca0868ac", "f0f9e8ccebc5a8ddb57bccc443a2ca0868ac", "f0f9e8ccebc5a8ddb57bccc44eb3d32b8cbe08589e", "f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe08589e", "f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe0868ac084081" ).map(colors$2); var GnBu = ramp$1(scheme$11); var scheme$12 = new Array(3).concat( "fee8c8fdbb84e34a33", "fef0d9fdcc8afc8d59d7301f", "fef0d9fdcc8afc8d59e34a33b30000", "fef0d9fdd49efdbb84fc8d59e34a33b30000", "fef0d9fdd49efdbb84fc8d59ef6548d7301f990000", "fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301f990000", "fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301fb300007f0000" ).map(colors$2); var OrRd = ramp$1(scheme$12); var scheme$13 = new Array(3).concat( "ece2f0a6bddb1c9099", "f6eff7bdc9e167a9cf02818a", "f6eff7bdc9e167a9cf1c9099016c59", "f6eff7d0d1e6a6bddb67a9cf1c9099016c59", "f6eff7d0d1e6a6bddb67a9cf3690c002818a016450", "fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016450", "fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016c59014636" ).map(colors$2); var PuBuGn = ramp$1(scheme$13); var scheme$14 = new Array(3).concat( "ece7f2a6bddb2b8cbe", "f1eef6bdc9e174a9cf0570b0", "f1eef6bdc9e174a9cf2b8cbe045a8d", "f1eef6d0d1e6a6bddb74a9cf2b8cbe045a8d", "f1eef6d0d1e6a6bddb74a9cf3690c00570b0034e7b", "fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0034e7b", "fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0045a8d023858" ).map(colors$2); var PuBu = ramp$1(scheme$14); var scheme$15 = new Array(3).concat( "e7e1efc994c7dd1c77", "f1eef6d7b5d8df65b0ce1256", "f1eef6d7b5d8df65b0dd1c77980043", "f1eef6d4b9dac994c7df65b0dd1c77980043", "f1eef6d4b9dac994c7df65b0e7298ace125691003f", "f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125691003f", "f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125698004367001f" ).map(colors$2); var PuRd = ramp$1(scheme$15); var scheme$16 = new Array(3).concat( "fde0ddfa9fb5c51b8a", "feebe2fbb4b9f768a1ae017e", "feebe2fbb4b9f768a1c51b8a7a0177", "feebe2fcc5c0fa9fb5f768a1c51b8a7a0177", "feebe2fcc5c0fa9fb5f768a1dd3497ae017e7a0177", "fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a0177", "fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a017749006a" ).map(colors$2); var RdPu = ramp$1(scheme$16); var scheme$17 = new Array(3).concat( "edf8b17fcdbb2c7fb8", "ffffcca1dab441b6c4225ea8", "ffffcca1dab441b6c42c7fb8253494", "ffffccc7e9b47fcdbb41b6c42c7fb8253494", "ffffccc7e9b47fcdbb41b6c41d91c0225ea80c2c84", "ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea80c2c84", "ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea8253494081d58" ).map(colors$2); var YlGnBu = ramp$1(scheme$17); var scheme$18 = new Array(3).concat( "f7fcb9addd8e31a354", "ffffccc2e69978c679238443", "ffffccc2e69978c67931a354006837", "ffffccd9f0a3addd8e78c67931a354006837", "ffffccd9f0a3addd8e78c67941ab5d238443005a32", "ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443005a32", "ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443006837004529" ).map(colors$2); var YlGn = ramp$1(scheme$18); var scheme$19 = new Array(3).concat( "fff7bcfec44fd95f0e", "ffffd4fed98efe9929cc4c02", "ffffd4fed98efe9929d95f0e993404", "ffffd4fee391fec44ffe9929d95f0e993404", "ffffd4fee391fec44ffe9929ec7014cc4c028c2d04", "ffffe5fff7bcfee391fec44ffe9929ec7014cc4c028c2d04", "ffffe5fff7bcfee391fec44ffe9929ec7014cc4c02993404662506" ).map(colors$2); var YlOrBr = ramp$1(scheme$19); var scheme$20 = new Array(3).concat( "ffeda0feb24cf03b20", "ffffb2fecc5cfd8d3ce31a1c", "ffffb2fecc5cfd8d3cf03b20bd0026", "ffffb2fed976feb24cfd8d3cf03b20bd0026", "ffffb2fed976feb24cfd8d3cfc4e2ae31a1cb10026", "ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cb10026", "ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cbd0026800026" ).map(colors$2); var YlOrRd = ramp$1(scheme$20); var scheme$21 = new Array(3).concat( "deebf79ecae13182bd", "eff3ffbdd7e76baed62171b5", "eff3ffbdd7e76baed63182bd08519c", "eff3ffc6dbef9ecae16baed63182bd08519c", "eff3ffc6dbef9ecae16baed64292c62171b5084594", "f7fbffdeebf7c6dbef9ecae16baed64292c62171b5084594", "f7fbffdeebf7c6dbef9ecae16baed64292c62171b508519c08306b" ).map(colors$2); var Blues = ramp$1(scheme$21); var scheme$22 = new Array(3).concat( "e5f5e0a1d99b31a354", "edf8e9bae4b374c476238b45", "edf8e9bae4b374c47631a354006d2c", "edf8e9c7e9c0a1d99b74c47631a354006d2c", "edf8e9c7e9c0a1d99b74c47641ab5d238b45005a32", "f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45005a32", "f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45006d2c00441b" ).map(colors$2); var Greens = ramp$1(scheme$22); var scheme$23 = new Array(3).concat( "f0f0f0bdbdbd636363", "f7f7f7cccccc969696525252", "f7f7f7cccccc969696636363252525", "f7f7f7d9d9d9bdbdbd969696636363252525", "f7f7f7d9d9d9bdbdbd969696737373525252252525", "fffffff0f0f0d9d9d9bdbdbd969696737373525252252525", "fffffff0f0f0d9d9d9bdbdbd969696737373525252252525000000" ).map(colors$2); var Greys = ramp$1(scheme$23); var scheme$24 = new Array(3).concat( "efedf5bcbddc756bb1", "f2f0f7cbc9e29e9ac86a51a3", "f2f0f7cbc9e29e9ac8756bb154278f", "f2f0f7dadaebbcbddc9e9ac8756bb154278f", "f2f0f7dadaebbcbddc9e9ac8807dba6a51a34a1486", "fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a34a1486", "fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a354278f3f007d" ).map(colors$2); var Purples = ramp$1(scheme$24); var scheme$25 = new Array(3).concat( "fee0d2fc9272de2d26", "fee5d9fcae91fb6a4acb181d", "fee5d9fcae91fb6a4ade2d26a50f15", "fee5d9fcbba1fc9272fb6a4ade2d26a50f15", "fee5d9fcbba1fc9272fb6a4aef3b2ccb181d99000d", "fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181d99000d", "fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181da50f1567000d" ).map(colors$2); var Reds = ramp$1(scheme$25); var scheme$26 = new Array(3).concat( "fee6cefdae6be6550d", "feeddefdbe85fd8d3cd94701", "feeddefdbe85fd8d3ce6550da63603", "feeddefdd0a2fdae6bfd8d3ce6550da63603", "feeddefdd0a2fdae6bfd8d3cf16913d948018c2d04", "fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d948018c2d04", "fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d94801a636037f2704" ).map(colors$2); var Oranges = ramp$1(scheme$26); var _ = Object.freeze({ schemeAccent: Accent, schemeDark2: Dark2, schemePaired: Paired, schemePastel1: Pastel1, schemePastel2: Pastel2, schemeSet1: Set1, schemeSet2: Set2, schemeSet3: Set3, interpolateBrBG: BrBG, schemeBrBG: scheme, interpolatePRGn: PRGn, schemePRGn: scheme$1, interpolatePiYG: PiYG, schemePiYG: scheme$2, interpolatePuOr: PuOr, schemePuOr: scheme$3, interpolateRdBu: RdBu, schemeRdBu: scheme$4, interpolateRdGy: RdGy, schemeRdGy: scheme$5, interpolateRdYlBu: RdYlBu, schemeRdYlBu: scheme$6, interpolateRdYlGn: RdYlGn, schemeRdYlGn: scheme$7, interpolateSpectral: Spectral, schemeSpectral: scheme$8, interpolateBuGn: BuGn, schemeBuGn: scheme$9, interpolateBuPu: BuPu, schemeBuPu: scheme$10, interpolateGnBu: GnBu, schemeGnBu: scheme$11, interpolateOrRd: OrRd, schemeOrRd: scheme$12, interpolatePuBuGn: PuBuGn, schemePuBuGn: scheme$13, interpolatePuBu: PuBu, schemePuBu: scheme$14, interpolatePuRd: PuRd, schemePuRd: scheme$15, interpolateRdPu: RdPu, schemeRdPu: scheme$16, interpolateYlGnBu: YlGnBu, schemeYlGnBu: scheme$17, interpolateYlGn: YlGn, schemeYlGn: scheme$18, interpolateYlOrBr: YlOrBr, schemeYlOrBr: scheme$19, interpolateYlOrRd: YlOrRd, schemeYlOrRd: scheme$20, interpolateBlues: Blues, schemeBlues: scheme$21, interpolateGreens: Greens, schemeGreens: scheme$22, interpolateGreys: Greys, schemeGreys: scheme$23, interpolatePurples: Purples, schemePurples: scheme$24, interpolateReds: Reds, schemeReds: scheme$25, interpolateOranges: Oranges, schemeOranges: scheme$26 }); var discrete = { blueorange: blueOrange }; var schemes = { // d3 built-in categorical palettes category10: category10, category20: category20, category20b: category20b, category20c: category20c, // extended categorical palettes accent: Accent, dark2: Dark2, paired: Paired, pastel1: Pastel1, pastel2: Pastel2, set1: Set1, set2: Set2, set3: Set3, tableau10: tableau10, tableau20: tableau20, // d3 built-in interpolators viridis: viridis, magma: magma, inferno: inferno, plasma: plasma, // extended interpolators blueorange: rgbBasis(peek(blueOrange)) }; function add$2(name, suffix) { schemes[name] = _['interpolate' + suffix]; discrete[name] = _['scheme' + suffix]; } // sequential single-hue add$2('blues', 'Blues'); add$2('greens', 'Greens'); add$2('greys', 'Greys'); add$2('purples', 'Purples'); add$2('reds', 'Reds'); add$2('oranges', 'Oranges'); // diverging add$2('brownbluegreen', 'BrBG'); add$2('purplegreen', 'PRGn'); add$2('pinkyellowgreen', 'PiYG'); add$2('purpleorange', 'PuOr'); add$2('redblue', 'RdBu'); add$2('redgrey', 'RdGy'); add$2('redyellowblue', 'RdYlBu'); add$2('redyellowgreen', 'RdYlGn'); add$2('spectral', 'Spectral'); // sequential multi-hue add$2('bluegreen', 'BuGn'); add$2('bluepurple', 'BuPu'); add$2('greenblue', 'GnBu'); add$2('orangered', 'OrRd'); add$2('purplebluegreen', 'PuBuGn'); add$2('purpleblue', 'PuBu'); add$2('purplered', 'PuRd'); add$2('redpurple', 'RdPu'); add$2('yellowgreenblue', 'YlGnBu'); add$2('yellowgreen', 'YlGn'); add$2('yelloworangebrown', 'YlOrBr'); add$2('yelloworangered', 'YlOrRd'); var getScheme = function(name, scheme$$1) { if (arguments.length > 1) { schemes[name] = scheme$$1; return this; } var part = name.split('-'); name = part[0]; part = +part[1] + 1; return part && discrete.hasOwnProperty(name) ? discrete[name][part-1] : !part && schemes.hasOwnProperty(name) ? schemes[name] : undefined; }; function interpolateRange(interpolator, range) { var start = range[0], span = peek(range) - start; return function(i) { return interpolator(start + i * span); }; } function scaleFraction(scale, min, max) { var delta = max - min; return !delta ? constant(0) : scale.type === 'linear' || scale.type === 'sequential' ? function(_) { return (_ - min) / delta; } : scale.copy().domain([min, max]).range([0, 1]).interpolate(lerp); } function lerp(a, b) { var span = b - a; return function(i) { return a + i * span; } } function interpolate$1(type, gamma) { var interp = $$1[method(type)]; return (gamma != null && interp && interp.gamma) ? interp.gamma(gamma) : interp; } function method(type) { return 'interpolate' + type.toLowerCase() .split('-') .map(function(s) { return s[0].toUpperCase() + s.slice(1); }) .join(''); } var time$1 = { millisecond: millisecond, second: second, minute: minute, hour: hour, day: day, week: sunday, month: month, year: year }; var utc = { millisecond: millisecond, second: second, minute: utcMinute, hour: utcHour, day: utcDay, week: utcSunday, month: utcMonth, year: utcYear }; function timeInterval(name) { return time$1.hasOwnProperty(name) && time$1[name]; } function utcInterval(name) { return utc.hasOwnProperty(name) && utc[name]; } /** * Determine the tick count or interval function. * @param {Scale} scale - The scale for which to generate tick values. * @param {*} count - The desired tick count or interval specifier. * @return {*} - The tick count or interval function. */ function tickCount(scale$$1, count) { var step; if (isObject(count)) { step = count.step; count = count.interval; } if (isString(count)) { count = scale$$1.type === 'time' ? timeInterval(count) : scale$$1.type === 'utc' ? utcInterval(count) : error$1('Only time and utc scales accept interval strings.'); if (step) count = count.every(step); } return count; } /** * Filter a set of candidate tick values, ensuring that only tick values * that lie within the scale range are included. * @param {Scale} scale - The scale for which to generate tick values. * @param {Array<*>} ticks - The candidate tick values. * @return {Array<*>} - The filtered tick values. */ function validTicks(scale$$1, ticks) { var range = scale$$1.range(), lo = range[0], hi = peek(range); if (lo > hi) { range = hi; hi = lo; lo = range; } return ticks.filter(function(v) { v = scale$$1(v); return !(v < lo || v > hi) }); } /** * Generate tick values for the given scale and approximate tick count or * interval value. If the scale has a 'ticks' method, it will be used to * generate the ticks, with the count argument passed as a parameter. If the * scale lacks a 'ticks' method, the full scale domain will be returned. * @param {Scale} scale - The scale for which to generate tick values. * @param {*} [count] - The approximate number of desired ticks. * @return {Array<*>} - The generated tick values. */ function tickValues(scale$$1, count) { return scale$$1.ticks ? scale$$1.ticks(count) : scale$$1.domain(); } /** * Generate a label format function for a scale. If the scale has a * 'tickFormat' method, it will be used to generate the formatter, with the * count and specifier arguments passed as parameters. If the scale lacks a * 'tickFormat' method, the returned formatter performs simple string coercion. * If the input scale is a logarithmic scale and the format specifier does not * indicate a desired decimal precision, a special variable precision formatter * that automatically trims trailing zeroes will be generated. * @param {Scale} scale - The scale for which to generate the label formatter. * @param {*} [count] - The approximate number of desired ticks. * @param {string} [specifier] - The format specifier. Must be a legal d3 4.0 * specifier string (see https://github.com/d3/d3-format#formatSpecifier). * @return {function(*):string} - The generated label formatter. */ function tickFormat(scale$$1, count, specifier) { var format$$1 = scale$$1.tickFormat ? scale$$1.tickFormat(count, specifier) : String; return (scale$$1.type === Log) ? filter$1(format$$1, variablePrecision(specifier)) : format$$1; } function filter$1(sourceFormat, targetFormat) { return function(_) { return sourceFormat(_) ? targetFormat(_) : ''; }; } function variablePrecision(specifier) { var s = formatSpecifier(specifier || ','); if (s.precision == null) { s.precision = 12; switch (s.type) { case '%': s.precision -= 2; break; case 'e': s.precision -= 1; break; } return trimZeroes( format(s), // number format format('.1f')(1)[1] // decimal point character ); } else { return format(s); } } function trimZeroes(format$$1, decimalChar) { return function(x) { var str = format$$1(x), dec = str.indexOf(decimalChar), idx, end; if (dec < 0) return str; idx = rightmostDigit(str, dec); end = idx < str.length ? str.slice(idx) : ''; while (--idx > dec) if (str[idx] !== '0') { ++idx; break; } return str.slice(0, idx) + end; }; } function rightmostDigit(str, dec) { var i = str.lastIndexOf('e'), c; if (i > 0) return i; for (i=str.length; --i > dec;) { c = str.charCodeAt(i); if (c >= 48 && c <= 57) return i + 1; // is digit } } /** * Generates axis ticks for visualizing a spatial scale. * @constructor * @param {object} params - The parameters for this operator. * @param {Scale} params.scale - The scale to generate ticks for. * @param {*} [params.count=10] - The approximate number of ticks, or * desired tick interval, to use. * @param {Array<*>} [params.values] - The exact tick values to use. * These must be legal domain values for the provided scale. * If provided, the count argument is ignored. * @param {function(*):string} [params.formatSpecifier] - A format specifier * to use in conjunction with scale.tickFormat. Legal values are * any valid d3 4.0 format specifier. * @param {function(*):string} [params.format] - The format function to use. * If provided, the formatSpecifier argument is ignored. */ function AxisTicks(params) { Transform.call(this, null, params); } var prototype$51 = inherits(AxisTicks, Transform); prototype$51.transform = function(_, pulse) { if (this.value && !_.modified()) { return pulse.StopPropagation; } var out = pulse.fork(pulse.NO_SOURCE | pulse.NO_FIELDS), ticks = this.value, scale = _.scale, count = _.values ? _.values.length : tickCount(scale, _.count), format = _.format || tickFormat(scale, count, _.formatSpecifier), values = _.values ? validTicks(scale, _.values) : tickValues(scale, count); if (ticks) out.rem = ticks; ticks = values.map(function(value) { return ingest({value: value, label: format(value)}) }); if (_.extra) { // add an extra tick pegged to the initial domain value // this is used to generate axes with 'binned' domains ticks.push(ingest({ extra: {value: ticks[0].value}, label: '' })); } out.source = ticks; out.add = ticks; this.value = ticks; return out; }; /** * Joins a set of data elements against a set of visual items. * @constructor * @param {object} params - The parameters for this operator. * @param {function(object): object} [params.item] - An item generator function. * @param {function(object): *} [params.key] - The key field associating data and visual items. */ function DataJoin(params) { Transform.call(this, null, params); } var prototype$52 = inherits(DataJoin, Transform); function defaultItemCreate() { return ingest({}); } function isExit(t) { return t.exit; } prototype$52.transform = function(_, pulse) { var df = pulse.dataflow, out = pulse.fork(pulse.NO_SOURCE | pulse.NO_FIELDS), item = _.item || defaultItemCreate, key$$1 = _.key || tupleid, map = this.value; // prevent transient (e.g., hover) requests from // cascading across marks derived from marks if (isArray(out.encode)) { out.encode = null; } if (!map) { pulse = pulse.addAll(); this.value = map = fastmap().test(isExit); map.lookup = function(t) { return map.get(key$$1(t)); }; } if (_.modified('key') || pulse.modified(key$$1)) { error$1('DataJoin does not support modified key function or fields.'); } pulse.visit(pulse.ADD, function(t) { var k = key$$1(t), x = map.get(k); if (x) { if (x.exit) { map.empty--; out.add.push(x); } else { out.mod.push(x); } } else { map.set(k, (x = item(t))); out.add.push(x); } x.datum = t; x.exit = false; }); pulse.visit(pulse.MOD, function(t) { var k = key$$1(t), x = map.get(k); if (x) { x.datum = t; out.mod.push(x); } }); pulse.visit(pulse.REM, function(t) { var k = key$$1(t), x = map.get(k); if (t === x.datum && !x.exit) { out.rem.push(x); x.exit = true; ++map.empty; } }); if (pulse.changed(pulse.ADD_MOD)) out.modifies('datum'); if (_.clean && map.empty > df.cleanThreshold) df.runAfter(map.clean); return out; }; /** * Invokes encoding functions for visual items. * @constructor * @param {object} params - The parameters to the encoding functions. This * parameter object will be passed through to all invoked encoding functions. * @param {object} param.encoders - The encoding functions * @param {function(object, object): boolean} [param.encoders.update] - Update encoding set * @param {function(object, object): boolean} [param.encoders.enter] - Enter encoding set * @param {function(object, object): boolean} [param.encoders.exit] - Exit encoding set */ function Encode(params) { Transform.call(this, null, params); } var prototype$53 = inherits(Encode, Transform); prototype$53.transform = function(_, pulse) { var out = pulse.fork(pulse.ADD_REM), encoders = _.encoders, encode = pulse.encode; // if an array, the encode directive includes additional sets // that must be defined in order for the primary set to be invoked // e.g., only run the update set if the hover set is defined if (isArray(encode)) { if (out.changed() || encode.every(function(e) { return encoders[e]; })) { encode = encode[0]; } else { return pulse.StopPropagation; } } // marshall encoder functions var reenter = encode === 'enter', update = encoders.update || falsy, enter = encoders.enter || falsy, exit = encoders.exit || falsy, set = (encode && !reenter ? encoders[encode] : update) || falsy; if (pulse.changed(pulse.ADD)) { pulse.visit(pulse.ADD, function(t) { enter(t, _); update(t, _); if (set !== falsy && set !== update) set(t, _); }); out.modifies(enter.output); out.modifies(update.output); if (set !== falsy && set !== update) out.modifies(set.output); } if (pulse.changed(pulse.REM) && exit !== falsy) { pulse.visit(pulse.REM, function(t) { exit(t, _); }); out.modifies(exit.output); } if (reenter || set !== falsy) { var flag = pulse.MOD | (_.modified() ? pulse.REFLOW : 0); if (reenter) { pulse.visit(flag, function(t) { var mod = enter(t, _); if (set(t, _) || mod) out.mod.push(t); }); if (out.mod.length) out.modifies(enter.output); } else { pulse.visit(flag, function(t) { if (set(t, _)) out.mod.push(t); }); } if (out.mod.length) out.modifies(set.output); } return out.changed() ? out : pulse.StopPropagation; }; var discrete$1 = {}; discrete$1[Quantile] = quantile$1; discrete$1[Quantize] = quantize$2; discrete$1[Threshold] = threshold$2; discrete$1[BinLinear] = bin$1; discrete$1[BinOrdinal] = bin$1; function labelValues(scale, count, gradient) { if (gradient) return scale.domain(); var values = discrete$1[scale.type]; return values ? values(scale) : tickValues(scale, count); } function quantize$2(scale) { var domain = scale.domain(), x0 = domain[0], x1 = peek(domain), n = scale.range().length, values = new Array(n), i = 0; values[0] = -Infinity; while (++i < n) values[i] = (i * x1 - (i - n) * x0) / n; values.max = +Infinity; return values; } function quantile$1(scale) { var values = [-Infinity].concat(scale.quantiles()); values.max = +Infinity; return values; } function threshold$2(scale) { var values = [-Infinity].concat(scale.domain()); values.max = +Infinity; return values; } function bin$1(scale) { var values = scale.domain(); values.max = values.pop(); return values; } function labelFormat(scale, format) { return discrete$1[scale.type] ? formatRange(format) : formatPoint(format); } function formatRange(format) { return function(value, index, array$$1) { var limit = array$$1[index + 1] || array$$1.max || +Infinity, lo = formatValue(value, format), hi = formatValue(limit, format); return lo && hi ? lo + '\u2013' + hi : hi ? '< ' + hi : '\u2265 ' + lo; }; } function formatValue(value, format) { return isFinite(value) ? format(value) : null; } function formatPoint(format) { return function(value) { return format(value); }; } /** * Generates legend entries for visualizing a scale. * @constructor * @param {object} params - The parameters for this operator. * @param {Scale} params.scale - The scale to generate items for. * @param {*} [params.count=10] - The approximate number of items, or * desired tick interval, to use. * @param {Array<*>} [params.values] - The exact tick values to use. * These must be legal domain values for the provided scale. * If provided, the count argument is ignored. * @param {function(*):string} [params.formatSpecifier] - A format specifier * to use in conjunction with scale.tickFormat. Legal values are * any valid d3 4.0 format specifier. * @param {function(*):string} [params.format] - The format function to use. * If provided, the formatSpecifier argument is ignored. */ function LegendEntries(params) { Transform.call(this, [], params); } var prototype$54 = inherits(LegendEntries, Transform); prototype$54.transform = function(_, pulse) { if (this.value != null && !_.modified()) { return pulse.StopPropagation; } var out = pulse.fork(pulse.NO_SOURCE | pulse.NO_FIELDS), total = 0, items = this.value, grad = _.type === 'gradient', scale = _.scale, count = _.count == null ? 5 : tickCount(scale, _.count), format = _.format || tickFormat(scale, count, _.formatSpecifier), values = _.values || labelValues(scale, count, grad); format = labelFormat(scale, format); if (items) out.rem = items; if (grad) { var domain = _.values ? scale.domain() : values, fraction = scaleFraction(scale, domain[0], peek(domain)); } else { var size = _.size, offset; if (isFunction(size)) { // if first value maps to size zero, remove from list (vega#717) if (!_.values && scale(values[0]) === 0) { values = values.slice(1); } // compute size offset for legend entries offset = values.reduce(function(max, value) { return Math.max(max, size(value, _)); }, 0); } else { size = constant(offset = size || 8); } } items = values.map(function(value, index) { var t = ingest({ index: index, label: format(value, index, values), value: value }); if (grad) { t.perc = fraction(value); } else { t.offset = offset; t.size = size(value, _); t.total = Math.round(total); total += t.size; } return t; }); out.source = items; out.add = items; this.value = items; return out; }; var Paths = fastmap({ 'line': line$3, 'line-radial': lineR, 'arc': arc$2, 'arc-radial': arcR, 'curve': curve, 'curve-radial': curveR, 'orthogonal-horizontal': orthoX, 'orthogonal-vertical': orthoY, 'orthogonal-radial': orthoR, 'diagonal-horizontal': diagonalX, 'diagonal-vertical': diagonalY, 'diagonal-radial': diagonalR }); function sourceX(t) { return t.source.x; } function sourceY(t) { return t.source.y; } function targetX(t) { return t.target.x; } function targetY(t) { return t.target.y; } /** * Layout paths linking source and target elements. * @constructor * @param {object} params - The parameters for this operator. */ function LinkPath(params) { Transform.call(this, {}, params); } LinkPath.Definition = { "type": "LinkPath", "metadata": {"modifies": true}, "params": [ { "name": "sourceX", "type": "field", "default": "source.x" }, { "name": "sourceY", "type": "field", "default": "source.y" }, { "name": "targetX", "type": "field", "default": "target.x" }, { "name": "targetY", "type": "field", "default": "target.y" }, { "name": "orient", "type": "enum", "default": "vertical", "values": ["horizontal", "vertical", "radial"] }, { "name": "shape", "type": "enum", "default": "line", "values": ["line", "arc", "curve", "diagonal", "orthogonal"] }, { "name": "as", "type": "string", "default": "path" } ] }; var prototype$55 = inherits(LinkPath, Transform); prototype$55.transform = function(_, pulse) { var sx = _.sourceX || sourceX, sy = _.sourceY || sourceY, tx = _.targetX || targetX, ty = _.targetY || targetY, as = _.as || 'path', orient = _.orient || 'vertical', shape = _.shape || 'line', path = Paths.get(shape + '-' + orient) || Paths.get(shape); if (!path) { error$1('LinkPath unsupported type: ' + _.shape + (_.orient ? '-' + _.orient : '')); } pulse.visit(pulse.SOURCE, function(t) { t[as] = path(sx(t), sy(t), tx(t), ty(t)); }); return pulse.reflow(_.modified()).modifies(as); }; // -- Link Path Generation Methods ----- function line$3(sx, sy, tx, ty) { return 'M' + sx + ',' + sy + 'L' + tx + ',' + ty; } function lineR(sa, sr, ta, tr) { return line$3( sr * Math.cos(sa), sr * Math.sin(sa), tr * Math.cos(ta), tr * Math.sin(ta) ); } function arc$2(sx, sy, tx, ty) { var dx = tx - sx, dy = ty - sy, rr = Math.sqrt(dx * dx + dy * dy) / 2, ra = 180 * Math.atan2(dy, dx) / Math.PI; return 'M' + sx + ',' + sy + 'A' + rr + ',' + rr + ' ' + ra + ' 0 1' + ' ' + tx + ',' + ty; } function arcR(sa, sr, ta, tr) { return arc$2( sr * Math.cos(sa), sr * Math.sin(sa), tr * Math.cos(ta), tr * Math.sin(ta) ); } function curve(sx, sy, tx, ty) { var dx = tx - sx, dy = ty - sy, ix = 0.2 * (dx + dy), iy = 0.2 * (dy - dx); return 'M' + sx + ',' + sy + 'C' + (sx+ix) + ',' + (sy+iy) + ' ' + (tx+iy) + ',' + (ty-ix) + ' ' + tx + ',' + ty; } function curveR(sa, sr, ta, tr) { return curve( sr * Math.cos(sa), sr * Math.sin(sa), tr * Math.cos(ta), tr * Math.sin(ta) ); } function orthoX(sx, sy, tx, ty) { return 'M' + sx + ',' + sy + 'V' + ty + 'H' + tx; } function orthoY(sx, sy, tx, ty) { return 'M' + sx + ',' + sy + 'H' + tx + 'V' + ty; } function orthoR(sa, sr, ta, tr) { var sc = Math.cos(sa), ss = Math.sin(sa), tc = Math.cos(ta), ts = Math.sin(ta), sf = Math.abs(ta - sa) > Math.PI ? ta <= sa : ta > sa; return 'M' + (sr*sc) + ',' + (sr*ss) + 'A' + sr + ',' + sr + ' 0 0,' + (sf?1:0) + ' ' + (sr*tc) + ',' + (sr*ts) + 'L' + (tr*tc) + ',' + (tr*ts); } function diagonalX(sx, sy, tx, ty) { var m = (sx + tx) / 2; return 'M' + sx + ',' + sy + 'C' + m + ',' + sy + ' ' + m + ',' + ty + ' ' + tx + ',' + ty; } function diagonalY(sx, sy, tx, ty) { var m = (sy + ty) / 2; return 'M' + sx + ',' + sy + 'C' + sx + ',' + m + ' ' + tx + ',' + m + ' ' + tx + ',' + ty; } function diagonalR(sa, sr, ta, tr) { var sc = Math.cos(sa), ss = Math.sin(sa), tc = Math.cos(ta), ts = Math.sin(ta), mr = (sr + tr) / 2; return 'M' + (sr*sc) + ',' + (sr*ss) + 'C' + (mr*sc) + ',' + (mr*ss) + ' ' + (mr*tc) + ',' + (mr*ts) + ' ' + (tr*tc) + ',' + (tr*ts); } /** * Pie and donut chart layout. * @constructor * @param {object} params - The parameters for this operator. * @param {function(object): *} params.field - The value field to size pie segments. * @param {number} [params.startAngle=0] - The start angle (in radians) of the layout. * @param {number} [params.endAngle=2π] - The end angle (in radians) of the layout. * @param {boolean} [params.sort] - Boolean flag for sorting sectors by value. */ function Pie(params) { Transform.call(this, null, params); } Pie.Definition = { "type": "Pie", "metadata": {"modifies": true}, "params": [ { "name": "field", "type": "field" }, { "name": "startAngle", "type": "number", "default": 0 }, { "name": "endAngle", "type": "number", "default": 6.283185307179586 }, { "name": "sort", "type": "boolean", "default": false }, { "name": "as", "type": "string", "array": true, "length": 2, "default": ["startAngle", "endAngle"] } ] }; var prototype$56 = inherits(Pie, Transform); prototype$56.transform = function(_, pulse) { var as = _.as || ['startAngle', 'endAngle'], startAngle = as[0], endAngle = as[1], field$$1 = _.field || one, start = _.startAngle || 0, stop = _.endAngle != null ? _.endAngle : 2 * Math.PI, data = pulse.source, values = data.map(field$$1), n = values.length, a = start, k = (stop - start) / sum(values), index = sequence(n), i, t, v; if (_.sort) { index.sort(function(a, b) { return values[a] - values[b]; }); } for (i=0; i -1) return raw; var domain = _.domain, zero$$1 = _.zero || (_.zero === undefined && INCLUDE_ZERO[scale.type]), n, mid; if (!domain) return 0; // adjust domain based on zero, min, max settings if (zero$$1 || _.domainMin != null || _.domainMax != null || _.domainMid != null) { n = ((domain = domain.slice()).length - 1) || 1; if (zero$$1) { if (domain[0] > 0) domain[0] = 0; if (domain[n] < 0) domain[n] = 0; } if (_.domainMin != null) domain[0] = _.domainMin; if (_.domainMax != null) domain[n] = _.domainMax; if (_.domainMid != null) { mid = _.domainMid; if (mid < domain[0] || mid > domain[n]) { df.warn('Scale domainMid exceeds domain min or max.', mid); } domain.splice(n, 0, mid); } } // set the scale domain scale.domain(domain); // perform 'nice' adjustment as requested if (_.nice && scale.nice) { scale.nice((_.nice !== true && tickCount(scale, _.nice)) || null); } // return the cardinality of the domain return domain.length; } function rawDomain(scale, raw) { if (raw) { scale.domain(raw); return raw.length; } else { return -1; } } function configureRange(scale, _, count) { var round = _.round || false, range = _.range; // if range step specified, calculate full range extent if (_.rangeStep != null) { range = configureRangeStep(scale.type, _, count); } // else if a range scheme is defined, use that else if (_.scheme) { range = configureScheme(scale.type, _, count); if (isFunction(range)) return scale.interpolator(range); } // given a range array for a sequential scale, convert to interpolator else if (range && scale.type === Sequential) { return scale.interpolator(rgbBasis(flip(range, _.reverse))); } // configure rounding / interpolation if (range && _.interpolate && scale.interpolate) { scale.interpolate(interpolate$1(_.interpolate, _.interpolateGamma)); } else if (isFunction(scale.round)) { scale.round(round); } else if (isFunction(scale.rangeRound)) { scale.interpolate(round ? interpolateRound : interpolate); } if (range) scale.range(flip(range, _.reverse)); } function configureRangeStep(type, _, count) { if (type !== Band && type !== Point) { error$1('Only band and point scales support rangeStep.'); } // calculate full range based on requested step size and padding var outer = (_.paddingOuter != null ? _.paddingOuter : _.padding) || 0, inner = type === Point ? 1 : ((_.paddingInner != null ? _.paddingInner : _.padding) || 0); return [0, _.rangeStep * bandSpace(count, inner, outer)]; } function configureScheme(type, _, count) { var name = _.scheme.toLowerCase(), scheme = getScheme(name), extent = _.schemeExtent, discrete; if (!scheme) { error$1('Unrecognized scheme name: ' + _.scheme); } // determine size for potential discrete range count = (type === Threshold) ? count + 1 : (type === BinOrdinal) ? count - 1 : (type === Quantile || type === Quantize) ? (+_.schemeCount || DEFAULT_COUNT) : count; // adjust and/or quantize scheme as appropriate return type === Sequential ? adjustScheme(scheme, extent, _.reverse) : !extent && (discrete = getScheme(name + '-' + count)) ? discrete : isFunction(scheme) ? quantize$3(adjustScheme(scheme, extent), count) : type === Ordinal ? scheme : scheme.slice(0, count); } function adjustScheme(scheme, extent, reverse) { return (isFunction(scheme) && (extent || reverse)) ? interpolateRange(scheme, flip(extent || [0, 1], reverse)) : scheme; } function flip(array$$1, reverse) { return reverse ? array$$1.slice().reverse() : array$$1; } function quantize$3(interpolator, count) { var samples = new Array(count), n = (count - 1) || 1; for (var i = 0; i < count; ++i) samples[i] = interpolator(i / n); return samples; } /** * Sorts scenegraph items in the pulse source array. * @constructor * @param {object} params - The parameters for this operator. * @param {function(*,*): number} [params.sort] - A comparator * function for sorting tuples. */ function SortItems(params) { Transform.call(this, null, params); } var prototype$58 = inherits(SortItems, Transform); prototype$58.transform = function(_, pulse) { var mod = _.modified('sort') || pulse.changed(pulse.ADD) || pulse.modified(_.sort.fields) || pulse.modified('datum'); if (mod) pulse.source.sort(_.sort); this.modified(mod); return pulse; }; var Center = 'center'; var Normalize = 'normalize'; /** * Stack layout for visualization elements. * @constructor * @param {object} params - The parameters for this operator. * @param {function(object): *} params.field - The value field to stack. * @param {Array} [params.groupby] - An array of accessors to groupby. * @param {function(object,object): number} [params.sort] - A comparator for stack sorting. * @param {string} [offset='zero'] - One of 'zero', 'center', 'normalize'. */ function Stack(params) { Transform.call(this, null, params); } Stack.Definition = { "type": "Stack", "metadata": {"modifies": true}, "params": [ { "name": "field", "type": "field" }, { "name": "groupby", "type": "field", "array": true }, { "name": "sort", "type": "compare" }, { "name": "offset", "type": "enum", "default": "zero", "values": ["zero", "center", "normalize"] }, { "name": "as", "type": "string", "array": true, "length": 2, "default": ["y0", "y1"] } ] }; var prototype$59 = inherits(Stack, Transform); prototype$59.transform = function(_, pulse) { var as = _.as || ['y0', 'y1'], y0 = as[0], y1 = as[1], field$$1 = _.field || one, stack = _.offset === Center ? stackCenter : _.offset === Normalize ? stackNormalize : stackZero, groups, i, n, max; // partition, sum, and sort the stack groups groups = partition$1(pulse.source, _.groupby, _.sort, field$$1); // compute stack layouts per group for (i=0, n=groups.length, max=groups.max; i max) max = s; if (sort) g.sort(sort); } groups.max = max; return groups; } var encode = Object.freeze({ axisticks: AxisTicks, datajoin: DataJoin, encode: Encode, legendentries: LegendEntries, linkpath: LinkPath, pie: Pie, scale: Scale, sortitems: SortItems, stack: Stack }); var array$4 = Array.prototype; var slice$4 = array$4.slice; var ascending$2 = function(a, b) { return a - b; }; var area$3 = function(ring) { var i = 0, n = ring.length, area = ring[n - 1][1] * ring[0][0] - ring[n - 1][0] * ring[0][1]; while (++i < n) area += ring[i - 1][1] * ring[i][0] - ring[i - 1][0] * ring[i][1]; return area; }; var constant$6 = function(x) { return function() { return x; }; }; var contains = function(ring, hole) { var i = -1, n = hole.length, c; while (++i < n) if (c = ringContains(ring, hole[i])) return c; return 0; }; function ringContains(ring, point) { var x = point[0], y = point[1], contains = -1; for (var i = 0, n = ring.length, j = n - 1; i < n; j = i++) { var pi = ring[i], xi = pi[0], yi = pi[1], pj = ring[j], xj = pj[0], yj = pj[1]; if (segmentContains(pi, pj, point)) return 0; if (((yi > y) !== (yj > y)) && ((x < (xj - xi) * (y - yi) / (yj - yi) + xi))) contains = -contains; } return contains; } function segmentContains(a, b, c) { var i; return collinear(a, b, c) && within(a[i = +(a[0] === b[0])], c[i], b[i]); } function collinear(a, b, c) { return (b[0] - a[0]) * (c[1] - a[1]) === (c[0] - a[0]) * (b[1] - a[1]); } function within(p, q, r) { return p <= q && q <= r || r <= q && q <= p; } var noop$4 = function() {}; var cases = [ [], [[[1,1.5],[0.5,1]]], [[[1.5,1],[1,1.5]]], [[[1.5,1],[0.5,1]]], [[[1,0.5],[1.5,1]]], [[[1,0.5],[0.5,1]],[[1,1.5],[1.5,1]]], [[[1,0.5],[1,1.5]]], [[[1,0.5],[0.5,1]]], [[[0.5,1],[1,0.5]]], [[[1,1.5],[1,0.5]]], [[[0.5,1],[1,1.5]],[[1.5,1],[1,0.5]]], [[[1.5,1],[1,0.5]]], [[[0.5,1],[1.5,1]]], [[[1,1.5],[1.5,1]]], [[[0.5,1],[1,1.5]]], [] ]; var contours = function() { var dx = 1, dy = 1, threshold$$1 = thresholdSturges, smooth = smoothLinear; function contours(values) { var tz = threshold$$1(values); // Convert number of thresholds into uniform thresholds. if (!Array.isArray(tz)) { var domain = extent(values), start = domain[0], stop = domain[1]; tz = tickStep(start, stop, tz); tz = sequence(Math.floor(start / tz) * tz, Math.floor(stop / tz) * tz, tz); } else { tz = tz.slice().sort(ascending$2); } // Accumulate, smooth contour rings, assign holes to exterior rings. // Based on https://github.com/mbostock/shapefile/blob/v0.6.2/shp/polygon.js var layers = tz.map(function(value) { var polygons = [], holes = []; isorings(values, value, function(ring) { smooth(ring, values, value); if (area$3(ring) > 0) polygons.push([ring]); else holes.push(ring); }); holes.forEach(function(hole) { for (var i = 0, n = polygons.length, polygon; i < n; ++i) { if (contains((polygon = polygons[i])[0], hole) !== -1) { polygon.push(hole); return; } } }); return polygons; }); return layers.map(function(polygons, i) { return { type: "MultiPolygon", value: tz[i], coordinates: polygons }; }); } // Marching squares with isolines stitched into rings. // Based on https://github.com/topojson/topojson-client/blob/v3.0.0/src/stitch.js function isorings(values, value, callback) { var fragmentByStart = new Array, fragmentByEnd = new Array, x, y, t0, t1, t2, t3; // Special case for the first row (y = -1, t2 = t3 = 0). x = y = -1; t1 = values[0] >= value; cases[t1 << 1].forEach(stitch); while (++x < dx - 1) { t0 = t1, t1 = values[x + 1] >= value; cases[t0 | t1 << 1].forEach(stitch); } cases[t1 << 0].forEach(stitch); // General case for the intermediate rows. while (++y < dy - 1) { x = -1; t1 = values[y * dx + dx] >= value; t2 = values[y * dx] >= value; cases[t1 << 1 | t2 << 2].forEach(stitch); while (++x < dx - 1) { t0 = t1, t1 = values[y * dx + dx + x + 1] >= value; t3 = t2, t2 = values[y * dx + x + 1] >= value; cases[t0 | t1 << 1 | t2 << 2 | t3 << 3].forEach(stitch); } cases[t1 | t2 << 3].forEach(stitch); } // Special case for the last row (y = dy - 1, t0 = t1 = 0). x = -1; t2 = values[y * dx] >= value; cases[t2 << 2].forEach(stitch); while (++x < dx - 1) { t3 = t2, t2 = values[y * dx + x + 1] >= value; cases[t2 << 2 | t3 << 3].forEach(stitch); } cases[t2 << 3].forEach(stitch); function stitch(line) { var start = [line[0][0] + x, line[0][1] + y], end = [line[1][0] + x, line[1][1] + y], startIndex = index(start), endIndex = index(end), f, g; if (f = fragmentByEnd[startIndex]) { if (g = fragmentByStart[endIndex]) { delete fragmentByEnd[f.end]; delete fragmentByStart[g.start]; if (f === g) { f.ring.push(end); callback(f.ring); } else { fragmentByStart[f.start] = fragmentByEnd[g.end] = {start: f.start, end: g.end, ring: f.ring.concat(g.ring)}; } } else { delete fragmentByEnd[f.end]; f.ring.push(end); fragmentByEnd[f.end = endIndex] = f; } } else if (f = fragmentByStart[endIndex]) { if (g = fragmentByEnd[startIndex]) { delete fragmentByStart[f.start]; delete fragmentByEnd[g.end]; if (f === g) { f.ring.push(end); callback(f.ring); } else { fragmentByStart[g.start] = fragmentByEnd[f.end] = {start: g.start, end: f.end, ring: g.ring.concat(f.ring)}; } } else { delete fragmentByStart[f.start]; f.ring.unshift(start); fragmentByStart[f.start = startIndex] = f; } } else { fragmentByStart[startIndex] = fragmentByEnd[endIndex] = {start: startIndex, end: endIndex, ring: [start, end]}; } } } function index(point) { return point[0] * 2 + point[1] * (dx + 1) * 4; } function smoothLinear(ring, values, value) { ring.forEach(function(point) { var x = point[0], y = point[1], xt = x | 0, yt = y | 0, v0, v1 = values[yt * dx + xt]; if (x > 0 && x < dx && xt === x) { v0 = values[yt * dx + xt - 1]; point[0] = x + (value - v0) / (v1 - v0) - 0.5; } if (y > 0 && y < dy && yt === y) { v0 = values[(yt - 1) * dx + xt]; point[1] = y + (value - v0) / (v1 - v0) - 0.5; } }); } contours.size = function(_) { if (!arguments.length) return [dx, dy]; var _0 = Math.ceil(_[0]), _1 = Math.ceil(_[1]); if (!(_0 > 0) || !(_1 > 0)) throw new Error("invalid size"); return dx = _0, dy = _1, contours; }; contours.thresholds = function(_) { return arguments.length ? (threshold$$1 = typeof _ === "function" ? _ : Array.isArray(_) ? constant$6(slice$4.call(_)) : constant$6(_), contours) : threshold$$1; }; contours.smooth = function(_) { return arguments.length ? (smooth = _ ? smoothLinear : noop$4, contours) : smooth === smoothLinear; }; return contours; }; // TODO Optimize edge cases. // TODO Optimize index calculation. // TODO Optimize arguments. function blurX(source, target, r) { var n = source.width, m = source.height, w = (r << 1) + 1; for (var j = 0; j < m; ++j) { for (var i = 0, sr = 0; i < n + r; ++i) { if (i < n) { sr += source.data[i + j * n]; } if (i >= r) { if (i >= w) { sr -= source.data[i - w + j * n]; } target.data[i - r + j * n] = sr / Math.min(i + 1, n - 1 + w - i, w); } } } } // TODO Optimize edge cases. // TODO Optimize index calculation. // TODO Optimize arguments. function blurY(source, target, r) { var n = source.width, m = source.height, w = (r << 1) + 1; for (var i = 0; i < n; ++i) { for (var j = 0, sr = 0; j < m + r; ++j) { if (j < m) { sr += source.data[i + j * n]; } if (j >= r) { if (j >= w) { sr -= source.data[i + (j - w) * n]; } target.data[i + (j - r) * n] = sr / Math.min(j + 1, m - 1 + w - j, w); } } } } function defaultX(d) { return d[0]; } function defaultY(d) { return d[1]; } var contourDensity = function() { var x = defaultX, y = defaultY, dx = 960, dy = 500, r = 20, // blur radius k = 2, // log2(grid cell size) o = r * 3, // grid offset, to pad for blur n = (dx + o * 2) >> k, // grid width m = (dy + o * 2) >> k, // grid height threshold$$1 = constant$6(20); function density(data) { var values0 = new Float32Array(n * m), values1 = new Float32Array(n * m); data.forEach(function(d, i, data) { var xi = (x(d, i, data) + o) >> k, yi = (y(d, i, data) + o) >> k; if (xi >= 0 && xi < n && yi >= 0 && yi < m) { ++values0[xi + yi * n]; } }); // TODO Optimize. blurX({width: n, height: m, data: values0}, {width: n, height: m, data: values1}, r >> k); blurY({width: n, height: m, data: values1}, {width: n, height: m, data: values0}, r >> k); blurX({width: n, height: m, data: values0}, {width: n, height: m, data: values1}, r >> k); blurY({width: n, height: m, data: values1}, {width: n, height: m, data: values0}, r >> k); blurX({width: n, height: m, data: values0}, {width: n, height: m, data: values1}, r >> k); blurY({width: n, height: m, data: values1}, {width: n, height: m, data: values0}, r >> k); var tz = threshold$$1(values0); // Convert number of thresholds into uniform thresholds. if (!Array.isArray(tz)) { var stop = max(values0); tz = tickStep(0, stop, tz); tz = sequence(0, Math.floor(stop / tz) * tz, tz); tz.shift(); } return contours() .thresholds(tz) .size([n, m]) (values0) .map(transform); } function transform(geometry) { geometry.value *= Math.pow(2, -2 * k); // Density in points per square pixel. geometry.coordinates.forEach(transformPolygon); return geometry; } function transformPolygon(coordinates) { coordinates.forEach(transformRing); } function transformRing(coordinates) { coordinates.forEach(transformPoint); } // TODO Optimize. function transformPoint(coordinates) { coordinates[0] = coordinates[0] * Math.pow(2, k) - o; coordinates[1] = coordinates[1] * Math.pow(2, k) - o; } function resize() { o = r * 3; n = (dx + o * 2) >> k; m = (dy + o * 2) >> k; return density; } density.x = function(_) { return arguments.length ? (x = typeof _ === "function" ? _ : constant$6(+_), density) : x; }; density.y = function(_) { return arguments.length ? (y = typeof _ === "function" ? _ : constant$6(+_), density) : y; }; density.size = function(_) { if (!arguments.length) return [dx, dy]; var _0 = Math.ceil(_[0]), _1 = Math.ceil(_[1]); if (!(_0 >= 0) && !(_0 >= 0)) throw new Error("invalid size"); return dx = _0, dy = _1, resize(); }; density.cellSize = function(_) { if (!arguments.length) return 1 << k; if (!((_ = +_) >= 1)) throw new Error("invalid cell size"); return k = Math.floor(Math.log(_) / Math.LN2), resize(); }; density.thresholds = function(_) { return arguments.length ? (threshold$$1 = typeof _ === "function" ? _ : Array.isArray(_) ? constant$6(slice$4.call(_)) : constant$6(_), density) : threshold$$1; }; density.bandwidth = function(_) { if (!arguments.length) return Math.sqrt(r * (r + 1)); if (!((_ = +_) >= 0)) throw new Error("invalid bandwidth"); return r = Math.round((Math.sqrt(4 * _ * _ + 1) - 1) / 2), resize(); }; return density; }; var CONTOUR_PARAMS = ['values', 'size']; var DENSITY_PARAMS = ['x', 'y', 'size', 'cellSize', 'bandwidth']; /** * Generate contours based on kernel-density estimation of point data. * @constructor * @param {object} params - The parameters for this operator. * @param {Array} params.size - The dimensions [width, height] over which to compute contours. * If the values parameter is provided, this must be the dimensions of the input data. * If density estimation is performed, this is the output view dimensions in pixels. * @param {Array} [params.values] - An array of numeric values representing an * width x height grid of values over which to compute contours. If unspecified, this * transform will instead attempt to compute contours for the kernel density estimate * using values drawn from data tuples in the input pulse. * @param {function(object): number} [params.x] - The pixel x-coordinate accessor for density estimation. * @param {function(object): number} [params.y] - The pixel y-coordinate accessor for density estimation. * @param {number} [params.cellSize] - Contour density calculation cell size. * @param {number} [params.bandwidth] - Kernel density estimation bandwidth. * @param {Array} [params.thresholds] - Contour threshold array. If * this parameter is set, the count and nice parameters will be ignored. * @param {number} [params.count] - The desired number of contours. * @param {boolean} [params.nice] - Boolean flag indicating if the contour * threshold values should be automatically aligned to "nice" * human-friendly values. Setting this flag may cause the number of * thresholds to deviate from the specified count. */ function Contour(params) { Transform.call(this, null, params); } Contour.Definition = { "type": "Contour", "metadata": {"generates": true, "source": true}, "params": [ { "name": "size", "type": "number", "array": true, "length": 2, "required": true }, { "name": "values", "type": "number", "array": true }, { "name": "x", "type": "field" }, { "name": "y", "type": "field" }, { "name": "cellSize", "type": "number" }, { "name": "bandwidth", "type": "number" }, { "name": "count", "type": "number" }, { "name": "nice", "type": "number", "default": false }, { "name": "thresholds", "type": "number", "array": true } ] }; var prototype$60 = inherits(Contour, Transform); prototype$60.transform = function(_, pulse) { if (this.value && !pulse.changed() && !_.modified()) return pulse.StopPropagation; var out = pulse.fork(pulse.NO_SOURCE | pulse.NO_FIELDS), count = _.count || 10, contour, params, values; if (_.values) { contour = contours(); params = CONTOUR_PARAMS; values = _.values; } else { contour = contourDensity(); params = DENSITY_PARAMS; values = pulse.materialize(pulse.SOURCE).source; } // set threshold parameter contour.thresholds(_.thresholds || (_.nice ? count : quantize$4(count))); // set all other parameters params.forEach(function(param) { if (_[param] != null) contour[param](_[param]); }); if (this.value) out.rem = this.value; this.value = out.source = out.add = contour(values).map(ingest); return out; }; function quantize$4(k) { return function(values) { var ex = extent(values), x0 = ex[0], dx = ex[1] - x0, t = [], i = 1; for (; i<=k; ++i) t.push(x0 + dx * i / (k + 1)); return t; }; } var Feature = 'Feature'; var FeatureCollection = 'FeatureCollection'; var MultiPoint = 'MultiPoint'; /** * Consolidate an array of [longitude, latitude] points or GeoJSON features * into a combined GeoJSON object. This transform is particularly useful for * combining geo data for a Projection's fit argument. The resulting GeoJSON * data is available as this transform's value. Input pulses are unchanged. * @constructor * @param {object} params - The parameters for this operator. * @param {Array} [params.fields] - A two-element array * of field accessors for the longitude and latitude values. * @param {function(object): *} params.geojson - A field accessor for * retrieving GeoJSON feature data. */ function GeoJSON(params) { Transform.call(this, null, params); } GeoJSON.Definition = { "type": "GeoJSON", "metadata": {}, "params": [ { "name": "fields", "type": "field", "array": true, "length": 2 }, { "name": "geojson", "type": "field" }, ] }; var prototype$61 = inherits(GeoJSON, Transform); prototype$61.transform = function(_, pulse) { var features = this._features, points = this._points, fields = _.fields, lon = fields && fields[0], lat = fields && fields[1], geojson = _.geojson, flag = pulse.ADD, mod; mod = _.modified() || pulse.changed(pulse.REM) || pulse.modified(accessorFields(geojson)) || (lon && (pulse.modified(accessorFields(lon)))) || (lat && (pulse.modified(accessorFields(lat)))); if (!this.value || mod) { flag = pulse.SOURCE; this._features = (features = []); this._points = (points = []); } if (geojson) { pulse.visit(flag, function(t) { features.push(geojson(t)); }); } if (lon && lat) { pulse.visit(flag, function(t) { var x = lon(t), y = lat(t); if (x != null && y != null && (x = +x) === x && (y = +y) === y) { points.push([x, y]); } }); features = features.concat({ type: Feature, geometry: { type: MultiPoint, coordinates: points } }); } this.value = { type: FeatureCollection, features: features }; }; // Adds floating point numbers with twice the normal precision. // Reference: J. R. Shewchuk, Adaptive Precision Floating-Point Arithmetic and // Fast Robust Geometric Predicates, Discrete & Computational Geometry 18(3) // 305–363 (1997). // Code adapted from GeographicLib by Charles F. F. Karney, // http://geographiclib.sourceforge.net/ var adder = function() { return new Adder; }; function Adder() { this.reset(); } Adder.prototype = { constructor: Adder, reset: function() { this.s = // rounded value this.t = 0; // exact error }, add: function(y) { add$3(temp$2, y, this.t); add$3(this, temp$2.s, this.s); if (this.s) this.t += temp$2.t; else this.s = temp$2.t; }, valueOf: function() { return this.s; } }; var temp$2 = new Adder; function add$3(adder, a, b) { var x = adder.s = a + b, bv = x - a, av = x - bv; adder.t = (a - av) + (b - bv); } var epsilon$2 = 1e-6; var pi$3 = Math.PI; var halfPi$2 = pi$3 / 2; var quarterPi = pi$3 / 4; var tau$4 = pi$3 * 2; var degrees$1 = 180 / pi$3; var radians = pi$3 / 180; var abs$1 = Math.abs; var atan = Math.atan; var atan2$1 = Math.atan2; var cos$1 = Math.cos; var ceil = Math.ceil; var exp = Math.exp; var log$2 = Math.log; var pow$1 = Math.pow; var sin$1 = Math.sin; var sign$1 = Math.sign || function(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; }; var sqrt$2 = Math.sqrt; var tan = Math.tan; function acos$1(x) { return x > 1 ? 0 : x < -1 ? pi$3 : Math.acos(x); } function asin$1(x) { return x > 1 ? halfPi$2 : x < -1 ? -halfPi$2 : Math.asin(x); } function noop$5() {} function streamGeometry(geometry, stream) { if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) { streamGeometryType[geometry.type](geometry, stream); } } var streamObjectType = { Feature: function(object, stream) { streamGeometry(object.geometry, stream); }, FeatureCollection: function(object, stream) { var features = object.features, i = -1, n = features.length; while (++i < n) streamGeometry(features[i].geometry, stream); } }; var streamGeometryType = { Sphere: function(object, stream) { stream.sphere(); }, Point: function(object, stream) { object = object.coordinates; stream.point(object[0], object[1], object[2]); }, MultiPoint: function(object, stream) { var coordinates = object.coordinates, i = -1, n = coordinates.length; while (++i < n) object = coordinates[i], stream.point(object[0], object[1], object[2]); }, LineString: function(object, stream) { streamLine(object.coordinates, stream, 0); }, MultiLineString: function(object, stream) { var coordinates = object.coordinates, i = -1, n = coordinates.length; while (++i < n) streamLine(coordinates[i], stream, 0); }, Polygon: function(object, stream) { streamPolygon(object.coordinates, stream); }, MultiPolygon: function(object, stream) { var coordinates = object.coordinates, i = -1, n = coordinates.length; while (++i < n) streamPolygon(coordinates[i], stream); }, GeometryCollection: function(object, stream) { var geometries = object.geometries, i = -1, n = geometries.length; while (++i < n) streamGeometry(geometries[i], stream); } }; function streamLine(coordinates, stream, closed) { var i = -1, n = coordinates.length - closed, coordinate; stream.lineStart(); while (++i < n) coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]); stream.lineEnd(); } function streamPolygon(coordinates, stream) { var i = -1, n = coordinates.length; stream.polygonStart(); while (++i < n) streamLine(coordinates[i], stream, 1); stream.polygonEnd(); } var geoStream = function(object, stream) { if (object && streamObjectType.hasOwnProperty(object.type)) { streamObjectType[object.type](object, stream); } else { streamGeometry(object, stream); } }; var areaRingSum = adder(); var areaSum = adder(); var lambda00; var phi00; var lambda0; var cosPhi0; var sinPhi0; function spherical(cartesian) { return [atan2$1(cartesian[1], cartesian[0]), asin$1(cartesian[2])]; } function cartesian(spherical) { var lambda = spherical[0], phi = spherical[1], cosPhi = cos$1(phi); return [cosPhi * cos$1(lambda), cosPhi * sin$1(lambda), sin$1(phi)]; } function cartesianDot(a, b) { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; } function cartesianCross(a, b) { return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]]; } // TODO return a function cartesianAddInPlace(a, b) { a[0] += b[0], a[1] += b[1], a[2] += b[2]; } function cartesianScale(vector, k) { return [vector[0] * k, vector[1] * k, vector[2] * k]; } // TODO return d function cartesianNormalizeInPlace(d) { var l = sqrt$2(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); d[0] /= l, d[1] /= l, d[2] /= l; } var lambda0$1; var phi0; var lambda1; var phi1; var lambda2; var lambda00$1; var phi00$1; var p0; var deltaSum = adder(); var ranges; var range; var W0; var X0; var Y0; var Z0; // previous point var compose = function(a, b) { function compose(x, y) { return x = a(x, y), b(x[0], x[1]); } if (a.invert && b.invert) compose.invert = function(x, y) { return x = b.invert(x, y), x && a.invert(x[0], x[1]); }; return compose; }; function rotationIdentity(lambda, phi) { return [lambda > pi$3 ? lambda - tau$4 : lambda < -pi$3 ? lambda + tau$4 : lambda, phi]; } rotationIdentity.invert = rotationIdentity; function rotateRadians(deltaLambda, deltaPhi, deltaGamma) { return (deltaLambda %= tau$4) ? (deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma)) : rotationLambda(deltaLambda)) : (deltaPhi || deltaGamma ? rotationPhiGamma(deltaPhi, deltaGamma) : rotationIdentity); } function forwardRotationLambda(deltaLambda) { return function(lambda, phi) { return lambda += deltaLambda, [lambda > pi$3 ? lambda - tau$4 : lambda < -pi$3 ? lambda + tau$4 : lambda, phi]; }; } function rotationLambda(deltaLambda) { var rotation = forwardRotationLambda(deltaLambda); rotation.invert = forwardRotationLambda(-deltaLambda); return rotation; } function rotationPhiGamma(deltaPhi, deltaGamma) { var cosDeltaPhi = cos$1(deltaPhi), sinDeltaPhi = sin$1(deltaPhi), cosDeltaGamma = cos$1(deltaGamma), sinDeltaGamma = sin$1(deltaGamma); function rotation(lambda, phi) { var cosPhi = cos$1(phi), x = cos$1(lambda) * cosPhi, y = sin$1(lambda) * cosPhi, z = sin$1(phi), k = z * cosDeltaPhi + x * sinDeltaPhi; return [ atan2$1(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi), asin$1(k * cosDeltaGamma + y * sinDeltaGamma) ]; } rotation.invert = function(lambda, phi) { var cosPhi = cos$1(phi), x = cos$1(lambda) * cosPhi, y = sin$1(lambda) * cosPhi, z = sin$1(phi), k = z * cosDeltaGamma - y * sinDeltaGamma; return [ atan2$1(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi), asin$1(k * cosDeltaPhi - x * sinDeltaPhi) ]; }; return rotation; } var rotation = function(rotate) { rotate = rotateRadians(rotate[0] * radians, rotate[1] * radians, rotate.length > 2 ? rotate[2] * radians : 0); function forward(coordinates) { coordinates = rotate(coordinates[0] * radians, coordinates[1] * radians); return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates; } forward.invert = function(coordinates) { coordinates = rotate.invert(coordinates[0] * radians, coordinates[1] * radians); return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates; }; return forward; }; // Generates a circle centered at [0°, 0°], with a given radius and precision. function circleStream(stream, radius, delta, direction, t0, t1) { if (!delta) return; var cosRadius = cos$1(radius), sinRadius = sin$1(radius), step = direction * delta; if (t0 == null) { t0 = radius + direction * tau$4; t1 = radius - step / 2; } else { t0 = circleRadius(cosRadius, t0); t1 = circleRadius(cosRadius, t1); if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau$4; } for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) { point = spherical([cosRadius, -sinRadius * cos$1(t), -sinRadius * sin$1(t)]); stream.point(point[0], point[1]); } } // Returns the signed angle of a cartesian point relative to [cosRadius, 0, 0]. function circleRadius(cosRadius, point) { point = cartesian(point), point[0] -= cosRadius; cartesianNormalizeInPlace(point); var radius = acos$1(-point[1]); return ((-point[2] < 0 ? -radius : radius) + tau$4 - epsilon$2) % tau$4; } var clipBuffer = function() { var lines = [], line; return { point: function(x, y) { line.push([x, y]); }, lineStart: function() { lines.push(line = []); }, lineEnd: noop$5, rejoin: function() { if (lines.length > 1) lines.push(lines.pop().concat(lines.shift())); }, result: function() { var result = lines; lines = []; line = null; return result; } }; }; var clipLine = function(a, b, x0, y0, x1, y1) { var ax = a[0], ay = a[1], bx = b[0], by = b[1], t0 = 0, t1 = 1, dx = bx - ax, dy = by - ay, r; r = x0 - ax; if (!dx && r > 0) return; r /= dx; if (dx < 0) { if (r < t0) return; if (r < t1) t1 = r; } else if (dx > 0) { if (r > t1) return; if (r > t0) t0 = r; } r = x1 - ax; if (!dx && r < 0) return; r /= dx; if (dx < 0) { if (r > t1) return; if (r > t0) t0 = r; } else if (dx > 0) { if (r < t0) return; if (r < t1) t1 = r; } r = y0 - ay; if (!dy && r > 0) return; r /= dy; if (dy < 0) { if (r < t0) return; if (r < t1) t1 = r; } else if (dy > 0) { if (r > t1) return; if (r > t0) t0 = r; } r = y1 - ay; if (!dy && r < 0) return; r /= dy; if (dy < 0) { if (r > t1) return; if (r > t0) t0 = r; } else if (dy > 0) { if (r < t0) return; if (r < t1) t1 = r; } if (t0 > 0) a[0] = ax + t0 * dx, a[1] = ay + t0 * dy; if (t1 < 1) b[0] = ax + t1 * dx, b[1] = ay + t1 * dy; return true; }; var pointEqual = function(a, b) { return abs$1(a[0] - b[0]) < epsilon$2 && abs$1(a[1] - b[1]) < epsilon$2; }; function Intersection(point, points, other, entry) { this.x = point; this.z = points; this.o = other; // another intersection this.e = entry; // is an entry? this.v = false; // visited this.n = this.p = null; // next & previous } // A generalized polygon clipping algorithm: given a polygon that has been cut // into its visible line segments, and rejoins the segments by interpolating // along the clip edge. var clipPolygon = function(segments, compareIntersection, startInside, interpolate, stream) { var subject = [], clip = [], i, n; segments.forEach(function(segment) { if ((n = segment.length - 1) <= 0) return; var n, p0 = segment[0], p1 = segment[n], x; // If the first and last points of a segment are coincident, then treat as a // closed ring. TODO if all rings are closed, then the winding order of the // exterior ring should be checked. if (pointEqual(p0, p1)) { stream.lineStart(); for (i = 0; i < n; ++i) stream.point((p0 = segment[i])[0], p0[1]); stream.lineEnd(); return; } subject.push(x = new Intersection(p0, segment, null, true)); clip.push(x.o = new Intersection(p0, null, x, false)); subject.push(x = new Intersection(p1, segment, null, false)); clip.push(x.o = new Intersection(p1, null, x, true)); }); if (!subject.length) return; clip.sort(compareIntersection); link$1(subject); link$1(clip); for (i = 0, n = clip.length; i < n; ++i) { clip[i].e = startInside = !startInside; } var start = subject[0], points, point; while (1) { // Find first unvisited intersection. var current = start, isSubject = true; while (current.v) if ((current = current.n) === start) return; points = current.z; stream.lineStart(); do { current.v = current.o.v = true; if (current.e) { if (isSubject) { for (i = 0, n = points.length; i < n; ++i) stream.point((point = points[i])[0], point[1]); } else { interpolate(current.x, current.n.x, 1, stream); } current = current.n; } else { if (isSubject) { points = current.p.z; for (i = points.length - 1; i >= 0; --i) stream.point((point = points[i])[0], point[1]); } else { interpolate(current.x, current.p.x, -1, stream); } current = current.p; } current = current.o; points = current.z; isSubject = !isSubject; } while (!current.v); stream.lineEnd(); } }; function link$1(array) { if (!(n = array.length)) return; var n, i = 0, a = array[0], b; while (++i < n) { a.n = b = array[i]; b.p = a; a = b; } a.n = b = array[0]; b.p = a; } var clipMax = 1e9; var clipMin = -clipMax; // TODO Use d3-polygon’s polygonContains here for the ring check? // TODO Eliminate duplicate buffering in clipBuffer and polygon.push? function clipExtent(x0, y0, x1, y1) { function visible(x, y) { return x0 <= x && x <= x1 && y0 <= y && y <= y1; } function interpolate(from, to, direction, stream) { var a = 0, a1 = 0; if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoint(from, to) < 0 ^ direction > 0) { do stream.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0); while ((a = (a + direction + 4) % 4) !== a1); } else { stream.point(to[0], to[1]); } } function corner(p, direction) { return abs$1(p[0] - x0) < epsilon$2 ? direction > 0 ? 0 : 3 : abs$1(p[0] - x1) < epsilon$2 ? direction > 0 ? 2 : 1 : abs$1(p[1] - y0) < epsilon$2 ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2; // abs(p[1] - y1) < epsilon } function compareIntersection(a, b) { return comparePoint(a.x, b.x); } function comparePoint(a, b) { var ca = corner(a, 1), cb = corner(b, 1); return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0]; } return function(stream) { var activeStream = stream, bufferStream = clipBuffer(), segments, polygon, ring, x__, y__, v__, // first point x_, y_, v_, // previous point first, clean; var clipStream = { point: point, lineStart: lineStart, lineEnd: lineEnd, polygonStart: polygonStart, polygonEnd: polygonEnd }; function point(x, y) { if (visible(x, y)) activeStream.point(x, y); } function polygonInside() { var winding = 0; for (var i = 0, n = polygon.length; i < n; ++i) { for (var ring = polygon[i], j = 1, m = ring.length, point = ring[0], a0, a1, b0 = point[0], b1 = point[1]; j < m; ++j) { a0 = b0, a1 = b1, point = ring[j], b0 = point[0], b1 = point[1]; if (a1 <= y1) { if (b1 > y1 && (b0 - a0) * (y1 - a1) > (b1 - a1) * (x0 - a0)) ++winding; } else { if (b1 <= y1 && (b0 - a0) * (y1 - a1) < (b1 - a1) * (x0 - a0)) --winding; } } } return winding; } // Buffer geometry within a polygon and then clip it en masse. function polygonStart() { activeStream = bufferStream, segments = [], polygon = [], clean = true; } function polygonEnd() { var startInside = polygonInside(), cleanInside = clean && startInside, visible = (segments = merge$2(segments)).length; if (cleanInside || visible) { stream.polygonStart(); if (cleanInside) { stream.lineStart(); interpolate(null, null, 1, stream); stream.lineEnd(); } if (visible) { clipPolygon(segments, compareIntersection, startInside, interpolate, stream); } stream.polygonEnd(); } activeStream = stream, segments = polygon = ring = null; } function lineStart() { clipStream.point = linePoint; if (polygon) polygon.push(ring = []); first = true; v_ = false; x_ = y_ = NaN; } // TODO rather than special-case polygons, simply handle them separately. // Ideally, coincident intersection points should be jittered to avoid // clipping issues. function lineEnd() { if (segments) { linePoint(x__, y__); if (v__ && v_) bufferStream.rejoin(); segments.push(bufferStream.result()); } clipStream.point = point; if (v_) activeStream.lineEnd(); } function linePoint(x, y) { var v = visible(x, y); if (polygon) ring.push([x, y]); if (first) { x__ = x, y__ = y, v__ = v; first = false; if (v) { activeStream.lineStart(); activeStream.point(x, y); } } else { if (v && v_) activeStream.point(x, y); else { var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))], b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))]; if (clipLine(a, b, x0, y0, x1, y1)) { if (!v_) { activeStream.lineStart(); activeStream.point(a[0], a[1]); } activeStream.point(b[0], b[1]); if (!v) activeStream.lineEnd(); clean = false; } else if (v) { activeStream.lineStart(); activeStream.point(x, y); clean = false; } } } x_ = x, y_ = y, v_ = v; } return clipStream; }; } var sum$2 = adder(); var polygonContains = function(polygon, point) { var lambda = point[0], phi = point[1], normal = [sin$1(lambda), -cos$1(lambda), 0], angle = 0, winding = 0; sum$2.reset(); for (var i = 0, n = polygon.length; i < n; ++i) { if (!(m = (ring = polygon[i]).length)) continue; var ring, m, point0 = ring[m - 1], lambda0 = point0[0], phi0 = point0[1] / 2 + quarterPi, sinPhi0 = sin$1(phi0), cosPhi0 = cos$1(phi0); for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) { var point1 = ring[j], lambda1 = point1[0], phi1 = point1[1] / 2 + quarterPi, sinPhi1 = sin$1(phi1), cosPhi1 = cos$1(phi1), delta = lambda1 - lambda0, sign = delta >= 0 ? 1 : -1, absDelta = sign * delta, antimeridian = absDelta > pi$3, k = sinPhi0 * sinPhi1; sum$2.add(atan2$1(k * sign * sin$1(absDelta), cosPhi0 * cosPhi1 + k * cos$1(absDelta))); angle += antimeridian ? delta + sign * tau$4 : delta; // Are the longitudes either side of the point’s meridian (lambda), // and are the latitudes smaller than the parallel (phi)? if (antimeridian ^ lambda0 >= lambda ^ lambda1 >= lambda) { var arc = cartesianCross(cartesian(point0), cartesian(point1)); cartesianNormalizeInPlace(arc); var intersection = cartesianCross(normal, arc); cartesianNormalizeInPlace(intersection); var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin$1(intersection[2]); if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) { winding += antimeridian ^ delta >= 0 ? 1 : -1; } } } } // First, determine whether the South pole is inside or outside: // // It is inside if: // * the polygon winds around it in a clockwise direction. // * the polygon does not (cumulatively) wind around it, but has a negative // (counter-clockwise) area. // // Second, count the (signed) number of times a segment crosses a lambda // from the point to the South pole. If it is zero, then the point is the // same side as the South pole. return (angle < -epsilon$2 || angle < epsilon$2 && sum$2 < -epsilon$2) ^ (winding & 1); }; var lengthSum = adder(); var lambda0$2; var sinPhi0$1; var cosPhi0$1; var lengthStream = { sphere: noop$5, point: noop$5, lineStart: lengthLineStart, lineEnd: noop$5, polygonStart: noop$5, polygonEnd: noop$5 }; function lengthLineStart() { lengthStream.point = lengthPointFirst; lengthStream.lineEnd = lengthLineEnd; } function lengthLineEnd() { lengthStream.point = lengthStream.lineEnd = noop$5; } function lengthPointFirst(lambda, phi) { lambda *= radians, phi *= radians; lambda0$2 = lambda, sinPhi0$1 = sin$1(phi), cosPhi0$1 = cos$1(phi); lengthStream.point = lengthPoint; } function lengthPoint(lambda, phi) { lambda *= radians, phi *= radians; var sinPhi = sin$1(phi), cosPhi = cos$1(phi), delta = abs$1(lambda - lambda0$2), cosDelta = cos$1(delta), sinDelta = sin$1(delta), x = cosPhi * sinDelta, y = cosPhi0$1 * sinPhi - sinPhi0$1 * cosPhi * cosDelta, z = sinPhi0$1 * sinPhi + cosPhi0$1 * cosPhi * cosDelta; lengthSum.add(atan2$1(sqrt$2(x * x + y * y), z)); lambda0$2 = lambda, sinPhi0$1 = sinPhi, cosPhi0$1 = cosPhi; } var length$1 = function(object) { lengthSum.reset(); geoStream(object, lengthStream); return +lengthSum; }; var coordinates = [null, null]; var object$3 = {type: "LineString", coordinates: coordinates}; var distance = function(a, b) { coordinates[0] = a; coordinates[1] = b; return length$1(object$3); }; var containsGeometryType = { Sphere: function() { return true; }, Point: function(object, point) { return containsPoint(object.coordinates, point); }, MultiPoint: function(object, point) { var coordinates = object.coordinates, i = -1, n = coordinates.length; while (++i < n) if (containsPoint(coordinates[i], point)) return true; return false; }, LineString: function(object, point) { return containsLine(object.coordinates, point); }, MultiLineString: function(object, point) { var coordinates = object.coordinates, i = -1, n = coordinates.length; while (++i < n) if (containsLine(coordinates[i], point)) return true; return false; }, Polygon: function(object, point) { return containsPolygon(object.coordinates, point); }, MultiPolygon: function(object, point) { var coordinates = object.coordinates, i = -1, n = coordinates.length; while (++i < n) if (containsPolygon(coordinates[i], point)) return true; return false; }, GeometryCollection: function(object, point) { var geometries = object.geometries, i = -1, n = geometries.length; while (++i < n) if (containsGeometry(geometries[i], point)) return true; return false; } }; function containsGeometry(geometry, point) { return geometry && containsGeometryType.hasOwnProperty(geometry.type) ? containsGeometryType[geometry.type](geometry, point) : false; } function containsPoint(coordinates, point) { return distance(coordinates, point) === 0; } function containsLine(coordinates, point) { var ab = distance(coordinates[0], coordinates[1]), ao = distance(coordinates[0], point), ob = distance(point, coordinates[1]); return ao + ob <= ab + epsilon$2; } function containsPolygon(coordinates, point) { return !!polygonContains(coordinates.map(ringRadians), pointRadians(point)); } function ringRadians(ring) { return ring = ring.map(pointRadians), ring.pop(), ring; } function pointRadians(point) { return [point[0] * radians, point[1] * radians]; } function graticuleX(y0, y1, dy) { var y = sequence(y0, y1 - epsilon$2, 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$2, dx).concat(x1); return function(y) { return x.map(function(x) { return [x, y]; }); }; } function graticule() { var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5; function graticule() { return {type: "MultiLineString", coordinates: lines()}; } function lines() { return 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$2; }).map(x)) .concat(sequence(ceil(y0 / dy) * dy, y1, dy).filter(function(y) { return abs$1(y % DY) > epsilon$2; }).map(y)); } graticule.lines = function() { return lines().map(function(coordinates) { return {type: "LineString", coordinates: coordinates}; }); }; graticule.outline = function() { return { type: "Polygon", coordinates: [ X(X0).concat( Y(Y1).slice(1), X(X1).reverse().slice(1), Y(Y0).reverse().slice(1)) ] }; }; graticule.extent = function(_) { if (!arguments.length) return graticule.extentMinor(); return graticule.extentMajor(_).extentMinor(_); }; graticule.extentMajor = function(_) { if (!arguments.length) return [[X0, Y0], [X1, Y1]]; X0 = +_[0][0], X1 = +_[1][0]; Y0 = +_[0][1], Y1 = +_[1][1]; if (X0 > X1) _ = X0, X0 = X1, X1 = _; if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _; return graticule.precision(precision); }; graticule.extentMinor = function(_) { if (!arguments.length) return [[x0, y0], [x1, y1]]; x0 = +_[0][0], x1 = +_[1][0]; y0 = +_[0][1], y1 = +_[1][1]; if (x0 > x1) _ = x0, x0 = x1, x1 = _; if (y0 > y1) _ = y0, y0 = y1, y1 = _; return graticule.precision(precision); }; graticule.step = function(_) { if (!arguments.length) return graticule.stepMinor(); return graticule.stepMajor(_).stepMinor(_); }; graticule.stepMajor = function(_) { if (!arguments.length) return [DX, DY]; DX = +_[0], DY = +_[1]; return graticule; }; graticule.stepMinor = function(_) { if (!arguments.length) return [dx, dy]; dx = +_[0], dy = +_[1]; return graticule; }; graticule.precision = function(_) { if (!arguments.length) return precision; precision = +_; x = graticuleX(y0, y1, 90); y = graticuleY(x0, x1, precision); X = graticuleX(Y0, Y1, 90); Y = graticuleY(X0, X1, precision); return graticule; }; return graticule .extentMajor([[-180, -90 + epsilon$2], [180, 90 - epsilon$2]]) .extentMinor([[-180, -80 - epsilon$2], [180, 80 + epsilon$2]]); } var identity$6 = function(x) { return x; }; var areaSum$1 = adder(); var areaRingSum$1 = adder(); var x00; var y00; var x0$1; var y0$1; var areaStream$1 = { point: noop$5, lineStart: noop$5, lineEnd: noop$5, polygonStart: function() { areaStream$1.lineStart = areaRingStart$1; areaStream$1.lineEnd = areaRingEnd$1; }, polygonEnd: function() { areaStream$1.lineStart = areaStream$1.lineEnd = areaStream$1.point = noop$5; areaSum$1.add(abs$1(areaRingSum$1)); areaRingSum$1.reset(); }, result: function() { var area = areaSum$1 / 2; areaSum$1.reset(); return area; } }; function areaRingStart$1() { areaStream$1.point = areaPointFirst$1; } function areaPointFirst$1(x, y) { areaStream$1.point = areaPoint$1; x00 = x0$1 = x, y00 = y0$1 = y; } function areaPoint$1(x, y) { areaRingSum$1.add(y0$1 * x - x0$1 * y); x0$1 = x, y0$1 = y; } function areaRingEnd$1() { areaPoint$1(x00, y00); } var x0$2 = Infinity; var y0$2 = x0$2; var x1 = -x0$2; var y1 = x1; var boundsStream$1 = { point: boundsPoint$1, lineStart: noop$5, lineEnd: noop$5, polygonStart: noop$5, polygonEnd: noop$5, result: function() { var bounds = [[x0$2, y0$2], [x1, y1]]; x1 = y1 = -(y0$2 = x0$2 = Infinity); return bounds; } }; function boundsPoint$1(x, y) { if (x < x0$2) x0$2 = x; if (x > x1) x1 = x; if (y < y0$2) y0$2 = y; if (y > y1) y1 = y; } // TODO Enforce positive area for exterior, negative area for interior? var X0$1 = 0; var Y0$1 = 0; var Z0$1 = 0; var X1$1 = 0; var Y1$1 = 0; var Z1$1 = 0; var X2$1 = 0; var Y2$1 = 0; var Z2$1 = 0; var x00$1; var y00$1; var x0$3; var y0$3; var centroidStream$1 = { point: centroidPoint$1, lineStart: centroidLineStart$1, lineEnd: centroidLineEnd$1, polygonStart: function() { centroidStream$1.lineStart = centroidRingStart$1; centroidStream$1.lineEnd = centroidRingEnd$1; }, polygonEnd: function() { centroidStream$1.point = centroidPoint$1; centroidStream$1.lineStart = centroidLineStart$1; centroidStream$1.lineEnd = centroidLineEnd$1; }, result: function() { var centroid = Z2$1 ? [X2$1 / Z2$1, Y2$1 / Z2$1] : Z1$1 ? [X1$1 / Z1$1, Y1$1 / Z1$1] : Z0$1 ? [X0$1 / Z0$1, Y0$1 / Z0$1] : [NaN, NaN]; X0$1 = Y0$1 = Z0$1 = X1$1 = Y1$1 = Z1$1 = X2$1 = Y2$1 = Z2$1 = 0; return centroid; } }; function centroidPoint$1(x, y) { X0$1 += x; Y0$1 += y; ++Z0$1; } function centroidLineStart$1() { centroidStream$1.point = centroidPointFirstLine; } function centroidPointFirstLine(x, y) { centroidStream$1.point = centroidPointLine; centroidPoint$1(x0$3 = x, y0$3 = y); } function centroidPointLine(x, y) { var dx = x - x0$3, dy = y - y0$3, z = sqrt$2(dx * dx + dy * dy); X1$1 += z * (x0$3 + x) / 2; Y1$1 += z * (y0$3 + y) / 2; Z1$1 += z; centroidPoint$1(x0$3 = x, y0$3 = y); } function centroidLineEnd$1() { centroidStream$1.point = centroidPoint$1; } function centroidRingStart$1() { centroidStream$1.point = centroidPointFirstRing; } function centroidRingEnd$1() { centroidPointRing(x00$1, y00$1); } function centroidPointFirstRing(x, y) { centroidStream$1.point = centroidPointRing; centroidPoint$1(x00$1 = x0$3 = x, y00$1 = y0$3 = y); } function centroidPointRing(x, y) { var dx = x - x0$3, dy = y - y0$3, z = sqrt$2(dx * dx + dy * dy); X1$1 += z * (x0$3 + x) / 2; Y1$1 += z * (y0$3 + y) / 2; Z1$1 += z; z = y0$3 * x - x0$3 * y; X2$1 += z * (x0$3 + x); Y2$1 += z * (y0$3 + y); Z2$1 += z * 3; centroidPoint$1(x0$3 = x, y0$3 = y); } function PathContext(context) { this._context = context; } PathContext.prototype = { _radius: 4.5, pointRadius: function(_) { return this._radius = _, this; }, polygonStart: function() { this._line = 0; }, polygonEnd: function() { this._line = NaN; }, lineStart: function() { this._point = 0; }, lineEnd: function() { if (this._line === 0) this._context.closePath(); this._point = NaN; }, point: function(x, y) { switch (this._point) { case 0: { this._context.moveTo(x, y); this._point = 1; break; } case 1: { this._context.lineTo(x, y); break; } default: { this._context.moveTo(x + this._radius, y); this._context.arc(x, y, this._radius, 0, tau$4); break; } } }, result: noop$5 }; var lengthSum$1 = adder(); var lengthRing; var x00$2; var y00$2; var x0$4; var y0$4; var lengthStream$1 = { point: noop$5, lineStart: function() { lengthStream$1.point = lengthPointFirst$1; }, lineEnd: function() { if (lengthRing) lengthPoint$1(x00$2, y00$2); lengthStream$1.point = noop$5; }, polygonStart: function() { lengthRing = true; }, polygonEnd: function() { lengthRing = null; }, result: function() { var length = +lengthSum$1; lengthSum$1.reset(); return length; } }; function lengthPointFirst$1(x, y) { lengthStream$1.point = lengthPoint$1; x00$2 = x0$4 = x, y00$2 = y0$4 = y; } function lengthPoint$1(x, y) { x0$4 -= x, y0$4 -= y; lengthSum$1.add(sqrt$2(x0$4 * x0$4 + y0$4 * y0$4)); x0$4 = x, y0$4 = y; } function PathString() { this._string = []; } PathString.prototype = { _radius: 4.5, _circle: circle$2(4.5), pointRadius: function(_) { if ((_ = +_) !== this._radius) this._radius = _, this._circle = null; return this; }, polygonStart: function() { this._line = 0; }, polygonEnd: function() { this._line = NaN; }, lineStart: function() { this._point = 0; }, lineEnd: function() { if (this._line === 0) this._string.push("Z"); this._point = NaN; }, point: function(x, y) { switch (this._point) { case 0: { this._string.push("M", x, ",", y); this._point = 1; break; } case 1: { this._string.push("L", x, ",", y); break; } default: { if (this._circle == null) this._circle = circle$2(this._radius); this._string.push("M", x, ",", y, this._circle); break; } } }, result: function() { if (this._string.length) { var result = this._string.join(""); this._string = []; return result; } else { return null; } } }; function circle$2(radius) { return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z"; } var geoPath = function(projection, context) { var pointRadius = 4.5, projectionStream, contextStream; function path(object) { if (object) { if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments)); geoStream(object, projectionStream(contextStream)); } return contextStream.result(); } path.area = function(object) { geoStream(object, projectionStream(areaStream$1)); return areaStream$1.result(); }; path.measure = function(object) { geoStream(object, projectionStream(lengthStream$1)); return lengthStream$1.result(); }; path.bounds = function(object) { geoStream(object, projectionStream(boundsStream$1)); return boundsStream$1.result(); }; path.centroid = function(object) { geoStream(object, projectionStream(centroidStream$1)); return centroidStream$1.result(); }; path.projection = function(_) { return arguments.length ? (projectionStream = _ == null ? (projection = null, identity$6) : (projection = _).stream, path) : projection; }; path.context = function(_) { if (!arguments.length) return context; contextStream = _ == null ? (context = null, new PathString) : new PathContext(context = _); if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius); return path; }; path.pointRadius = function(_) { if (!arguments.length) return pointRadius; pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_); return path; }; return path.projection(projection).context(context); }; var clip$2 = function(pointVisible, clipLine, interpolate, start) { return function(rotate, sink) { var line = clipLine(sink), rotatedStart = rotate.invert(start[0], start[1]), ringBuffer = clipBuffer(), ringSink = clipLine(ringBuffer), polygonStarted = false, polygon, segments, ring; var clip = { point: point, lineStart: lineStart, lineEnd: lineEnd, polygonStart: function() { clip.point = pointRing; clip.lineStart = ringStart; clip.lineEnd = ringEnd; segments = []; polygon = []; }, polygonEnd: function() { clip.point = point; clip.lineStart = lineStart; clip.lineEnd = lineEnd; segments = merge$2(segments); var startInside = polygonContains(polygon, rotatedStart); if (segments.length) { if (!polygonStarted) sink.polygonStart(), polygonStarted = true; clipPolygon(segments, compareIntersection, startInside, interpolate, sink); } else if (startInside) { if (!polygonStarted) sink.polygonStart(), polygonStarted = true; sink.lineStart(); interpolate(null, null, 1, sink); sink.lineEnd(); } if (polygonStarted) sink.polygonEnd(), polygonStarted = false; segments = polygon = null; }, sphere: function() { sink.polygonStart(); sink.lineStart(); interpolate(null, null, 1, sink); sink.lineEnd(); sink.polygonEnd(); } }; function point(lambda, phi) { var point = rotate(lambda, phi); if (pointVisible(lambda = point[0], phi = point[1])) sink.point(lambda, phi); } function pointLine(lambda, phi) { var point = rotate(lambda, phi); line.point(point[0], point[1]); } function lineStart() { clip.point = pointLine; line.lineStart(); } function lineEnd() { clip.point = point; line.lineEnd(); } function pointRing(lambda, phi) { ring.push([lambda, phi]); var point = rotate(lambda, phi); ringSink.point(point[0], point[1]); } function ringStart() { ringSink.lineStart(); ring = []; } function ringEnd() { pointRing(ring[0][0], ring[0][1]); ringSink.lineEnd(); var clean = ringSink.clean(), ringSegments = ringBuffer.result(), i, n = ringSegments.length, m, segment, point; ring.pop(); polygon.push(ring); ring = null; if (!n) return; // No intersections. if (clean & 1) { segment = ringSegments[0]; if ((m = segment.length - 1) > 0) { if (!polygonStarted) sink.polygonStart(), polygonStarted = true; sink.lineStart(); for (i = 0; i < m; ++i) sink.point((point = segment[i])[0], point[1]); sink.lineEnd(); } return; } // Rejoin connected segments. // TODO reuse ringBuffer.rejoin()? if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift())); segments.push(ringSegments.filter(validSegment)); } return clip; }; }; function validSegment(segment) { return segment.length > 1; } // Intersections are sorted along the clip edge. For both antimeridian cutting // and circle clipping, the same comparison is used. function compareIntersection(a, b) { return ((a = a.x)[0] < 0 ? a[1] - halfPi$2 - epsilon$2 : halfPi$2 - a[1]) - ((b = b.x)[0] < 0 ? b[1] - halfPi$2 - epsilon$2 : halfPi$2 - b[1]); } var clipAntimeridian = clip$2( function() { return true; }, clipAntimeridianLine, clipAntimeridianInterpolate, [-pi$3, -halfPi$2] ); // Takes a line and cuts into visible segments. Return values: 0 - there were // intersections or the line was empty; 1 - no intersections; 2 - there were // intersections, and the first and last segments should be rejoined. function clipAntimeridianLine(stream) { var lambda0 = NaN, phi0 = NaN, sign0 = NaN, clean; // no intersections return { lineStart: function() { stream.lineStart(); clean = 1; }, point: function(lambda1, phi1) { var sign1 = lambda1 > 0 ? pi$3 : -pi$3, delta = abs$1(lambda1 - lambda0); if (abs$1(delta - pi$3) < epsilon$2) { // line crosses a pole stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi$2 : -halfPi$2); stream.point(sign0, phi0); stream.lineEnd(); stream.lineStart(); stream.point(sign1, phi0); stream.point(lambda1, phi0); clean = 0; } else if (sign0 !== sign1 && delta >= pi$3) { // line crosses antimeridian if (abs$1(lambda0 - sign0) < epsilon$2) lambda0 -= sign0 * epsilon$2; // handle degeneracies if (abs$1(lambda1 - sign1) < epsilon$2) lambda1 -= sign1 * epsilon$2; phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1); stream.point(sign0, phi0); stream.lineEnd(); stream.lineStart(); stream.point(sign1, phi0); clean = 0; } stream.point(lambda0 = lambda1, phi0 = phi1); sign0 = sign1; }, lineEnd: function() { stream.lineEnd(); lambda0 = phi0 = NaN; }, clean: function() { return 2 - clean; // if intersections, rejoin first and last segments } }; } function clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1) { var cosPhi0, cosPhi1, sinLambda0Lambda1 = sin$1(lambda0 - lambda1); return abs$1(sinLambda0Lambda1) > epsilon$2 ? atan((sin$1(phi0) * (cosPhi1 = cos$1(phi1)) * sin$1(lambda1) - sin$1(phi1) * (cosPhi0 = cos$1(phi0)) * sin$1(lambda0)) / (cosPhi0 * cosPhi1 * sinLambda0Lambda1)) : (phi0 + phi1) / 2; } function clipAntimeridianInterpolate(from, to, direction, stream) { var phi; if (from == null) { phi = direction * halfPi$2; stream.point(-pi$3, phi); stream.point(0, phi); stream.point(pi$3, phi); stream.point(pi$3, 0); stream.point(pi$3, -phi); stream.point(0, -phi); stream.point(-pi$3, -phi); stream.point(-pi$3, 0); stream.point(-pi$3, phi); } else if (abs$1(from[0] - to[0]) > epsilon$2) { var lambda = from[0] < to[0] ? pi$3 : -pi$3; phi = direction * lambda / 2; stream.point(-lambda, phi); stream.point(0, phi); stream.point(lambda, phi); } else { stream.point(to[0], to[1]); } } var clipCircle = function(radius, delta) { var cr = cos$1(radius), smallRadius = cr > 0, notHemisphere = abs$1(cr) > epsilon$2; // TODO optimise for this common case function interpolate(from, to, direction, stream) { circleStream(stream, radius, delta, direction, from, to); } function visible(lambda, phi) { return cos$1(lambda) * cos$1(phi) > cr; } // Takes a line and cuts into visible segments. Return values used for polygon // clipping: 0 - there were intersections or the line was empty; 1 - no // intersections 2 - there were intersections, and the first and last segments // should be rejoined. function clipLine(stream) { var point0, // previous point c0, // code for previous point v0, // visibility of previous point v00, // visibility of first point clean; // no intersections return { lineStart: function() { v00 = v0 = false; clean = 1; }, point: function(lambda, phi) { var point1 = [lambda, phi], point2, v = visible(lambda, phi), c = smallRadius ? v ? 0 : code(lambda, phi) : v ? code(lambda + (lambda < 0 ? pi$3 : -pi$3), phi) : 0; if (!point0 && (v00 = v0 = v)) stream.lineStart(); // Handle degeneracies. // TODO ignore if not clipping polygons. if (v !== v0) { point2 = intersect(point0, point1); if (!point2 || pointEqual(point0, point2) || pointEqual(point1, point2)) { point1[0] += epsilon$2; point1[1] += epsilon$2; v = visible(point1[0], point1[1]); } } if (v !== v0) { clean = 0; if (v) { // outside going in stream.lineStart(); point2 = intersect(point1, point0); stream.point(point2[0], point2[1]); } else { // inside going out point2 = intersect(point0, point1); stream.point(point2[0], point2[1]); stream.lineEnd(); } point0 = point2; } else if (notHemisphere && point0 && smallRadius ^ v) { var t; // If the codes for two points are different, or are both zero, // and there this segment intersects with the small circle. if (!(c & c0) && (t = intersect(point1, point0, true))) { clean = 0; if (smallRadius) { stream.lineStart(); stream.point(t[0][0], t[0][1]); stream.point(t[1][0], t[1][1]); stream.lineEnd(); } else { stream.point(t[1][0], t[1][1]); stream.lineEnd(); stream.lineStart(); stream.point(t[0][0], t[0][1]); } } } if (v && (!point0 || !pointEqual(point0, point1))) { stream.point(point1[0], point1[1]); } point0 = point1, v0 = v, c0 = c; }, lineEnd: function() { if (v0) stream.lineEnd(); point0 = null; }, // Rejoin first and last segments if there were intersections and the first // and last points were visible. clean: function() { return clean | ((v00 && v0) << 1); } }; } // Intersects the great circle between a and b with the clip circle. function intersect(a, b, two) { var pa = cartesian(a), pb = cartesian(b); // We have two planes, n1.p = d1 and n2.p = d2. // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2). var n1 = [1, 0, 0], // normal n2 = cartesianCross(pa, pb), n2n2 = cartesianDot(n2, n2), n1n2 = n2[0], // cartesianDot(n1, n2), determinant = n2n2 - n1n2 * n1n2; // Two polar points. if (!determinant) return !two && a; var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = cartesianCross(n1, n2), A = cartesianScale(n1, c1), B = cartesianScale(n2, c2); cartesianAddInPlace(A, B); // Solve |p(t)|^2 = 1. var u = n1xn2, w = cartesianDot(A, u), uu = cartesianDot(u, u), t2 = w * w - uu * (cartesianDot(A, A) - 1); if (t2 < 0) return; var t = sqrt$2(t2), q = cartesianScale(u, (-w - t) / uu); cartesianAddInPlace(q, A); q = spherical(q); if (!two) return q; // Two intersection points. var lambda0 = a[0], lambda1 = b[0], phi0 = a[1], phi1 = b[1], z; if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z; var delta = lambda1 - lambda0, polar = abs$1(delta - pi$3) < epsilon$2, meridian = polar || delta < epsilon$2; if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z; // Check that the first point is between a and b. if (meridian ? polar ? phi0 + phi1 > 0 ^ q[1] < (abs$1(q[0] - lambda0) < epsilon$2 ? phi0 : phi1) : phi0 <= q[1] && q[1] <= phi1 : delta > pi$3 ^ (lambda0 <= q[0] && q[0] <= lambda1)) { var q1 = cartesianScale(u, (-w + t) / uu); cartesianAddInPlace(q1, A); return [q, spherical(q1)]; } } // Generates a 4-bit vector representing the location of a point relative to // the small circle's bounding box. function code(lambda, phi) { var r = smallRadius ? radius : pi$3 - radius, code = 0; if (lambda < -r) code |= 1; // left else if (lambda > r) code |= 2; // right if (phi < -r) code |= 4; // below else if (phi > r) code |= 8; // above return code; } return clip$2(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi$3, radius - pi$3]); }; function transformer(methods) { return function(stream) { var s = new TransformStream; for (var key in methods) s[key] = methods[key]; s.stream = stream; return s; }; } function TransformStream() {} TransformStream.prototype = { constructor: TransformStream, point: function(x, y) { this.stream.point(x, y); }, sphere: function() { this.stream.sphere(); }, lineStart: function() { this.stream.lineStart(); }, lineEnd: function() { this.stream.lineEnd(); }, polygonStart: function() { this.stream.polygonStart(); }, polygonEnd: function() { this.stream.polygonEnd(); } }; function fitExtent(projection, extent, object) { var w = extent[1][0] - extent[0][0], h = extent[1][1] - extent[0][1], clip = projection.clipExtent && projection.clipExtent(); projection .scale(150) .translate([0, 0]); if (clip != null) projection.clipExtent(null); geoStream(object, projection.stream(boundsStream$1)); var b = boundsStream$1.result(), k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1])), x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2, y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2; if (clip != null) projection.clipExtent(clip); return projection .scale(k * 150) .translate([x, y]); } function fitSize(projection, size, object) { return fitExtent(projection, [[0, 0], size], object); } var maxDepth = 16; var cosMinDistance = cos$1(30 * radians); // cos(minimum angular distance) var resample = function(project, delta2) { return +delta2 ? resample$1(project, delta2) : resampleNone(project); }; function resampleNone(project) { return transformer({ point: function(x, y) { x = project(x, y); this.stream.point(x[0], x[1]); } }); } function resample$1(project, delta2) { function resampleLineTo(x0, y0, lambda0, a0, b0, c0, x1, y1, lambda1, a1, b1, c1, depth, stream) { var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy; if (d2 > 4 * delta2 && depth--) { var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = sqrt$2(a * a + b * b + c * c), phi2 = asin$1(c /= m), lambda2 = abs$1(abs$1(c) - 1) < epsilon$2 || abs$1(lambda0 - lambda1) < epsilon$2 ? (lambda0 + lambda1) / 2 : atan2$1(b, a), p = project(lambda2, phi2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 - y0, dz = dy * dx2 - dx * dy2; if (dz * dz / d2 > delta2 // perpendicular projected distance || abs$1((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { // angular distance resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream); stream.point(x2, y2); resampleLineTo(x2, y2, lambda2, a, b, c, x1, y1, lambda1, a1, b1, c1, depth, stream); } } } return function(stream) { var lambda00, x00, y00, a00, b00, c00, // first point lambda0, x0, y0, a0, b0, c0; // previous point var resampleStream = { point: point, lineStart: lineStart, lineEnd: lineEnd, polygonStart: function() { stream.polygonStart(); resampleStream.lineStart = ringStart; }, polygonEnd: function() { stream.polygonEnd(); resampleStream.lineStart = lineStart; } }; function point(x, y) { x = project(x, y); stream.point(x[0], x[1]); } function lineStart() { x0 = NaN; resampleStream.point = linePoint; stream.lineStart(); } function linePoint(lambda, phi) { var c = cartesian([lambda, phi]), p = project(lambda, phi); resampleLineTo(x0, y0, lambda0, a0, b0, c0, x0 = p[0], y0 = p[1], lambda0 = lambda, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream); stream.point(x0, y0); } function lineEnd() { resampleStream.point = point; stream.lineEnd(); } function ringStart() { lineStart(); resampleStream.point = ringPoint; resampleStream.lineEnd = ringEnd; } function ringPoint(lambda, phi) { linePoint(lambda00 = lambda, phi), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0; resampleStream.point = linePoint; } function ringEnd() { resampleLineTo(x0, y0, lambda0, a0, b0, c0, x00, y00, lambda00, a00, b00, c00, maxDepth, stream); resampleStream.lineEnd = lineEnd; lineEnd(); } return resampleStream; }; } var transformRadians = transformer({ point: function(x, y) { this.stream.point(x * radians, y * radians); } }); function projection$1(project) { return projectionMutator(function() { return project; })(); } function projectionMutator(projectAt) { var project, k = 150, // scale x = 480, y = 250, // translate dx, dy, lambda = 0, phi = 0, // center deltaLambda = 0, deltaPhi = 0, deltaGamma = 0, rotate, projectRotate, // rotate theta = null, preclip = clipAntimeridian, // clip angle x0 = null, y0, x1, y1, postclip = identity$6, // clip extent delta2 = 0.5, projectResample = resample(projectTransform, delta2), // precision cache, cacheStream; function projection(point) { point = projectRotate(point[0] * radians, point[1] * radians); return [point[0] * k + dx, dy - point[1] * k]; } function invert(point) { point = projectRotate.invert((point[0] - dx) / k, (dy - point[1]) / k); return point && [point[0] * degrees$1, point[1] * degrees$1]; } function projectTransform(x, y) { return x = project(x, y), [x[0] * k + dx, dy - x[1] * k]; } projection.stream = function(stream) { return cache && cacheStream === stream ? cache : cache = transformRadians(preclip(rotate, projectResample(postclip(cacheStream = stream)))); }; projection.clipAngle = function(_) { return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians, 6 * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees$1; }; projection.clipExtent = function(_) { return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$6) : clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]]; }; projection.scale = function(_) { return arguments.length ? (k = +_, recenter()) : k; }; projection.translate = function(_) { return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y]; }; projection.center = function(_) { return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees$1, phi * degrees$1]; }; projection.rotate = function(_) { return arguments.length ? (deltaLambda = _[0] % 360 * radians, deltaPhi = _[1] % 360 * radians, deltaGamma = _.length > 2 ? _[2] % 360 * radians : 0, recenter()) : [deltaLambda * degrees$1, deltaPhi * degrees$1, deltaGamma * degrees$1]; }; projection.precision = function(_) { return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt$2(delta2); }; projection.fitExtent = function(extent, object) { return fitExtent(projection, extent, object); }; projection.fitSize = function(size, object) { return fitSize(projection, size, object); }; function recenter() { projectRotate = compose(rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma), project); var center = project(lambda, phi); dx = x - center[0] * k; dy = y + center[1] * k; return reset(); } function reset() { cache = cacheStream = null; return projection; } return function() { project = projectAt.apply(this, arguments); projection.invert = project.invert && invert; return recenter(); }; } function conicProjection(projectAt) { var phi0 = 0, phi1 = pi$3 / 3, m = projectionMutator(projectAt), p = m(phi0, phi1); p.parallels = function(_) { return arguments.length ? m(phi0 = _[0] * radians, phi1 = _[1] * radians) : [phi0 * degrees$1, phi1 * degrees$1]; }; return p; } function cylindricalEqualAreaRaw(phi0) { var cosPhi0 = cos$1(phi0); function forward(lambda, phi) { return [lambda * cosPhi0, sin$1(phi) / cosPhi0]; } forward.invert = function(x, y) { return [x / cosPhi0, asin$1(y * cosPhi0)]; }; return forward; } function conicEqualAreaRaw(y0, y1) { var sy0 = sin$1(y0), n = (sy0 + sin$1(y1)) / 2; // Are the parallels symmetrical around the Equator? if (abs$1(n) < epsilon$2) return cylindricalEqualAreaRaw(y0); var c = 1 + sy0 * (2 * n - sy0), r0 = sqrt$2(c) / n; function project(x, y) { var r = sqrt$2(c - 2 * n * sin$1(y)) / n; return [r * sin$1(x *= n), r0 - r * cos$1(x)]; } project.invert = function(x, y) { var r0y = r0 - y; return [atan2$1(x, abs$1(r0y)) / n * sign$1(r0y), asin$1((c - (x * x + r0y * r0y) * n * n) / (2 * n))]; }; return project; } var conicEqualArea = function() { return conicProjection(conicEqualAreaRaw) .scale(155.424) .center([0, 33.6442]); }; var albers = function() { return conicEqualArea() .parallels([29.5, 45.5]) .scale(1070) .translate([480, 250]) .rotate([96, 0]) .center([-0.6, 38.7]); }; // The projections must have mutually exclusive clip regions on the sphere, // as this will avoid emitting interleaving lines and polygons. function multiplex(streams) { var n = streams.length; return { point: function(x, y) { var i = -1; while (++i < n) streams[i].point(x, y); }, sphere: function() { var i = -1; while (++i < n) streams[i].sphere(); }, lineStart: function() { var i = -1; while (++i < n) streams[i].lineStart(); }, lineEnd: function() { var i = -1; while (++i < n) streams[i].lineEnd(); }, polygonStart: function() { var i = -1; while (++i < n) streams[i].polygonStart(); }, polygonEnd: function() { var i = -1; while (++i < n) streams[i].polygonEnd(); } }; } // A composite projection for the United States, configured by default for // 960×500. The projection also works quite well at 960×600 if you change the // scale to 1285 and adjust the translate accordingly. The set of standard // parallels for each region comes from USGS, which is published here: // http://egsc.usgs.gov/isb/pubs/MapProjections/projections.html#albers var geoAlbersUsa = function() { var cache, cacheStream, lower48 = albers(), lower48Point, alaska = conicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]), alaskaPoint, // EPSG:3338 hawaii = conicEqualArea().rotate([157, 0]).center([-3, 19.9]).parallels([8, 18]), hawaiiPoint, // ESRI:102007 point, pointStream = {point: function(x, y) { point = [x, y]; }}; function albersUsa(coordinates) { var x = coordinates[0], y = coordinates[1]; return point = null, (lower48Point.point(x, y), point) || (alaskaPoint.point(x, y), point) || (hawaiiPoint.point(x, y), point); } albersUsa.invert = function(coordinates) { var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k, y = (coordinates[1] - t[1]) / k; return (y >= 0.120 && y < 0.234 && x >= -0.425 && x < -0.214 ? alaska : y >= 0.166 && y < 0.234 && x >= -0.214 && x < -0.115 ? hawaii : lower48).invert(coordinates); }; albersUsa.stream = function(stream) { return cache && cacheStream === stream ? cache : cache = multiplex([lower48.stream(cacheStream = stream), alaska.stream(stream), hawaii.stream(stream)]); }; albersUsa.precision = function(_) { if (!arguments.length) return lower48.precision(); lower48.precision(_), alaska.precision(_), hawaii.precision(_); return reset(); }; albersUsa.scale = function(_) { if (!arguments.length) return lower48.scale(); lower48.scale(_), alaska.scale(_ * 0.35), hawaii.scale(_); return albersUsa.translate(lower48.translate()); }; albersUsa.translate = function(_) { if (!arguments.length) return lower48.translate(); var k = lower48.scale(), x = +_[0], y = +_[1]; lower48Point = lower48 .translate(_) .clipExtent([[x - 0.455 * k, y - 0.238 * k], [x + 0.455 * k, y + 0.238 * k]]) .stream(pointStream); alaskaPoint = alaska .translate([x - 0.307 * k, y + 0.201 * k]) .clipExtent([[x - 0.425 * k + epsilon$2, y + 0.120 * k + epsilon$2], [x - 0.214 * k - epsilon$2, y + 0.234 * k - epsilon$2]]) .stream(pointStream); hawaiiPoint = hawaii .translate([x - 0.205 * k, y + 0.212 * k]) .clipExtent([[x - 0.214 * k + epsilon$2, y + 0.166 * k + epsilon$2], [x - 0.115 * k - epsilon$2, y + 0.234 * k - epsilon$2]]) .stream(pointStream); return reset(); }; albersUsa.fitExtent = function(extent, object) { return fitExtent(albersUsa, extent, object); }; albersUsa.fitSize = function(size, object) { return fitSize(albersUsa, size, object); }; function reset() { cache = cacheStream = null; return albersUsa; } return albersUsa.scale(1070); }; function azimuthalRaw(scale) { return function(x, y) { var cx = cos$1(x), cy = cos$1(y), k = scale(cx * cy); return [ k * cy * sin$1(x), k * sin$1(y) ]; } } function azimuthalInvert(angle) { return function(x, y) { var z = sqrt$2(x * x + y * y), c = angle(z), sc = sin$1(c), cc = cos$1(c); return [ atan2$1(x * sc, z * cc), asin$1(z && y * sc / z) ]; } } var azimuthalEqualAreaRaw = azimuthalRaw(function(cxcy) { return sqrt$2(2 / (1 + cxcy)); }); azimuthalEqualAreaRaw.invert = azimuthalInvert(function(z) { return 2 * asin$1(z / 2); }); var geoAzimuthalEqualArea = function() { return projection$1(azimuthalEqualAreaRaw) .scale(124.75) .clipAngle(180 - 1e-3); }; var azimuthalEquidistantRaw = azimuthalRaw(function(c) { return (c = acos$1(c)) && c / sin$1(c); }); azimuthalEquidistantRaw.invert = azimuthalInvert(function(z) { return z; }); var geoAzimuthalEquidistant = function() { return projection$1(azimuthalEquidistantRaw) .scale(79.4188) .clipAngle(180 - 1e-3); }; function mercatorRaw(lambda, phi) { return [lambda, log$2(tan((halfPi$2 + phi) / 2))]; } mercatorRaw.invert = function(x, y) { return [x, 2 * atan(exp(y)) - halfPi$2]; }; var geoMercator = function() { return mercatorProjection(mercatorRaw) .scale(961 / tau$4); }; function mercatorProjection(project) { var m = projection$1(project), center = m.center, scale = m.scale, translate = m.translate, clipExtent = m.clipExtent, x0 = null, y0, x1, y1; // clip extent m.scale = function(_) { return arguments.length ? (scale(_), reclip()) : scale(); }; m.translate = function(_) { return arguments.length ? (translate(_), reclip()) : translate(); }; m.center = function(_) { return arguments.length ? (center(_), reclip()) : center(); }; m.clipExtent = function(_) { return arguments.length ? ((_ == null ? x0 = y0 = x1 = y1 = null : (x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1])), reclip()) : x0 == null ? null : [[x0, y0], [x1, y1]]; }; function reclip() { var k = pi$3 * scale(), t = m(rotation(m.rotate()).invert([0, 0])); return clipExtent(x0 == null ? [[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]] : project === mercatorRaw ? [[Math.max(t[0] - k, x0), y0], [Math.min(t[0] + k, x1), y1]] : [[x0, Math.max(t[1] - k, y0)], [x1, Math.min(t[1] + k, y1)]]); } return reclip(); } function tany(y) { return tan((halfPi$2 + y) / 2); } function conicConformalRaw(y0, y1) { var cy0 = cos$1(y0), n = y0 === y1 ? sin$1(y0) : log$2(cy0 / cos$1(y1)) / log$2(tany(y1) / tany(y0)), f = cy0 * pow$1(tany(y0), n) / n; if (!n) return mercatorRaw; function project(x, y) { if (f > 0) { if (y < -halfPi$2 + epsilon$2) y = -halfPi$2 + epsilon$2; } else { if (y > halfPi$2 - epsilon$2) y = halfPi$2 - epsilon$2; } var r = f / pow$1(tany(y), n); return [r * sin$1(n * x), f - r * cos$1(n * x)]; } project.invert = function(x, y) { var fy = f - y, r = sign$1(n) * sqrt$2(x * x + fy * fy); return [atan2$1(x, abs$1(fy)) / n * sign$1(fy), 2 * atan(pow$1(f / r, 1 / n)) - halfPi$2]; }; return project; } var geoConicConformal = function() { return conicProjection(conicConformalRaw) .scale(109.5) .parallels([30, 30]); }; function equirectangularRaw(lambda, phi) { return [lambda, phi]; } equirectangularRaw.invert = equirectangularRaw; var geoEquirectangular = function() { return projection$1(equirectangularRaw) .scale(152.63); }; function conicEquidistantRaw(y0, y1) { var cy0 = cos$1(y0), n = y0 === y1 ? sin$1(y0) : (cy0 - cos$1(y1)) / (y1 - y0), g = cy0 / n + y0; if (abs$1(n) < epsilon$2) return equirectangularRaw; function project(x, y) { var gy = g - y, nx = n * x; return [gy * sin$1(nx), g - gy * cos$1(nx)]; } project.invert = function(x, y) { var gy = g - y; return [atan2$1(x, abs$1(gy)) / n * sign$1(gy), g - sign$1(n) * sqrt$2(x * x + gy * gy)]; }; return project; } var geoConicEquidistant = function() { return conicProjection(conicEquidistantRaw) .scale(131.154) .center([0, 13.9389]); }; function gnomonicRaw(x, y) { var cy = cos$1(y), k = cos$1(x) * cy; return [cy * sin$1(x) / k, sin$1(y) / k]; } gnomonicRaw.invert = azimuthalInvert(atan); var geoGnomonic = function() { return projection$1(gnomonicRaw) .scale(144.049) .clipAngle(60); }; function orthographicRaw(x, y) { return [cos$1(y) * sin$1(x), sin$1(y)]; } orthographicRaw.invert = azimuthalInvert(asin$1); var geoOrthographic = function() { return projection$1(orthographicRaw) .scale(249.5) .clipAngle(90 + epsilon$2); }; function stereographicRaw(x, y) { var cy = cos$1(y), k = 1 + cos$1(x) * cy; return [cy * sin$1(x) / k, sin$1(y) / k]; } stereographicRaw.invert = azimuthalInvert(function(z) { return 2 * atan(z); }); var geoStereographic = function() { return projection$1(stereographicRaw) .scale(250) .clipAngle(142); }; function transverseMercatorRaw(lambda, phi) { return [log$2(tan((halfPi$2 + phi) / 2)), -lambda]; } transverseMercatorRaw.invert = function(x, y) { return [-y, 2 * atan(exp(x)) - halfPi$2]; }; var geoTransverseMercator = function() { var m = mercatorProjection(transverseMercatorRaw), center = m.center, rotate = m.rotate; m.center = function(_) { return arguments.length ? center([-_[1], _[0]]) : (_ = center(), [_[1], -_[0]]); }; m.rotate = function(_) { return arguments.length ? rotate([_[0], _[1], _.length > 2 ? _[2] + 90 : 90]) : (_ = rotate(), [_[0], _[1], _[2] - 90]); }; return rotate([0, 0, 90]) .scale(159.155); }; var defaultPath = geoPath(); var projectionProperties = [ // standard properties in d3-geo 'clipAngle', 'clipExtent', 'scale', 'translate', 'center', 'rotate', 'parallels', 'precision', // extended properties in d3-geo-projections 'coefficient', 'distance', 'fraction', 'lobes', 'parallel', 'radius', 'ratio', 'spacing', 'tilt' ]; /** * Augment projections with their type and a copy method. */ function create$1(type, constructor) { return function projection$$1() { var p = constructor(); p.type = type; p.path = geoPath().projection(p); p.copy = p.copy || function() { var c = projection$$1(); projectionProperties.forEach(function(prop) { if (p.hasOwnProperty(prop)) c[prop](p[prop]()); }); c.path.pointRadius(p.path.pointRadius()); return c; }; return p; }; } function projection$$1(type, proj) { if (arguments.length > 1) { projections[type] = create$1(type, proj); return this; } else { return projections.hasOwnProperty(type) ? projections[type] : null; } } function getProjectionPath(proj) { return (proj && proj.path) || defaultPath; } var projections = { // base d3-geo projection types albers: albers, albersusa: geoAlbersUsa, azimuthalequalarea: geoAzimuthalEqualArea, azimuthalequidistant: geoAzimuthalEquidistant, conicconformal: geoConicConformal, conicequalarea: conicEqualArea, conicequidistant: geoConicEquidistant, equirectangular: geoEquirectangular, gnomonic: geoGnomonic, mercator: geoMercator, orthographic: geoOrthographic, stereographic: geoStereographic, transversemercator: geoTransverseMercator }; for (var key$2 in projections) { projection$$1(key$2, projections[key$2]); } /** * Map GeoJSON data to an SVG path string. * @constructor * @param {object} params - The parameters for this operator. * @param {function(number, number): *} params.projection - The cartographic * projection to apply. * @param {function(object): *} [params.field] - The field with GeoJSON data, * or null if the tuple itself is a GeoJSON feature. * @param {string} [params.as='path'] - The output field in which to store * the generated path data (default 'path'). */ function GeoPath(params) { Transform.call(this, null, params); } GeoPath.Definition = { "type": "GeoPath", "metadata": {"modifies": true}, "params": [ { "name": "projection", "type": "projection" }, { "name": "field", "type": "field" }, { "name": "as", "type": "string", "default": "path" } ] }; var prototype$62 = inherits(GeoPath, Transform); prototype$62.transform = function(_, pulse) { var out = pulse.fork(pulse.ALL), path = this.value, field$$1 = _.field || identity, as = _.as || 'path', mod; function set(t) { t[as] = path(field$$1(t)); } if (!path || _.modified()) { // parameters updated, reset and reflow this.value = path = getProjectionPath(_.projection).context(null); out.materialize().reflow().visit(out.SOURCE, set); } else { path.context(null); mod = field$$1 === identity || pulse.modified(field$$1.fields); out.visit(mod ? out.ADD_MOD : out.ADD, set); } return out.modifies(as); }; /** * Geo-code a longitude/latitude point to an x/y coordinate. * @constructor * @param {object} params - The parameters for this operator. * @param {function(number, number): *} params.projection - The cartographic * projection to apply. * @param {Array} params.fields - A two-element array of * field accessors for the longitude and latitude values. * @param {Array} [params.as] - A two-element array of field names * under which to store the result. Defaults to ['x','y']. */ function GeoPoint(params) { Transform.call(this, null, params); } GeoPoint.Definition = { "type": "GeoPoint", "metadata": {"modifies": true}, "params": [ { "name": "projection", "type": "projection", "required": true }, { "name": "fields", "type": "field", "array": true, "required": true, "length": 2 }, { "name": "as", "type": "string", "array": true, "length": 2, "default": ["x", "y"] } ] }; var prototype$63 = inherits(GeoPoint, Transform); prototype$63.transform = function(_, pulse) { var proj = _.projection, lon = _.fields[0], lat = _.fields[1], as = _.as || ['x', 'y'], x = as[0], y = as[1], mod; function set(t) { var xy = proj([lon(t), lat(t)]); if (xy) { t[x] = xy[0]; t[y] = xy[1]; } else { t[x] = undefined; t[y] = undefined; } } if (_.modified()) { // parameters updated, reflow pulse = pulse.materialize().reflow(true).visit(pulse.SOURCE, set); } else { mod = pulse.modified(lon.fields) || pulse.modified(lat.fields); pulse.visit(mod ? pulse.ADD_MOD : pulse.ADD, set); } return pulse.modifies(as); }; /** * Annotate items with a geopath shape generator. * @constructor * @param {object} params - The parameters for this operator. * @param {function(number, number): *} params.projection - The cartographic * projection to apply. * @param {function(object): *} [params.field] - The field with GeoJSON data, * or null if the tuple itself is a GeoJSON feature. * @param {string} [params.as='shape'] - The output field in which to store * the generated path data (default 'shape'). */ function GeoShape(params) { Transform.call(this, null, params); } GeoShape.Definition = { "type": "GeoShape", "metadata": {"modifies": true}, "params": [ { "name": "projection", "type": "projection" }, { "name": "field", "type": "field", "default": "datum" }, { "name": "as", "type": "string", "default": "shape" } ] }; var prototype$64 = inherits(GeoShape, Transform); prototype$64.transform = function(_, pulse) { var out = pulse.fork(pulse.ALL), shape = this.value, datum = _.field || field('datum'), as = _.as || 'shape', flag = out.ADD_MOD; if (!shape || _.modified()) { // parameters updated, reset and reflow this.value = shape = shapeGenerator( getProjectionPath(_.projection), datum); out.materialize().reflow(); flag = out.SOURCE; } out.visit(flag, function(t) { t[as] = shape; }); return out.modifies(as); }; function shapeGenerator(path, field$$1) { var shape = function(_) { return path(field$$1(_)); }; shape.context = function(_) { path.context(_); return shape; }; return shape; } /** * GeoJSON feature generator for creating graticules. * @constructor */ function Graticule(params) { Transform.call(this, [], params); this.generator = graticule(); } Graticule.Definition = { "type": "Graticule", "metadata": {"source": true, "generates": true, "changes": true}, "params": [ { "name": "extent", "type": "array", "array": true, "length": 2, "content": {"type": "number", "array": true, "length": 2} }, { "name": "extentMajor", "type": "array", "array": true, "length": 2, "content": {"type": "number", "array": true, "length": 2} }, { "name": "extentMinor", "type": "array", "array": true, "length": 2, "content": {"type": "number", "array": true, "length": 2} }, { "name": "step", "type": "number", "array": true, "length": 2 }, { "name": "stepMajor", "type": "number", "array": true, "length": 2, "default": [90, 360] }, { "name": "stepMinor", "type": "number", "array": true, "length": 2, "default": [10, 10] }, { "name": "precision", "type": "number", "default": 2.5 } ] }; var prototype$65 = inherits(Graticule, Transform); prototype$65.transform = function(_, pulse) { var out = pulse.fork(), src = this.value, gen = this.generator, t; if (!src.length || _.modified()) { for (var prop in _) { if (isFunction(gen[prop])) { gen[prop](_[prop]); } } } t = gen(); if (src.length) { out.mod.push(replace(src[0], t)); } else { out.add.push(ingest(t)); } src[0] = t; out.source = src; return out; }; /** * Maintains a cartographic projection. * @constructor * @param {object} params - The parameters for this operator. */ function Projection(params) { Transform.call(this, null, params); this.modified(true); // always treat as modified } var prototype$66 = inherits(Projection, Transform); prototype$66.transform = function(_, pulse) { var proj = this.value; if (!proj || _.modified('type')) { this.value = (proj = create$2(_.type)); projectionProperties.forEach(function(prop) { if (_[prop] != null) set$4(proj, prop, _[prop]); }); } else { projectionProperties.forEach(function(prop) { if (_.modified(prop)) set$4(proj, prop, _[prop]); }); } if (_.pointRadius != null) proj.path.pointRadius(_.pointRadius); if (_.fit) fit(proj, _); return pulse.fork(pulse.NO_SOURCE | pulse.NO_FIELDS); }; function fit(proj, _) { var data = collectGeoJSON(_.fit); _.extent ? proj.fitExtent(_.extent, data) : _.size ? proj.fitSize(_.size, data) : 0; } function create$2(type) { var constructor = projection$$1((type || 'mercator').toLowerCase()); if (!constructor) error$1('Unrecognized projection type: ' + type); return constructor(); } function set$4(proj, key$$1, value) { if (isFunction(proj[key$$1])) proj[key$$1](value); } function collectGeoJSON(features) { features = array(features); return features.length === 1 ? features[0] : { type: FeatureCollection, features: features.reduce(function(list, f) { (f && f.type === FeatureCollection) ? list.push.apply(list, f.features) : isArray(f) ? list.push.apply(list, f) : list.push(f); return list; }, []) }; } var geo = Object.freeze({ contour: Contour, geojson: GeoJSON, geopath: GeoPath, geopoint: GeoPoint, geoshape: GeoShape, graticule: Graticule, projection: Projection }); var forceCenter = function(x, y) { var nodes; if (x == null) x = 0; if (y == null) y = 0; function force() { var i, n = nodes.length, node, sx = 0, sy = 0; for (i = 0; i < n; ++i) { node = nodes[i], sx += node.x, sy += node.y; } for (sx = sx / n - x, sy = sy / n - y, i = 0; i < n; ++i) { node = nodes[i], node.x -= sx, node.y -= sy; } } force.initialize = function(_) { nodes = _; }; force.x = function(_) { return arguments.length ? (x = +_, force) : x; }; force.y = function(_) { return arguments.length ? (y = +_, force) : y; }; return force; }; var constant$8 = function(x) { return function() { return x; }; }; var jiggle = function() { return (Math.random() - 0.5) * 1e-6; }; var tree_add = function(d) { var x = +this._x.call(null, d), y = +this._y.call(null, d); return add$4(this.cover(x, y), x, y, d); }; function add$4(tree, x, y, d) { if (isNaN(x) || isNaN(y)) return tree; // ignore invalid points var parent, node = tree._root, leaf = {data: d}, x0 = tree._x0, y0 = tree._y0, x1 = tree._x1, y1 = tree._y1, xm, ym, xp, yp, right, bottom, i, j; // If the tree is empty, initialize the root as a leaf. if (!node) return tree._root = leaf, tree; // Find the existing leaf for the new point, or add it. while (node.length) { if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm; if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym; if (parent = node, !(node = node[i = bottom << 1 | right])) return parent[i] = leaf, tree; } // Is the new point is exactly coincident with the existing point? xp = +tree._x.call(null, node.data); yp = +tree._y.call(null, node.data); if (x === xp && y === yp) return leaf.next = node, parent ? parent[i] = leaf : tree._root = leaf, tree; // Otherwise, split the leaf node until the old and new point are separated. do { parent = parent ? parent[i] = new Array(4) : tree._root = new Array(4); if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm; if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym; } while ((i = bottom << 1 | right) === (j = (yp >= ym) << 1 | (xp >= xm))); return parent[j] = node, parent[i] = leaf, tree; } function addAll$1(data) { var d, i, n = data.length, x, y, xz = new Array(n), yz = new Array(n), x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity; // Compute the points and their extent. for (i = 0; i < n; ++i) { if (isNaN(x = +this._x.call(null, d = data[i])) || isNaN(y = +this._y.call(null, d))) continue; xz[i] = x; yz[i] = y; if (x < x0) x0 = x; if (x > x1) x1 = x; if (y < y0) y0 = y; if (y > y1) y1 = y; } // If there were no (valid) points, inherit the existing extent. if (x1 < x0) x0 = this._x0, x1 = this._x1; if (y1 < y0) y0 = this._y0, y1 = this._y1; // Expand the tree to cover the new points. this.cover(x0, y0).cover(x1, y1); // Add the new points. for (i = 0; i < n; ++i) { add$4(this, xz[i], yz[i], data[i]); } return this; } var tree_cover = function(x, y) { if (isNaN(x = +x) || isNaN(y = +y)) return this; // ignore invalid points var x0 = this._x0, y0 = this._y0, x1 = this._x1, y1 = this._y1; // If the quadtree has no extent, initialize them. // Integer extent are necessary so that if we later double the extent, // the existing quadrant boundaries don’t change due to floating point error! if (isNaN(x0)) { x1 = (x0 = Math.floor(x)) + 1; y1 = (y0 = Math.floor(y)) + 1; } // Otherwise, double repeatedly to cover. else if (x0 > x || x > x1 || y0 > y || y > y1) { var z = x1 - x0, node = this._root, parent, i; switch (i = (y < (y0 + y1) / 2) << 1 | (x < (x0 + x1) / 2)) { case 0: { do parent = new Array(4), parent[i] = node, node = parent; while (z *= 2, x1 = x0 + z, y1 = y0 + z, x > x1 || y > y1); break; } case 1: { do parent = new Array(4), parent[i] = node, node = parent; while (z *= 2, x0 = x1 - z, y1 = y0 + z, x0 > x || y > y1); break; } case 2: { do parent = new Array(4), parent[i] = node, node = parent; while (z *= 2, x1 = x0 + z, y0 = y1 - z, x > x1 || y0 > y); break; } case 3: { do parent = new Array(4), parent[i] = node, node = parent; while (z *= 2, x0 = x1 - z, y0 = y1 - z, x0 > x || y0 > y); break; } } if (this._root && this._root.length) this._root = node; } // If the quadtree covers the point already, just return. else return this; this._x0 = x0; this._y0 = y0; this._x1 = x1; this._y1 = y1; return this; }; var tree_data = function() { var data = []; this.visit(function(node) { if (!node.length) do data.push(node.data); while (node = node.next) }); return data; }; var tree_extent = function(_) { return arguments.length ? this.cover(+_[0][0], +_[0][1]).cover(+_[1][0], +_[1][1]) : isNaN(this._x0) ? undefined : [[this._x0, this._y0], [this._x1, this._y1]]; }; var Quad = function(node, x0, y0, x1, y1) { this.node = node; this.x0 = x0; this.y0 = y0; this.x1 = x1; this.y1 = y1; }; var tree_find = function(x, y, radius) { var data, x0 = this._x0, y0 = this._y0, x1, y1, x2, y2, x3 = this._x1, y3 = this._y1, quads = [], node = this._root, q, i; if (node) quads.push(new Quad(node, x0, y0, x3, y3)); if (radius == null) radius = Infinity; else { x0 = x - radius, y0 = y - radius; x3 = x + radius, y3 = y + radius; radius *= radius; } while (q = quads.pop()) { // Stop searching if this quadrant can’t contain a closer node. if (!(node = q.node) || (x1 = q.x0) > x3 || (y1 = q.y0) > y3 || (x2 = q.x1) < x0 || (y2 = q.y1) < y0) continue; // Bisect the current quadrant. if (node.length) { var xm = (x1 + x2) / 2, ym = (y1 + y2) / 2; quads.push( new Quad(node[3], xm, ym, x2, y2), new Quad(node[2], x1, ym, xm, y2), new Quad(node[1], xm, y1, x2, ym), new Quad(node[0], x1, y1, xm, ym) ); // Visit the closest quadrant first. if (i = (y >= ym) << 1 | (x >= xm)) { q = quads[quads.length - 1]; quads[quads.length - 1] = quads[quads.length - 1 - i]; quads[quads.length - 1 - i] = q; } } // Visit this point. (Visiting coincident points isn’t necessary!) else { var dx = x - +this._x.call(null, node.data), dy = y - +this._y.call(null, node.data), d2 = dx * dx + dy * dy; if (d2 < radius) { var d = Math.sqrt(radius = d2); x0 = x - d, y0 = y - d; x3 = x + d, y3 = y + d; data = node.data; } } } return data; }; var tree_remove = function(d) { if (isNaN(x = +this._x.call(null, d)) || isNaN(y = +this._y.call(null, d))) return this; // ignore invalid points var parent, node = this._root, retainer, previous, next, x0 = this._x0, y0 = this._y0, x1 = this._x1, y1 = this._y1, x, y, xm, ym, right, bottom, i, j; // If the tree is empty, initialize the root as a leaf. if (!node) return this; // Find the leaf node for the point. // While descending, also retain the deepest parent with a non-removed sibling. if (node.length) while (true) { if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm; if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym; if (!(parent = node, node = node[i = bottom << 1 | right])) return this; if (!node.length) break; if (parent[(i + 1) & 3] || parent[(i + 2) & 3] || parent[(i + 3) & 3]) retainer = parent, j = i; } // Find the point to remove. while (node.data !== d) if (!(previous = node, node = node.next)) return this; if (next = node.next) delete node.next; // If there are multiple coincident points, remove just the point. if (previous) return (next ? previous.next = next : delete previous.next), this; // If this is the root point, remove it. if (!parent) return this._root = next, this; // Remove this leaf. next ? parent[i] = next : delete parent[i]; // If the parent now contains exactly one leaf, collapse superfluous parents. if ((node = parent[0] || parent[1] || parent[2] || parent[3]) && node === (parent[3] || parent[2] || parent[1] || parent[0]) && !node.length) { if (retainer) retainer[j] = node; else this._root = node; } return this; }; function removeAll(data) { for (var i = 0, n = data.length; i < n; ++i) this.remove(data[i]); return this; } var tree_root = function() { return this._root; }; var tree_size = function() { var size = 0; this.visit(function(node) { if (!node.length) do ++size; while (node = node.next) }); return size; }; var tree_visit = function(callback) { var quads = [], q, node = this._root, child, x0, y0, x1, y1; if (node) quads.push(new Quad(node, this._x0, this._y0, this._x1, this._y1)); while (q = quads.pop()) { if (!callback(node = q.node, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1) && node.length) { var xm = (x0 + x1) / 2, ym = (y0 + y1) / 2; if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1)); if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1)); if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym)); if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym)); } } return this; }; var tree_visitAfter = function(callback) { var quads = [], next = [], q; if (this._root) quads.push(new Quad(this._root, this._x0, this._y0, this._x1, this._y1)); while (q = quads.pop()) { var node = q.node; if (node.length) { var child, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1, xm = (x0 + x1) / 2, ym = (y0 + y1) / 2; if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym)); if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym)); if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1)); if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1)); } next.push(q); } while (q = next.pop()) { callback(q.node, q.x0, q.y0, q.x1, q.y1); } return this; }; function defaultX$1(d) { return d[0]; } var tree_x = function(_) { return arguments.length ? (this._x = _, this) : this._x; }; function defaultY$1(d) { return d[1]; } var tree_y = function(_) { return arguments.length ? (this._y = _, this) : this._y; }; function quadtree(nodes, x, y) { var tree = new Quadtree(x == null ? defaultX$1 : x, y == null ? defaultY$1 : y, NaN, NaN, NaN, NaN); return nodes == null ? tree : tree.addAll(nodes); } function Quadtree(x, y, x0, y0, x1, y1) { this._x = x; this._y = y; this._x0 = x0; this._y0 = y0; this._x1 = x1; this._y1 = y1; this._root = undefined; } function leaf_copy(leaf) { var copy = {data: leaf.data}, next = copy; while (leaf = leaf.next) next = next.next = {data: leaf.data}; return copy; } var treeProto = quadtree.prototype = Quadtree.prototype; treeProto.copy = function() { var copy = new Quadtree(this._x, this._y, this._x0, this._y0, this._x1, this._y1), node = this._root, nodes, child; if (!node) return copy; if (!node.length) return copy._root = leaf_copy(node), copy; nodes = [{source: node, target: copy._root = new Array(4)}]; while (node = nodes.pop()) { for (var i = 0; i < 4; ++i) { if (child = node.source[i]) { if (child.length) nodes.push({source: child, target: node.target[i] = new Array(4)}); else node.target[i] = leaf_copy(child); } } } return copy; }; treeProto.add = tree_add; treeProto.addAll = addAll$1; treeProto.cover = tree_cover; treeProto.data = tree_data; treeProto.extent = tree_extent; treeProto.find = tree_find; treeProto.remove = tree_remove; treeProto.removeAll = removeAll; treeProto.root = tree_root; treeProto.size = tree_size; treeProto.visit = tree_visit; treeProto.visitAfter = tree_visitAfter; treeProto.x = tree_x; treeProto.y = tree_y; function x$2(d) { return d.x + d.vx; } function y$2(d) { return d.y + d.vy; } var forceCollide = function(radius) { var nodes, radii, strength = 1, iterations = 1; if (typeof radius !== "function") radius = constant$8(radius == null ? 1 : +radius); function force() { var i, n = nodes.length, tree, node, xi, yi, ri, ri2; for (var k = 0; k < iterations; ++k) { tree = quadtree(nodes, x$2, y$2).visitAfter(prepare); for (i = 0; i < n; ++i) { node = nodes[i]; ri = radii[node.index], ri2 = ri * ri; xi = node.x + node.vx; yi = node.y + node.vy; tree.visit(apply); } } function apply(quad, x0, y0, x1, y1) { var data = quad.data, rj = quad.r, r = ri + rj; if (data) { if (data.index > node.index) { var x = xi - data.x - data.vx, y = yi - data.y - data.vy, l = x * x + y * y; if (l < r * r) { if (x === 0) x = jiggle(), l += x * x; if (y === 0) y = jiggle(), l += y * y; l = (r - (l = Math.sqrt(l))) / l * strength; node.vx += (x *= l) * (r = (rj *= rj) / (ri2 + rj)); node.vy += (y *= l) * r; data.vx -= x * (r = 1 - r); data.vy -= y * r; } } return; } return x0 > xi + r || x1 < xi - r || y0 > yi + r || y1 < yi - r; } } function prepare(quad) { if (quad.data) return quad.r = radii[quad.data.index]; for (var i = quad.r = 0; i < 4; ++i) { if (quad[i] && quad[i].r > quad.r) { quad.r = quad[i].r; } } } function initialize() { if (!nodes) return; var i, n = nodes.length, node; radii = new Array(n); for (i = 0; i < n; ++i) node = nodes[i], radii[node.index] = +radius(node, i, nodes); } force.initialize = function(_) { nodes = _; initialize(); }; force.iterations = function(_) { return arguments.length ? (iterations = +_, force) : iterations; }; force.strength = function(_) { return arguments.length ? (strength = +_, force) : strength; }; force.radius = function(_) { return arguments.length ? (radius = typeof _ === "function" ? _ : constant$8(+_), initialize(), force) : radius; }; return force; }; function index(d) { return d.index; } function find(nodeById, nodeId) { var node = nodeById.get(nodeId); if (!node) throw new Error("missing: " + nodeId); return node; } var forceLink = function(links) { var id = index, strength = defaultStrength, strengths, distance = constant$8(30), distances, nodes, count, bias, iterations = 1; if (links == null) links = []; function defaultStrength(link) { return 1 / Math.min(count[link.source.index], count[link.target.index]); } function force(alpha) { for (var k = 0, n = links.length; k < iterations; ++k) { for (var i = 0, link, source, target, x, y, l, b; i < n; ++i) { link = links[i], source = link.source, target = link.target; x = target.x + target.vx - source.x - source.vx || jiggle(); y = target.y + target.vy - source.y - source.vy || jiggle(); l = Math.sqrt(x * x + y * y); l = (l - distances[i]) / l * alpha * strengths[i]; x *= l, y *= l; target.vx -= x * (b = bias[i]); target.vy -= y * b; source.vx += x * (b = 1 - b); source.vy += y * b; } } } function initialize() { if (!nodes) return; var i, n = nodes.length, m = links.length, nodeById = map(nodes, id), link; for (i = 0, count = new Array(n); i < m; ++i) { link = links[i], link.index = i; if (typeof link.source !== "object") link.source = find(nodeById, link.source); if (typeof link.target !== "object") link.target = find(nodeById, link.target); count[link.source.index] = (count[link.source.index] || 0) + 1; count[link.target.index] = (count[link.target.index] || 0) + 1; } for (i = 0, bias = new Array(m); i < m; ++i) { link = links[i], bias[i] = count[link.source.index] / (count[link.source.index] + count[link.target.index]); } strengths = new Array(m), initializeStrength(); distances = new Array(m), initializeDistance(); } function initializeStrength() { if (!nodes) return; for (var i = 0, n = links.length; i < n; ++i) { strengths[i] = +strength(links[i], i, links); } } function initializeDistance() { if (!nodes) return; for (var i = 0, n = links.length; i < n; ++i) { distances[i] = +distance(links[i], i, links); } } force.initialize = function(_) { nodes = _; initialize(); }; force.links = function(_) { return arguments.length ? (links = _, initialize(), force) : links; }; force.id = function(_) { return arguments.length ? (id = _, force) : id; }; force.iterations = function(_) { return arguments.length ? (iterations = +_, force) : iterations; }; force.strength = function(_) { return arguments.length ? (strength = typeof _ === "function" ? _ : constant$8(+_), initializeStrength(), force) : strength; }; force.distance = function(_) { return arguments.length ? (distance = typeof _ === "function" ? _ : constant$8(+_), initializeDistance(), force) : distance; }; return force; }; var frame = 0; var timeout = 0; var interval = 0; var pokeDelay = 1000; var taskHead; var taskTail; var clockLast = 0; var clockNow = 0; var clockSkew = 0; var clock = typeof performance === "object" && performance.now ? performance : Date; var setFrame = typeof window === "object" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : function(f) { setTimeout(f, 17); }; function now() { return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew); } function clearNow() { clockNow = 0; } function Timer() { this._call = this._time = this._next = null; } Timer.prototype = timer.prototype = { constructor: Timer, restart: function(callback, delay, time) { if (typeof callback !== "function") throw new TypeError("callback is not a function"); time = (time == null ? now() : +time) + (delay == null ? 0 : +delay); if (!this._next && taskTail !== this) { if (taskTail) taskTail._next = this; else taskHead = this; taskTail = this; } this._call = callback; this._time = time; sleep(); }, stop: function() { if (this._call) { this._call = null; this._time = Infinity; sleep(); } } }; function timer(callback, delay, time) { var t = new Timer; t.restart(callback, delay, time); return t; } function timerFlush() { now(); // Get the current time, if not already set. ++frame; // Pretend we’ve set an alarm, if we haven’t already. var t = taskHead, e; while (t) { if ((e = clockNow - t._time) >= 0) t._call.call(null, e); t = t._next; } --frame; } function wake() { clockNow = (clockLast = clock.now()) + clockSkew; frame = timeout = 0; try { timerFlush(); } finally { frame = 0; nap(); clockNow = 0; } } function poke() { var now = clock.now(), delay = now - clockLast; if (delay > pokeDelay) clockSkew -= delay, clockLast = now; } function nap() { var t0, t1 = taskHead, t2, time = Infinity; while (t1) { if (t1._call) { if (time > t1._time) time = t1._time; t0 = t1, t1 = t1._next; } else { t2 = t1._next, t1._next = null; t1 = t0 ? t0._next = t2 : taskHead = t2; } } taskTail = t0; sleep(time); } function sleep(time) { if (frame) return; // Soonest alarm already set, or will be. if (timeout) timeout = clearTimeout(timeout); var delay = time - clockNow; if (delay > 24) { if (time < Infinity) timeout = setTimeout(wake, delay); if (interval) interval = clearInterval(interval); } else { if (!interval) clockLast = clockNow, interval = setInterval(poke, pokeDelay); frame = 1, setFrame(wake); } } function x$3(d) { return d.x; } function y$3(d) { return d.y; } var initialRadius = 10; var initialAngle = Math.PI * (3 - Math.sqrt(5)); var forceSimulation = function(nodes) { var simulation, alpha = 1, alphaMin = 0.001, alphaDecay = 1 - Math.pow(alphaMin, 1 / 300), alphaTarget = 0, velocityDecay = 0.6, forces = map(), stepper = timer(step), event = dispatch("tick", "end"); if (nodes == null) nodes = []; function step() { tick(); event.call("tick", simulation); if (alpha < alphaMin) { stepper.stop(); event.call("end", simulation); } } function tick() { var i, n = nodes.length, node; alpha += (alphaTarget - alpha) * alphaDecay; forces.each(function(force) { force(alpha); }); for (i = 0; i < n; ++i) { node = nodes[i]; if (node.fx == null) node.x += node.vx *= velocityDecay; else node.x = node.fx, node.vx = 0; if (node.fy == null) node.y += node.vy *= velocityDecay; else node.y = node.fy, node.vy = 0; } } function initializeNodes() { for (var i = 0, n = nodes.length, node; i < n; ++i) { node = nodes[i], node.index = i; if (isNaN(node.x) || isNaN(node.y)) { var radius = initialRadius * Math.sqrt(i), angle = i * initialAngle; node.x = radius * Math.cos(angle); node.y = radius * Math.sin(angle); } if (isNaN(node.vx) || isNaN(node.vy)) { node.vx = node.vy = 0; } } } function initializeForce(force) { if (force.initialize) force.initialize(nodes); return force; } initializeNodes(); return simulation = { tick: tick, restart: function() { return stepper.restart(step), simulation; }, stop: function() { return stepper.stop(), simulation; }, nodes: function(_) { return arguments.length ? (nodes = _, initializeNodes(), forces.each(initializeForce), simulation) : nodes; }, alpha: function(_) { return arguments.length ? (alpha = +_, simulation) : alpha; }, alphaMin: function(_) { return arguments.length ? (alphaMin = +_, simulation) : alphaMin; }, alphaDecay: function(_) { return arguments.length ? (alphaDecay = +_, simulation) : +alphaDecay; }, alphaTarget: function(_) { return arguments.length ? (alphaTarget = +_, simulation) : alphaTarget; }, velocityDecay: function(_) { return arguments.length ? (velocityDecay = 1 - _, simulation) : 1 - velocityDecay; }, force: function(name, _) { return arguments.length > 1 ? ((_ == null ? forces.remove(name) : forces.set(name, initializeForce(_))), simulation) : forces.get(name); }, find: function(x, y, radius) { var i = 0, n = nodes.length, dx, dy, d2, node, closest; if (radius == null) radius = Infinity; else radius *= radius; for (i = 0; i < n; ++i) { node = nodes[i]; dx = x - node.x; dy = y - node.y; d2 = dx * dx + dy * dy; if (d2 < radius) closest = node, radius = d2; } return closest; }, on: function(name, _) { return arguments.length > 1 ? (event.on(name, _), simulation) : event.on(name); } }; }; var forceManyBody = function() { var nodes, node, alpha, strength = constant$8(-30), strengths, distanceMin2 = 1, distanceMax2 = Infinity, theta2 = 0.81; function force(_) { var i, n = nodes.length, tree = quadtree(nodes, x$3, y$3).visitAfter(accumulate); for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply); } function initialize() { if (!nodes) return; var i, n = nodes.length, node; strengths = new Array(n); for (i = 0; i < n; ++i) node = nodes[i], strengths[node.index] = +strength(node, i, nodes); } function accumulate(quad) { var strength = 0, q, c, x, y, i; // For internal nodes, accumulate forces from child quadrants. if (quad.length) { for (x = y = i = 0; i < 4; ++i) { if ((q = quad[i]) && (c = q.value)) { strength += c, x += c * q.x, y += c * q.y; } } quad.x = x / strength; quad.y = y / strength; } // For leaf nodes, accumulate forces from coincident quadrants. else { q = quad; q.x = q.data.x; q.y = q.data.y; do strength += strengths[q.data.index]; while (q = q.next); } quad.value = strength; } function apply(quad, x1, _, x2) { if (!quad.value) return true; var x = quad.x - node.x, y = quad.y - node.y, w = x2 - x1, l = x * x + y * y; // Apply the Barnes-Hut approximation if possible. // Limit forces for very close nodes; randomize direction if coincident. if (w * w / theta2 < l) { if (l < distanceMax2) { if (x === 0) x = jiggle(), l += x * x; if (y === 0) y = jiggle(), l += y * y; if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l); node.vx += x * quad.value * alpha / l; node.vy += y * quad.value * alpha / l; } return true; } // Otherwise, process points directly. else if (quad.length || l >= distanceMax2) return; // Limit forces for very close nodes; randomize direction if coincident. if (quad.data !== node || quad.next) { if (x === 0) x = jiggle(), l += x * x; if (y === 0) y = jiggle(), l += y * y; if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l); } do if (quad.data !== node) { w = strengths[quad.data.index] * alpha / l; node.vx += x * w; node.vy += y * w; } while (quad = quad.next); } force.initialize = function(_) { nodes = _; initialize(); }; force.strength = function(_) { return arguments.length ? (strength = typeof _ === "function" ? _ : constant$8(+_), initialize(), force) : strength; }; force.distanceMin = function(_) { return arguments.length ? (distanceMin2 = _ * _, force) : Math.sqrt(distanceMin2); }; force.distanceMax = function(_) { return arguments.length ? (distanceMax2 = _ * _, force) : Math.sqrt(distanceMax2); }; force.theta = function(_) { return arguments.length ? (theta2 = _ * _, force) : Math.sqrt(theta2); }; return force; }; var forceX = function(x) { var strength = constant$8(0.1), nodes, strengths, xz; if (typeof x !== "function") x = constant$8(x == null ? 0 : +x); function force(alpha) { for (var i = 0, n = nodes.length, node; i < n; ++i) { node = nodes[i], node.vx += (xz[i] - node.x) * strengths[i] * alpha; } } function initialize() { if (!nodes) return; var i, n = nodes.length; strengths = new Array(n); xz = new Array(n); for (i = 0; i < n; ++i) { strengths[i] = isNaN(xz[i] = +x(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes); } } force.initialize = function(_) { nodes = _; initialize(); }; force.strength = function(_) { return arguments.length ? (strength = typeof _ === "function" ? _ : constant$8(+_), initialize(), force) : strength; }; force.x = function(_) { return arguments.length ? (x = typeof _ === "function" ? _ : constant$8(+_), initialize(), force) : x; }; return force; }; var forceY = function(y) { var strength = constant$8(0.1), nodes, strengths, yz; if (typeof y !== "function") y = constant$8(y == null ? 0 : +y); function force(alpha) { for (var i = 0, n = nodes.length, node; i < n; ++i) { node = nodes[i], node.vy += (yz[i] - node.y) * strengths[i] * alpha; } } function initialize() { if (!nodes) return; var i, n = nodes.length; strengths = new Array(n); yz = new Array(n); for (i = 0; i < n; ++i) { strengths[i] = isNaN(yz[i] = +y(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes); } } force.initialize = function(_) { nodes = _; initialize(); }; force.strength = function(_) { return arguments.length ? (strength = typeof _ === "function" ? _ : constant$8(+_), initialize(), force) : strength; }; force.y = function(_) { return arguments.length ? (y = typeof _ === "function" ? _ : constant$8(+_), initialize(), force) : y; }; return force; }; var ForceMap = { center: forceCenter, collide: forceCollide, nbody: forceManyBody, link: forceLink, x: forceX, y: forceY }; var Forces = 'forces'; var ForceParams = [ 'alpha', 'alphaMin', 'alphaTarget', 'velocityDecay', 'forces' ]; var ForceConfig = ['static', 'iterations']; var ForceOutput = ['x', 'y', 'vx', 'vy']; /** * Force simulation layout. * @constructor * @param {object} params - The parameters for this operator. * @param {Array} params.forces - The forces to apply. */ function Force(params) { Transform.call(this, null, params); } Force.Definition = { "type": "Force", "metadata": {"modifies": true}, "params": [ { "name": "static", "type": "boolean", "default": false }, { "name": "restart", "type": "boolean", "default": false }, { "name": "iterations", "type": "number", "default": 300 }, { "name": "alpha", "type": "number", "default": 1 }, { "name": "alphaMin", "type": "number", "default": 0.001 }, { "name": "alphaTarget", "type": "number", "default": 0 }, { "name": "velocityDecay", "type": "number", "default": 0.4 }, { "name": "forces", "type": "param", "array": true, "params": [ { "key": {"force": "center"}, "params": [ { "name": "x", "type": "number", "default": 0 }, { "name": "y", "type": "number", "default": 0 } ] }, { "key": {"force": "collide"}, "params": [ { "name": "radius", "type": "number", "expr": true }, { "name": "strength", "type": "number", "default": 0.7 }, { "name": "iterations", "type": "number", "default": 1 } ] }, { "key": {"force": "nbody"}, "params": [ { "name": "strength", "type": "number", "default": -30 }, { "name": "theta", "type": "number", "default": 0.9 }, { "name": "distanceMin", "type": "number", "default": 1 }, { "name": "distanceMax", "type": "number" } ] }, { "key": {"force": "link"}, "params": [ { "name": "links", "type": "data" }, { "name": "id", "type": "field" }, { "name": "distance", "type": "number", "default": 30, "expr": true }, { "name": "strength", "type": "number", "expr": true }, { "name": "iterations", "type": "number", "default": 1 } ] }, { "key": {"force": "x"}, "params": [ { "name": "strength", "type": "number", "default": 0.1 }, { "name": "x", "type": "field" } ] }, { "key": {"force": "y"}, "params": [ { "name": "strength", "type": "number", "default": 0.1 }, { "name": "y", "type": "field" } ] } ] }, { "name": "as", "type": "string", "array": true, "modify": false, "default": ForceOutput } ] }; var prototype$67 = inherits(Force, Transform); prototype$67.transform = function(_, pulse) { var sim = this.value, change = pulse.changed(pulse.ADD_REM), params = _.modified(ForceParams), iters = _.iterations || 300; // configure simulation if (!sim) { this.value = sim = simulation(pulse.source, _); sim.on('tick', rerun(pulse.dataflow, this)); if (!_.static) { change = true; sim.tick(); // ensure we run on init } pulse.modifies('index'); } else { if (change) { pulse.modifies('index'); sim.nodes(pulse.source); } if (params || pulse.changed(pulse.MOD)) { setup(sim, _, 0, pulse); } } // run simulation if (params || change || _.modified(ForceConfig) || (pulse.changed() && _.restart)) { sim.alpha(Math.max(sim.alpha(), _.alpha || 1)) .alphaDecay(1 - Math.pow(sim.alphaMin(), 1 / iters)); if (_.static) { for (sim.stop(); --iters >= 0;) sim.tick(); } else { if (sim.stopped()) sim.restart(); if (!change) return pulse.StopPropagation; // defer to sim ticks } } return this.finish(_, pulse); }; prototype$67.finish = function(_, pulse) { var dataflow = pulse.dataflow; // inspect dependencies, touch link source data for (var args=this._argops, j=0, m=args.length, arg; j= 0) sum += children[i].value; node.value = sum; } var node_count = function() { return this.eachAfter(count); }; var node_each = function(callback) { var node = this, current, next = [node], children, i, n; do { current = next.reverse(), next = []; while (node = current.pop()) { callback(node), children = node.children; if (children) for (i = 0, n = children.length; i < n; ++i) { next.push(children[i]); } } } while (next.length); return this; }; var node_eachBefore = function(callback) { var node = this, nodes = [node], children, i; while (node = nodes.pop()) { callback(node), children = node.children; if (children) for (i = children.length - 1; i >= 0; --i) { nodes.push(children[i]); } } return this; }; var node_eachAfter = function(callback) { var node = this, nodes = [node], next = [], children, i, n; while (node = nodes.pop()) { next.push(node), children = node.children; if (children) for (i = 0, n = children.length; i < n; ++i) { nodes.push(children[i]); } } while (node = next.pop()) { callback(node); } return this; }; var node_sum = function(value) { return this.eachAfter(function(node) { var sum = +value(node.data) || 0, children = node.children, i = children && children.length; while (--i >= 0) sum += children[i].value; node.value = sum; }); }; var node_sort = function(compare) { return this.eachBefore(function(node) { if (node.children) { node.children.sort(compare); } }); }; var node_path = function(end) { var start = this, ancestor = leastCommonAncestor(start, end), nodes = [start]; while (start !== ancestor) { start = start.parent; nodes.push(start); } var k = nodes.length; while (end !== ancestor) { nodes.splice(k, 0, end); end = end.parent; } return nodes; }; function leastCommonAncestor(a, b) { if (a === b) return a; var aNodes = a.ancestors(), bNodes = b.ancestors(), c = null; a = aNodes.pop(); b = bNodes.pop(); while (a === b) { c = a; a = aNodes.pop(); b = bNodes.pop(); } return c; } var node_ancestors = function() { var node = this, nodes = [node]; while (node = node.parent) { nodes.push(node); } return nodes; }; var node_descendants = function() { var nodes = []; this.each(function(node) { nodes.push(node); }); return nodes; }; var node_leaves = function() { var leaves = []; this.eachBefore(function(node) { if (!node.children) { leaves.push(node); } }); return leaves; }; var node_links = function() { var root = this, links = []; root.each(function(node) { if (node !== root) { // Don’t include the root’s parent, if any. links.push({source: node.parent, target: node}); } }); return links; }; function hierarchy(data, children) { var root = new Node(data), valued = +data.value && (root.value = data.value), node, nodes = [root], child, childs, i, n; if (children == null) children = defaultChildren; while (node = nodes.pop()) { if (valued) node.value = +node.data.value; if ((childs = children(node.data)) && (n = childs.length)) { node.children = new Array(n); for (i = n - 1; i >= 0; --i) { nodes.push(child = node.children[i] = new Node(childs[i])); child.parent = node; child.depth = node.depth + 1; } } } return root.eachBefore(computeHeight); } function node_copy() { return hierarchy(this).eachBefore(copyData); } function defaultChildren(d) { return d.children; } function copyData(node) { node.data = node.data.data; } function computeHeight(node) { var height = 0; do node.height = height; while ((node = node.parent) && (node.height < ++height)); } function Node(data) { this.data = data; this.depth = this.height = 0; this.parent = null; } Node.prototype = hierarchy.prototype = { constructor: Node, count: node_count, each: node_each, eachAfter: node_eachAfter, eachBefore: node_eachBefore, sum: node_sum, sort: node_sort, path: node_path, ancestors: node_ancestors, descendants: node_descendants, leaves: node_leaves, links: node_links, copy: node_copy }; var slice$5 = Array.prototype.slice; function shuffle$1(array) { var m = array.length, t, i; while (m) { i = Math.random() * m-- | 0; t = array[m]; array[m] = array[i]; array[i] = t; } return array; } var enclose = function(circles) { var i = 0, n = (circles = shuffle$1(slice$5.call(circles))).length, B = [], p, e; while (i < n) { p = circles[i]; if (e && enclosesWeak(e, p)) ++i; else e = encloseBasis(B = extendBasis(B, p)), i = 0; } return e; }; function extendBasis(B, p) { var i, j; if (enclosesWeakAll(p, B)) return [p]; // If we get here then B must have at least one element. for (i = 0; i < B.length; ++i) { if (enclosesNot(p, B[i]) && enclosesWeakAll(encloseBasis2(B[i], p), B)) { return [B[i], p]; } } // If we get here then B must have at least two elements. for (i = 0; i < B.length - 1; ++i) { for (j = i + 1; j < B.length; ++j) { if (enclosesNot(encloseBasis2(B[i], B[j]), p) && enclosesNot(encloseBasis2(B[i], p), B[j]) && enclosesNot(encloseBasis2(B[j], p), B[i]) && enclosesWeakAll(encloseBasis3(B[i], B[j], p), B)) { return [B[i], B[j], p]; } } } // If we get here then something is very wrong. throw new Error; } function enclosesNot(a, b) { var dr = a.r - b.r, dx = b.x - a.x, dy = b.y - a.y; return dr < 0 || dr * dr < dx * dx + dy * dy; } function enclosesWeak(a, b) { var dr = a.r - b.r + 1e-6, dx = b.x - a.x, dy = b.y - a.y; return dr > 0 && dr * dr > dx * dx + dy * dy; } function enclosesWeakAll(a, B) { for (var i = 0; i < B.length; ++i) { if (!enclosesWeak(a, B[i])) { return false; } } return true; } function encloseBasis(B) { switch (B.length) { case 1: return encloseBasis1(B[0]); case 2: return encloseBasis2(B[0], B[1]); case 3: return encloseBasis3(B[0], B[1], B[2]); } } function encloseBasis1(a) { return { x: a.x, y: a.y, r: a.r }; } function encloseBasis2(a, b) { var x1 = a.x, y1 = a.y, r1 = a.r, x2 = b.x, y2 = b.y, r2 = b.r, x21 = x2 - x1, y21 = y2 - y1, r21 = r2 - r1, l = Math.sqrt(x21 * x21 + y21 * y21); return { x: (x1 + x2 + x21 / l * r21) / 2, y: (y1 + y2 + y21 / l * r21) / 2, r: (l + r1 + r2) / 2 }; } function encloseBasis3(a, b, c) { var x1 = a.x, y1 = a.y, r1 = a.r, x2 = b.x, y2 = b.y, r2 = b.r, x3 = c.x, y3 = c.y, r3 = c.r, a2 = x1 - x2, a3 = x1 - x3, b2 = y1 - y2, b3 = y1 - y3, c2 = r2 - r1, c3 = r3 - r1, d1 = x1 * x1 + y1 * y1 - r1 * r1, d2 = d1 - x2 * x2 - y2 * y2 + r2 * r2, d3 = d1 - x3 * x3 - y3 * y3 + r3 * r3, ab = a3 * b2 - a2 * b3, xa = (b2 * d3 - b3 * d2) / (ab * 2) - x1, xb = (b3 * c2 - b2 * c3) / ab, ya = (a3 * d2 - a2 * d3) / (ab * 2) - y1, yb = (a2 * c3 - a3 * c2) / ab, A = xb * xb + yb * yb - 1, B = 2 * (r1 + xa * xb + ya * yb), C = xa * xa + ya * ya - r1 * r1, r = -(A ? (B + Math.sqrt(B * B - 4 * A * C)) / (2 * A) : C / B); return { x: x1 + xa + xb * r, y: y1 + ya + yb * r, r: r }; } function place(a, b, c) { var ax = a.x, ay = a.y, da = b.r + c.r, db = a.r + c.r, dx = b.x - ax, dy = b.y - ay, dc = dx * dx + dy * dy; if (dc) { var x = 0.5 + ((db *= db) - (da *= da)) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc); c.x = ax + x * dx + y * dy; c.y = ay + x * dy - y * dx; } else { c.x = ax + db; c.y = ay; } } function intersects(a, b) { var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r; return dr * dr - 1e-6 > dx * dx + dy * dy; } function score(node) { var a = node._, b = node.next._, ab = a.r + b.r, dx = (a.x * b.r + b.x * a.r) / ab, dy = (a.y * b.r + b.y * a.r) / ab; return dx * dx + dy * dy; } function Node$1(circle) { this._ = circle; this.next = null; this.previous = null; } function packEnclose(circles) { if (!(n = circles.length)) return 0; var a, b, c, n, aa, ca, i, j, k, sj, sk; // Place the first circle. a = circles[0], a.x = 0, a.y = 0; if (!(n > 1)) return a.r; // Place the second circle. b = circles[1], a.x = -b.r, b.x = a.r, b.y = 0; if (!(n > 2)) return a.r + b.r; // Place the third circle. place(b, a, c = circles[2]); // Initialize the front-chain using the first three circles a, b and c. a = new Node$1(a), b = new Node$1(b), c = new Node$1(c); a.next = c.previous = b; b.next = a.previous = c; c.next = b.previous = a; // Attempt to place each remaining circle… pack: for (i = 3; i < n; ++i) { place(a._, b._, c = circles[i]), c = new Node$1(c); // Find the closest intersecting circle on the front-chain, if any. // “Closeness” is determined by linear distance along the front-chain. // “Ahead” or “behind” is likewise determined by linear distance. j = b.next, k = a.previous, sj = b._.r, sk = a._.r; do { if (sj <= sk) { if (intersects(j._, c._)) { b = j, a.next = b, b.previous = a, --i; continue pack; } sj += j._.r, j = j.next; } else { if (intersects(k._, c._)) { a = k, a.next = b, b.previous = a, --i; continue pack; } sk += k._.r, k = k.previous; } } while (j !== k.next); // Success! Insert the new circle c between a and b. c.previous = a, c.next = b, a.next = b.previous = b = c; // Compute the new closest circle pair to the centroid. aa = score(a); while ((c = c.next) !== b) { if ((ca = score(c)) < aa) { a = c, aa = ca; } } b = a.next; } // Compute the enclosing circle of the front chain. a = [b._], c = b; while ((c = c.next) !== b) a.push(c._); c = enclose(a); // Translate the circles to put the enclosing circle around the origin. for (i = 0; i < n; ++i) a = circles[i], a.x -= c.x, a.y -= c.y; return c.r; } function optional(f) { return f == null ? null : required(f); } function required(f) { if (typeof f !== "function") throw new Error; return f; } function constantZero() { return 0; } var constant$9 = function(x) { return function() { return x; }; }; function defaultRadius(d) { return Math.sqrt(d.value); } var pack$1 = function() { var radius = null, dx = 1, dy = 1, padding = constantZero; function pack(root) { root.x = dx / 2, root.y = dy / 2; if (radius) { root.eachBefore(radiusLeaf(radius)) .eachAfter(packChildren(padding, 0.5)) .eachBefore(translateChild(1)); } else { root.eachBefore(radiusLeaf(defaultRadius)) .eachAfter(packChildren(constantZero, 1)) .eachAfter(packChildren(padding, root.r / Math.min(dx, dy))) .eachBefore(translateChild(Math.min(dx, dy) / (2 * root.r))); } return root; } pack.radius = function(x) { return arguments.length ? (radius = optional(x), pack) : radius; }; pack.size = function(x) { return arguments.length ? (dx = +x[0], dy = +x[1], pack) : [dx, dy]; }; pack.padding = function(x) { return arguments.length ? (padding = typeof x === "function" ? x : constant$9(+x), pack) : padding; }; return pack; }; function radiusLeaf(radius) { return function(node) { if (!node.children) { node.r = Math.max(0, +radius(node) || 0); } }; } function packChildren(padding, k) { return function(node) { if (children = node.children) { var children, i, n = children.length, r = padding(node) * k || 0, e; if (r) for (i = 0; i < n; ++i) children[i].r += r; e = packEnclose(children); if (r) for (i = 0; i < n; ++i) children[i].r -= r; node.r = e + r; } }; } function translateChild(k) { return function(node) { var parent = node.parent; node.r *= k; if (parent) { node.x = parent.x + k * node.x; node.y = parent.y + k * node.y; } }; } var roundNode = function(node) { node.x0 = Math.round(node.x0); node.y0 = Math.round(node.y0); node.x1 = Math.round(node.x1); node.y1 = Math.round(node.y1); }; var treemapDice = function(parent, x0, y0, x1, y1) { var nodes = parent.children, node, i = -1, n = nodes.length, k = parent.value && (x1 - x0) / parent.value; while (++i < n) { node = nodes[i], node.y0 = y0, node.y1 = y1; node.x0 = x0, node.x1 = x0 += node.value * k; } }; var partition$2 = function() { var dx = 1, dy = 1, padding = 0, round = false; function partition(root) { var n = root.height + 1; root.x0 = root.y0 = padding; root.x1 = dx; root.y1 = dy / n; root.eachBefore(positionNode(dy, n)); if (round) root.eachBefore(roundNode); return root; } function positionNode(dy, n) { return function(node) { if (node.children) { treemapDice(node, node.x0, dy * (node.depth + 1) / n, node.x1, dy * (node.depth + 2) / n); } var x0 = node.x0, y0 = node.y0, x1 = node.x1 - padding, y1 = node.y1 - padding; if (x1 < x0) x0 = x1 = (x0 + x1) / 2; if (y1 < y0) y0 = y1 = (y0 + y1) / 2; node.x0 = x0; node.y0 = y0; node.x1 = x1; node.y1 = y1; }; } partition.round = function(x) { return arguments.length ? (round = !!x, partition) : round; }; partition.size = function(x) { return arguments.length ? (dx = +x[0], dy = +x[1], partition) : [dx, dy]; }; partition.padding = function(x) { return arguments.length ? (padding = +x, partition) : padding; }; return partition; }; var keyPrefix = "$"; var preroot = {depth: -1}; var ambiguous = {}; function defaultId(d) { return d.id; } function defaultParentId(d) { return d.parentId; } var stratify = function() { var id = defaultId, parentId = defaultParentId; function stratify(data) { var d, i, n = data.length, root, parent, node, nodes = new Array(n), nodeId, nodeKey, nodeByKey = {}; for (i = 0; i < n; ++i) { d = data[i], node = nodes[i] = new Node(d); if ((nodeId = id(d, i, data)) != null && (nodeId += "")) { nodeKey = keyPrefix + (node.id = nodeId); nodeByKey[nodeKey] = nodeKey in nodeByKey ? ambiguous : node; } } for (i = 0; i < n; ++i) { node = nodes[i], nodeId = parentId(data[i], i, data); if (nodeId == null || !(nodeId += "")) { if (root) throw new Error("multiple roots"); root = node; } else { parent = nodeByKey[keyPrefix + nodeId]; if (!parent) throw new Error("missing: " + nodeId); if (parent === ambiguous) throw new Error("ambiguous: " + nodeId); if (parent.children) parent.children.push(node); else parent.children = [node]; node.parent = parent; } } if (!root) throw new Error("no root"); root.parent = preroot; root.eachBefore(function(node) { node.depth = node.parent.depth + 1; --n; }).eachBefore(computeHeight); root.parent = null; if (n > 0) throw new Error("cycle"); return root; } stratify.id = function(x) { return arguments.length ? (id = required(x), stratify) : id; }; stratify.parentId = function(x) { return arguments.length ? (parentId = required(x), stratify) : parentId; }; return stratify; }; function defaultSeparation$1(a, b) { return a.parent === b.parent ? 1 : 2; } // function radialSeparation(a, b) { // return (a.parent === b.parent ? 1 : 2) / a.depth; // } // This function is used to traverse the left contour of a subtree (or // subforest). It returns the successor of v on this contour. This successor is // either given by the leftmost child of v or by the thread of v. The function // returns null if and only if v is on the highest level of its subtree. function nextLeft(v) { var children = v.children; return children ? children[0] : v.t; } // This function works analogously to nextLeft. function nextRight(v) { var children = v.children; return children ? children[children.length - 1] : v.t; } // Shifts the current subtree rooted at w+. This is done by increasing // prelim(w+) and mod(w+) by shift. function moveSubtree(wm, wp, shift) { var change = shift / (wp.i - wm.i); wp.c -= change; wp.s += shift; wm.c += change; wp.z += shift; wp.m += shift; } // All other shifts, applied to the smaller subtrees between w- and w+, are // performed by this function. To prepare the shifts, we have to adjust // change(w+), shift(w+), and change(w-). function executeShifts(v) { var shift = 0, change = 0, children = v.children, i = children.length, w; while (--i >= 0) { w = children[i]; w.z += shift; w.m += shift; shift += w.s + (change += w.c); } } // If vi-’s ancestor is a sibling of v, returns vi-’s ancestor. Otherwise, // returns the specified (default) ancestor. function nextAncestor(vim, v, ancestor) { return vim.a.parent === v.parent ? vim.a : ancestor; } function TreeNode(node, i) { this._ = node; this.parent = null; this.children = null; this.A = null; // default ancestor this.a = this; // ancestor this.z = 0; // prelim this.m = 0; // mod this.c = 0; // change this.s = 0; // shift this.t = null; // thread this.i = i; // number } TreeNode.prototype = Object.create(Node.prototype); function treeRoot(root) { var tree = new TreeNode(root, 0), node, nodes = [tree], child, children, i, n; while (node = nodes.pop()) { if (children = node._.children) { node.children = new Array(n = children.length); for (i = n - 1; i >= 0; --i) { nodes.push(child = node.children[i] = new TreeNode(children[i], i)); child.parent = node; } } } (tree.parent = new TreeNode(null, 0)).children = [tree]; return tree; } // Node-link tree diagram using the Reingold-Tilford "tidy" algorithm var tree$1 = function() { var separation = defaultSeparation$1, dx = 1, dy = 1, nodeSize = null; function tree(root) { var t = treeRoot(root); // Compute the layout using Buchheim et al.’s algorithm. t.eachAfter(firstWalk), t.parent.m = -t.z; t.eachBefore(secondWalk); // If a fixed node size is specified, scale x and y. if (nodeSize) root.eachBefore(sizeNode); // If a fixed tree size is specified, scale x and y based on the extent. // Compute the left-most, right-most, and depth-most nodes for extents. else { var left = root, right = root, bottom = root; root.eachBefore(function(node) { if (node.x < left.x) left = node; if (node.x > right.x) right = node; if (node.depth > bottom.depth) bottom = node; }); var s = left === right ? 1 : separation(left, right) / 2, tx = s - left.x, kx = dx / (right.x + s + tx), ky = dy / (bottom.depth || 1); root.eachBefore(function(node) { node.x = (node.x + tx) * kx; node.y = node.depth * ky; }); } return root; } // Computes a preliminary x-coordinate for v. Before that, FIRST WALK is // applied recursively to the children of v, as well as the function // APPORTION. After spacing out the children by calling EXECUTE SHIFTS, the // node v is placed to the midpoint of its outermost children. function firstWalk(v) { var children = v.children, siblings = v.parent.children, w = v.i ? siblings[v.i - 1] : null; if (children) { executeShifts(v); var midpoint = (children[0].z + children[children.length - 1].z) / 2; if (w) { v.z = w.z + separation(v._, w._); v.m = v.z - midpoint; } else { v.z = midpoint; } } else if (w) { v.z = w.z + separation(v._, w._); } v.parent.A = apportion(v, w, v.parent.A || siblings[0]); } // Computes all real x-coordinates by summing up the modifiers recursively. function secondWalk(v) { v._.x = v.z + v.parent.m; v.m += v.parent.m; } // The core of the algorithm. Here, a new subtree is combined with the // previous subtrees. Threads are used to traverse the inside and outside // contours of the left and right subtree up to the highest common level. The // vertices used for the traversals are vi+, vi-, vo-, and vo+, where the // superscript o means outside and i means inside, the subscript - means left // subtree and + means right subtree. For summing up the modifiers along the // contour, we use respective variables si+, si-, so-, and so+. Whenever two // nodes of the inside contours conflict, we compute the left one of the // greatest uncommon ancestors using the function ANCESTOR and call MOVE // SUBTREE to shift the subtree and prepare the shifts of smaller subtrees. // Finally, we add a new thread (if necessary). function apportion(v, w, ancestor) { if (w) { var vip = v, vop = v, vim = w, vom = vip.parent.children[0], sip = vip.m, sop = vop.m, sim = vim.m, som = vom.m, shift; while (vim = nextRight(vim), vip = nextLeft(vip), vim && vip) { vom = nextLeft(vom); vop = nextRight(vop); vop.a = v; shift = vim.z + sim - vip.z - sip + separation(vim._, vip._); if (shift > 0) { moveSubtree(nextAncestor(vim, v, ancestor), v, shift); sip += shift; sop += shift; } sim += vim.m; sip += vip.m; som += vom.m; sop += vop.m; } if (vim && !nextRight(vop)) { vop.t = vim; vop.m += sim - sop; } if (vip && !nextLeft(vom)) { vom.t = vip; vom.m += sip - som; ancestor = v; } } return ancestor; } function sizeNode(node) { node.x *= dx; node.y = node.depth * dy; } tree.separation = function(x) { return arguments.length ? (separation = x, tree) : separation; }; tree.size = function(x) { return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], tree) : (nodeSize ? null : [dx, dy]); }; tree.nodeSize = function(x) { return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], tree) : (nodeSize ? [dx, dy] : null); }; return tree; }; var treemapSlice = function(parent, x0, y0, x1, y1) { var nodes = parent.children, node, i = -1, n = nodes.length, k = parent.value && (y1 - y0) / parent.value; while (++i < n) { node = nodes[i], node.x0 = x0, node.x1 = x1; node.y0 = y0, node.y1 = y0 += node.value * k; } }; var phi = (1 + Math.sqrt(5)) / 2; function squarifyRatio(ratio, parent, x0, y0, x1, y1) { var rows = [], nodes = parent.children, row, nodeValue, i0 = 0, i1 = 0, n = nodes.length, dx, dy, value = parent.value, sumValue, minValue, maxValue, newRatio, minRatio, alpha, beta; while (i0 < n) { dx = x1 - x0, dy = y1 - y0; // Find the next non-empty node. do sumValue = nodes[i1++].value; while (!sumValue && i1 < n); minValue = maxValue = sumValue; alpha = Math.max(dy / dx, dx / dy) / (value * ratio); beta = sumValue * sumValue * alpha; minRatio = Math.max(maxValue / beta, beta / minValue); // Keep adding nodes while the aspect ratio maintains or improves. for (; i1 < n; ++i1) { sumValue += nodeValue = nodes[i1].value; if (nodeValue < minValue) minValue = nodeValue; if (nodeValue > maxValue) maxValue = nodeValue; beta = sumValue * sumValue * alpha; newRatio = Math.max(maxValue / beta, beta / minValue); if (newRatio > minRatio) { sumValue -= nodeValue; break; } minRatio = newRatio; } // Position and record the row orientation. rows.push(row = {value: sumValue, dice: dx < dy, children: nodes.slice(i0, i1)}); if (row.dice) treemapDice(row, x0, y0, x1, value ? y0 += dy * sumValue / value : y1); else treemapSlice(row, x0, y0, value ? x0 += dx * sumValue / value : x1, y1); value -= sumValue, i0 = i1; } return rows; } var treemapSquarify = (function custom(ratio) { function squarify(parent, x0, y0, x1, y1) { squarifyRatio(ratio, parent, x0, y0, x1, y1); } squarify.ratio = function(x) { return custom((x = +x) > 1 ? x : 1); }; return squarify; })(phi); var treemap = function() { var tile = treemapSquarify, round = false, dx = 1, dy = 1, paddingStack = [0], paddingInner = constantZero, paddingTop = constantZero, paddingRight = constantZero, paddingBottom = constantZero, paddingLeft = constantZero; function treemap(root) { root.x0 = root.y0 = 0; root.x1 = dx; root.y1 = dy; root.eachBefore(positionNode); paddingStack = [0]; if (round) root.eachBefore(roundNode); return root; } function positionNode(node) { var p = paddingStack[node.depth], x0 = node.x0 + p, y0 = node.y0 + p, x1 = node.x1 - p, y1 = node.y1 - p; if (x1 < x0) x0 = x1 = (x0 + x1) / 2; if (y1 < y0) y0 = y1 = (y0 + y1) / 2; node.x0 = x0; node.y0 = y0; node.x1 = x1; node.y1 = y1; if (node.children) { p = paddingStack[node.depth + 1] = paddingInner(node) / 2; x0 += paddingLeft(node) - p; y0 += paddingTop(node) - p; x1 -= paddingRight(node) - p; y1 -= paddingBottom(node) - p; if (x1 < x0) x0 = x1 = (x0 + x1) / 2; if (y1 < y0) y0 = y1 = (y0 + y1) / 2; tile(node, x0, y0, x1, y1); } } treemap.round = function(x) { return arguments.length ? (round = !!x, treemap) : round; }; treemap.size = function(x) { return arguments.length ? (dx = +x[0], dy = +x[1], treemap) : [dx, dy]; }; treemap.tile = function(x) { return arguments.length ? (tile = required(x), treemap) : tile; }; treemap.padding = function(x) { return arguments.length ? treemap.paddingInner(x).paddingOuter(x) : treemap.paddingInner(); }; treemap.paddingInner = function(x) { return arguments.length ? (paddingInner = typeof x === "function" ? x : constant$9(+x), treemap) : paddingInner; }; treemap.paddingOuter = function(x) { return arguments.length ? treemap.paddingTop(x).paddingRight(x).paddingBottom(x).paddingLeft(x) : treemap.paddingTop(); }; treemap.paddingTop = function(x) { return arguments.length ? (paddingTop = typeof x === "function" ? x : constant$9(+x), treemap) : paddingTop; }; treemap.paddingRight = function(x) { return arguments.length ? (paddingRight = typeof x === "function" ? x : constant$9(+x), treemap) : paddingRight; }; treemap.paddingBottom = function(x) { return arguments.length ? (paddingBottom = typeof x === "function" ? x : constant$9(+x), treemap) : paddingBottom; }; treemap.paddingLeft = function(x) { return arguments.length ? (paddingLeft = typeof x === "function" ? x : constant$9(+x), treemap) : paddingLeft; }; return treemap; }; var treemapBinary = function(parent, x0, y0, x1, y1) { var nodes = parent.children, i, n = nodes.length, sum, sums = new Array(n + 1); for (sums[0] = sum = i = 0; i < n; ++i) { sums[i + 1] = sum += nodes[i].value; } partition(0, n, parent.value, x0, y0, x1, y1); function partition(i, j, value, x0, y0, x1, y1) { if (i >= j - 1) { var node = nodes[i]; node.x0 = x0, node.y0 = y0; node.x1 = x1, node.y1 = y1; return; } var valueOffset = sums[i], valueTarget = (value / 2) + valueOffset, k = i + 1, hi = j - 1; while (k < hi) { var mid = k + hi >>> 1; if (sums[mid] < valueTarget) k = mid + 1; else hi = mid; } if ((valueTarget - sums[k - 1]) < (sums[k] - valueTarget) && i + 1 < k) --k; var valueLeft = sums[k] - valueOffset, valueRight = value - valueLeft; if ((x1 - x0) > (y1 - y0)) { var xk = (x0 * valueRight + x1 * valueLeft) / value; partition(i, k, valueLeft, x0, y0, xk, y1); partition(k, j, valueRight, xk, y0, x1, y1); } else { var yk = (y0 * valueRight + y1 * valueLeft) / value; partition(i, k, valueLeft, x0, y0, x1, yk); partition(k, j, valueRight, x0, yk, x1, y1); } } }; var treemapSliceDice = function(parent, x0, y0, x1, y1) { (parent.depth & 1 ? treemapSlice : treemapDice)(parent, x0, y0, x1, y1); }; var treemapResquarify = (function custom(ratio) { function resquarify(parent, x0, y0, x1, y1) { if ((rows = parent._squarify) && (rows.ratio === ratio)) { var rows, row, nodes, i, j = -1, n, m = rows.length, value = parent.value; while (++j < m) { row = rows[j], nodes = row.children; for (i = row.value = 0, n = nodes.length; i < n; ++i) row.value += nodes[i].value; if (row.dice) treemapDice(row, x0, y0, x1, y0 += (y1 - y0) * row.value / value); else treemapSlice(row, x0, y0, x0 += (x1 - x0) * row.value / value, y1); value -= row.value; } } else { parent._squarify = rows = squarifyRatio(ratio, parent, x0, y0, x1, y1); rows.ratio = ratio; } } resquarify.ratio = function(x) { return custom((x = +x) > 1 ? x : 1); }; return resquarify; })(phi); /** * Nest tuples into a tree structure, grouped by key values. * @constructor * @param {object} params - The parameters for this operator. * @param {Array} params.keys - The key fields to nest by, in order. * @param {function(object): *} [params.key] - Unique key field for each tuple. * If not provided, the tuple id field is used. * @param {boolean} [params.generate=false] - A boolean flag indicating if * non-leaf nodes generated by this transform should be included in the * output. The default (false) includes only the input data (leaf nodes) * in the data stream. */ function Nest(params) { Transform.call(this, null, params); } Nest.Definition = { "type": "Nest", "metadata": {"treesource": true, "source": true, "generates": true, "changes": true}, "params": [ { "name": "keys", "type": "field", "array": true }, { "name": "key", "type": "field" }, { "name": "generate", "type": "boolean" } ] }; var prototype$68 = inherits(Nest, Transform); function children(n) { return n.values; } prototype$68.transform = function(_, pulse) { if (!pulse.source) { error$1('Nest transform requires an upstream data source.'); } var key$$1 = _.key || tupleid, gen = _.generate, mod = _.modified(), out = gen || mod ? pulse.fork(pulse.ALL) : pulse, root, tree, map$$1; if (!this.value || mod || pulse.changed()) { // collect nodes to remove if (gen && this.value) { out.materialize(out.REM); this.value.each(function(node) { if (node.children) out.rem.push(node); }); } // generate new tree structure root = array(_.keys) .reduce(function(n, k) { n.key(k); return n; }, nest()) .entries(pulse.source); this.value = tree = hierarchy({values: root}, children); // collect nodes to add if (gen) { out.materialize(out.ADD); out.source = out.source.slice(); tree.each(function(node) { if (node.children) { node = ingest(node.data); out.add.push(node); out.source.push(node); } }); } // build lookup table map$$1 = tree.lookup = {}; tree.each(function(node) { if (tupleid(node.data) != null) { map$$1[key$$1(node.data)] = node; } }); } out.source.root = this.value; return out; }; /** * Abstract class for tree layout. * @constructor * @param {object} params - The parameters for this operator. */ function HierarchyLayout(params) { Transform.call(this, null, params); } var prototype$70 = inherits(HierarchyLayout, Transform); prototype$70.transform = function(_, pulse) { if (!pulse.source || !pulse.source.root) { error$1(this.constructor.name + ' transform requires a backing tree data source.'); } var layout = this.layout(_.method), fields = this.fields, root = pulse.source.root, as = _.as || fields; if (_.field) root.sum(_.field); if (_.sort) root.sort(_.sort); setParams(layout, this.params, _); try { this.value = layout(root); } catch (err) { error$1(err); } root.each(function(node) { setFields(node, fields, as); }); return pulse.reflow(_.modified()).modifies(as).modifies('leaf'); }; function setParams(layout, params, _) { for (var p, i=0, n=params.length; i 0) return; r /= dx; if (dx < 0) { if (r < t0) return; if (r < t1) t1 = r; } else if (dx > 0) { if (r > t1) return; if (r > t0) t0 = r; } r = x1 - ax; if (!dx && r < 0) return; r /= dx; if (dx < 0) { if (r > t1) return; if (r > t0) t0 = r; } else if (dx > 0) { if (r < t0) return; if (r < t1) t1 = r; } r = y0 - ay; if (!dy && r > 0) return; r /= dy; if (dy < 0) { if (r < t0) return; if (r < t1) t1 = r; } else if (dy > 0) { if (r > t1) return; if (r > t0) t0 = r; } r = y1 - ay; if (!dy && r < 0) return; r /= dy; if (dy < 0) { if (r > t1) return; if (r > t0) t0 = r; } else if (dy > 0) { if (r < t0) return; if (r < t1) t1 = r; } if (!(t0 > 0) && !(t1 < 1)) return true; // TODO Better check? if (t0 > 0) edge[0] = [ax + t0 * dx, ay + t0 * dy]; if (t1 < 1) edge[1] = [ax + t1 * dx, ay + t1 * dy]; return true; } function connectEdge(edge, x0, y0, x1, y1) { var v1 = edge[1]; if (v1) return true; var v0 = edge[0], left = edge.left, right = edge.right, lx = left[0], ly = left[1], rx = right[0], ry = right[1], fx = (lx + rx) / 2, fy = (ly + ry) / 2, fm, fb; if (ry === ly) { if (fx < x0 || fx >= x1) return; if (lx > rx) { if (!v0) v0 = [fx, y0]; else if (v0[1] >= y1) return; v1 = [fx, y1]; } else { if (!v0) v0 = [fx, y1]; else if (v0[1] < y0) return; v1 = [fx, y0]; } } else { fm = (lx - rx) / (ry - ly); fb = fy - fm * fx; if (fm < -1 || fm > 1) { if (lx > rx) { if (!v0) v0 = [(y0 - fb) / fm, y0]; else if (v0[1] >= y1) return; v1 = [(y1 - fb) / fm, y1]; } else { if (!v0) v0 = [(y1 - fb) / fm, y1]; else if (v0[1] < y0) return; v1 = [(y0 - fb) / fm, y0]; } } else { if (ly < ry) { if (!v0) v0 = [x0, fm * x0 + fb]; else if (v0[0] >= x1) return; v1 = [x1, fm * x1 + fb]; } else { if (!v0) v0 = [x1, fm * x1 + fb]; else if (v0[0] < x0) return; v1 = [x0, fm * x0 + fb]; } } } edge[0] = v0; edge[1] = v1; return true; } function clipEdges(x0, y0, x1, y1) { var i = edges.length, edge; while (i--) { if (!connectEdge(edge = edges[i], x0, y0, x1, y1) || !clipEdge(edge, x0, y0, x1, y1) || !(Math.abs(edge[0][0] - edge[1][0]) > epsilon$3 || Math.abs(edge[0][1] - edge[1][1]) > epsilon$3)) { delete edges[i]; } } } function createCell(site) { return cells[site.index] = { site: site, halfedges: [] }; } function cellHalfedgeAngle(cell, edge) { var site = cell.site, va = edge.left, vb = edge.right; if (site === vb) vb = va, va = site; if (vb) return Math.atan2(vb[1] - va[1], vb[0] - va[0]); if (site === va) va = edge[1], vb = edge[0]; else va = edge[0], vb = edge[1]; return Math.atan2(va[0] - vb[0], vb[1] - va[1]); } function cellHalfedgeStart(cell, edge) { return edge[+(edge.left !== cell.site)]; } function cellHalfedgeEnd(cell, edge) { return edge[+(edge.left === cell.site)]; } function sortCellHalfedges() { for (var i = 0, n = cells.length, cell, halfedges, j, m; i < n; ++i) { if ((cell = cells[i]) && (m = (halfedges = cell.halfedges).length)) { var index = new Array(m), array = new Array(m); for (j = 0; j < m; ++j) index[j] = j, array[j] = cellHalfedgeAngle(cell, edges[halfedges[j]]); index.sort(function(i, j) { return array[j] - array[i]; }); for (j = 0; j < m; ++j) array[j] = halfedges[index[j]]; for (j = 0; j < m; ++j) halfedges[j] = array[j]; } } } function clipCells(x0, y0, x1, y1) { var nCells = cells.length, iCell, cell, site, iHalfedge, halfedges, nHalfedges, start, startX, startY, end, endX, endY, cover = true; for (iCell = 0; iCell < nCells; ++iCell) { if (cell = cells[iCell]) { site = cell.site; halfedges = cell.halfedges; iHalfedge = halfedges.length; // Remove any dangling clipped edges. while (iHalfedge--) { if (!edges[halfedges[iHalfedge]]) { halfedges.splice(iHalfedge, 1); } } // Insert any border edges as necessary. iHalfedge = 0, nHalfedges = halfedges.length; while (iHalfedge < nHalfedges) { end = cellHalfedgeEnd(cell, edges[halfedges[iHalfedge]]), endX = end[0], endY = end[1]; start = cellHalfedgeStart(cell, edges[halfedges[++iHalfedge % nHalfedges]]), startX = start[0], startY = start[1]; if (Math.abs(endX - startX) > epsilon$3 || Math.abs(endY - startY) > epsilon$3) { halfedges.splice(iHalfedge, 0, edges.push(createBorderEdge(site, end, Math.abs(endX - x0) < epsilon$3 && y1 - endY > epsilon$3 ? [x0, Math.abs(startX - x0) < epsilon$3 ? startY : y1] : Math.abs(endY - y1) < epsilon$3 && x1 - endX > epsilon$3 ? [Math.abs(startY - y1) < epsilon$3 ? startX : x1, y1] : Math.abs(endX - x1) < epsilon$3 && endY - y0 > epsilon$3 ? [x1, Math.abs(startX - x1) < epsilon$3 ? startY : y0] : Math.abs(endY - y0) < epsilon$3 && endX - x0 > epsilon$3 ? [Math.abs(startY - y0) < epsilon$3 ? startX : x0, y0] : null)) - 1); ++nHalfedges; } } if (nHalfedges) cover = false; } } // If there weren’t any edges, have the closest site cover the extent. // It doesn’t matter which corner of the extent we measure! if (cover) { var dx, dy, d2, dc = Infinity; for (iCell = 0, cover = null; iCell < nCells; ++iCell) { if (cell = cells[iCell]) { site = cell.site; dx = site[0] - x0; dy = site[1] - y0; d2 = dx * dx + dy * dy; if (d2 < dc) dc = d2, cover = cell; } } if (cover) { var v00 = [x0, y0], v01 = [x0, y1], v11 = [x1, y1], v10 = [x1, y0]; cover.halfedges.push( edges.push(createBorderEdge(site = cover.site, v00, v01)) - 1, edges.push(createBorderEdge(site, v01, v11)) - 1, edges.push(createBorderEdge(site, v11, v10)) - 1, edges.push(createBorderEdge(site, v10, v00)) - 1 ); } } // Lastly delete any cells with no edges; these were entirely clipped. for (iCell = 0; iCell < nCells; ++iCell) { if (cell = cells[iCell]) { if (!cell.halfedges.length) { delete cells[iCell]; } } } } var circlePool = []; var firstCircle; function Circle() { RedBlackNode(this); this.x = this.y = this.arc = this.site = this.cy = null; } function attachCircle(arc) { var lArc = arc.P, rArc = arc.N; if (!lArc || !rArc) return; var lSite = lArc.site, cSite = arc.site, rSite = rArc.site; if (lSite === rSite) return; var bx = cSite[0], by = cSite[1], ax = lSite[0] - bx, ay = lSite[1] - by, cx = rSite[0] - bx, cy = rSite[1] - by; var d = 2 * (ax * cy - ay * cx); if (d >= -epsilon2$2) return; var ha = ax * ax + ay * ay, hc = cx * cx + cy * cy, x = (cy * ha - ay * hc) / d, y = (ax * hc - cx * ha) / d; var circle = circlePool.pop() || new Circle; circle.arc = arc; circle.site = cSite; circle.x = x + bx; circle.y = (circle.cy = y + by) + Math.sqrt(x * x + y * y); // y bottom arc.circle = circle; var before = null, node = circles._; while (node) { if (circle.y < node.y || (circle.y === node.y && circle.x <= node.x)) { if (node.L) node = node.L; else { before = node.P; break; } } else { if (node.R) node = node.R; else { before = node; break; } } } circles.insert(before, circle); if (!before) firstCircle = circle; } function detachCircle(arc) { var circle = arc.circle; if (circle) { if (!circle.P) firstCircle = circle.N; circles.remove(circle); circlePool.push(circle); RedBlackNode(circle); arc.circle = null; } } var beachPool = []; function Beach() { RedBlackNode(this); this.edge = this.site = this.circle = null; } function createBeach(site) { var beach = beachPool.pop() || new Beach; beach.site = site; return beach; } function detachBeach(beach) { detachCircle(beach); beaches.remove(beach); beachPool.push(beach); RedBlackNode(beach); } function removeBeach(beach) { var circle = beach.circle, x = circle.x, y = circle.cy, vertex = [x, y], previous = beach.P, next = beach.N, disappearing = [beach]; detachBeach(beach); var lArc = previous; while (lArc.circle && Math.abs(x - lArc.circle.x) < epsilon$3 && Math.abs(y - lArc.circle.cy) < epsilon$3) { previous = lArc.P; disappearing.unshift(lArc); detachBeach(lArc); lArc = previous; } disappearing.unshift(lArc); detachCircle(lArc); var rArc = next; while (rArc.circle && Math.abs(x - rArc.circle.x) < epsilon$3 && Math.abs(y - rArc.circle.cy) < epsilon$3) { next = rArc.N; disappearing.push(rArc); detachBeach(rArc); rArc = next; } disappearing.push(rArc); detachCircle(rArc); var nArcs = disappearing.length, iArc; for (iArc = 1; iArc < nArcs; ++iArc) { rArc = disappearing[iArc]; lArc = disappearing[iArc - 1]; setEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex); } lArc = disappearing[0]; rArc = disappearing[nArcs - 1]; rArc.edge = createEdge(lArc.site, rArc.site, null, vertex); attachCircle(lArc); attachCircle(rArc); } function addBeach(site) { var x = site[0], directrix = site[1], lArc, rArc, dxl, dxr, node = beaches._; while (node) { dxl = leftBreakPoint(node, directrix) - x; if (dxl > epsilon$3) node = node.L; else { dxr = x - rightBreakPoint(node, directrix); if (dxr > epsilon$3) { if (!node.R) { lArc = node; break; } node = node.R; } else { if (dxl > -epsilon$3) { lArc = node.P; rArc = node; } else if (dxr > -epsilon$3) { lArc = node; rArc = node.N; } else { lArc = rArc = node; } break; } } } createCell(site); var newArc = createBeach(site); beaches.insert(lArc, newArc); if (!lArc && !rArc) return; if (lArc === rArc) { detachCircle(lArc); rArc = createBeach(lArc.site); beaches.insert(newArc, rArc); newArc.edge = rArc.edge = createEdge(lArc.site, newArc.site); attachCircle(lArc); attachCircle(rArc); return; } if (!rArc) { // && lArc newArc.edge = createEdge(lArc.site, newArc.site); return; } // else lArc !== rArc detachCircle(lArc); detachCircle(rArc); var lSite = lArc.site, ax = lSite[0], ay = lSite[1], bx = site[0] - ax, by = site[1] - ay, rSite = rArc.site, cx = rSite[0] - ax, cy = rSite[1] - ay, d = 2 * (bx * cy - by * cx), hb = bx * bx + by * by, hc = cx * cx + cy * cy, vertex = [(cy * hb - by * hc) / d + ax, (bx * hc - cx * hb) / d + ay]; setEdgeEnd(rArc.edge, lSite, rSite, vertex); newArc.edge = createEdge(lSite, site, null, vertex); rArc.edge = createEdge(site, rSite, null, vertex); attachCircle(lArc); attachCircle(rArc); } function leftBreakPoint(arc, directrix) { var site = arc.site, rfocx = site[0], rfocy = site[1], pby2 = rfocy - directrix; if (!pby2) return rfocx; var lArc = arc.P; if (!lArc) return -Infinity; site = lArc.site; var lfocx = site[0], lfocy = site[1], plby2 = lfocy - directrix; if (!plby2) return lfocx; var hl = lfocx - rfocx, aby2 = 1 / pby2 - 1 / plby2, b = hl / plby2; if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx; return (rfocx + lfocx) / 2; } function rightBreakPoint(arc, directrix) { var rArc = arc.N; if (rArc) return leftBreakPoint(rArc, directrix); var site = arc.site; return site[1] === directrix ? site[0] : Infinity; } var epsilon$3 = 1e-6; var epsilon2$2 = 1e-12; var beaches; var cells; var circles; var edges; function triangleArea(a, b, c) { return (a[0] - c[0]) * (b[1] - a[1]) - (a[0] - b[0]) * (c[1] - a[1]); } function lexicographic(a, b) { return b[1] - a[1] || b[0] - a[0]; } function Diagram(sites, extent) { var site = sites.sort(lexicographic).pop(), x, y, circle; edges = []; cells = new Array(sites.length); beaches = new RedBlackTree; circles = new RedBlackTree; while (true) { circle = firstCircle; if (site && (!circle || site[1] < circle.y || (site[1] === circle.y && site[0] < circle.x))) { if (site[0] !== x || site[1] !== y) { addBeach(site); x = site[0], y = site[1]; } site = sites.pop(); } else if (circle) { removeBeach(circle.arc); } else { break; } } sortCellHalfedges(); if (extent) { var x0 = +extent[0][0], y0 = +extent[0][1], x1 = +extent[1][0], y1 = +extent[1][1]; clipEdges(x0, y0, x1, y1); clipCells(x0, y0, x1, y1); } this.edges = edges; this.cells = cells; beaches = circles = edges = cells = null; } Diagram.prototype = { constructor: Diagram, polygons: function() { var edges = this.edges; return this.cells.map(function(cell) { var polygon = cell.halfedges.map(function(i) { return cellHalfedgeStart(cell, edges[i]); }); polygon.data = cell.site.data; return polygon; }); }, triangles: function() { var triangles = [], edges = this.edges; this.cells.forEach(function(cell, i) { if (!(m = (halfedges = cell.halfedges).length)) return; var site = cell.site, halfedges, j = -1, m, s0, e1 = edges[halfedges[m - 1]], s1 = e1.left === site ? e1.right : e1.left; while (++j < m) { s0 = s1; e1 = edges[halfedges[j]]; s1 = e1.left === site ? e1.right : e1.left; if (s0 && s1 && i < s0.index && i < s1.index && triangleArea(site, s0, s1) < 0) { triangles.push([site.data, s0.data, s1.data]); } } }); return triangles; }, links: function() { return this.edges.filter(function(edge) { return edge.right; }).map(function(edge) { return { source: edge.left.data, target: edge.right.data }; }); }, find: function(x, y, radius) { var that = this, i0, i1 = that._found || 0, n = that.cells.length, cell; // Use the previously-found cell, or start with an arbitrary one. while (!(cell = that.cells[i1])) if (++i1 >= n) return null; var dx = x - cell.site[0], dy = y - cell.site[1], d2 = dx * dx + dy * dy; // Traverse the half-edges to find a closer cell, if any. do { cell = that.cells[i0 = i1], i1 = null; cell.halfedges.forEach(function(e) { var edge = that.edges[e], v = edge.left; if ((v === cell.site || !v) && !(v = edge.right)) return; var vx = x - v[0], vy = y - v[1], v2 = vx * vx + vy * vy; if (v2 < d2) d2 = v2, i1 = v.index; }); } while (i1 !== null); that._found = i0; return radius == null || d2 <= radius * radius ? cell.site : null; } }; var voronoi$1 = function() { var x = x$4, y = y$4, extent = null; function voronoi(data) { return new Diagram(data.map(function(d, i) { var s = [Math.round(x(d, i, data) / epsilon$3) * epsilon$3, Math.round(y(d, i, data) / epsilon$3) * epsilon$3]; s.index = i; s.data = d; return s; }), extent); } voronoi.polygons = function(data) { return voronoi(data).polygons(); }; voronoi.links = function(data) { return voronoi(data).links(); }; voronoi.triangles = function(data) { return voronoi(data).triangles(); }; voronoi.x = function(_) { return arguments.length ? (x = typeof _ === "function" ? _ : constant$10(+_), voronoi) : x; }; voronoi.y = function(_) { return arguments.length ? (y = typeof _ === "function" ? _ : constant$10(+_), voronoi) : y; }; voronoi.extent = function(_) { return arguments.length ? (extent = _ == null ? null : [[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]], voronoi) : extent && [[extent[0][0], extent[0][1]], [extent[1][0], extent[1][1]]]; }; voronoi.size = function(_) { return arguments.length ? (extent = _ == null ? null : [[0, 0], [+_[0], +_[1]]], voronoi) : extent && [extent[1][0] - extent[0][0], extent[1][1] - extent[0][1]]; }; return voronoi; }; function Voronoi(params) { Transform.call(this, null, params); } Voronoi.Definition = { "type": "Voronoi", "metadata": {"modifies": true}, "params": [ { "name": "x", "type": "field", "required": true }, { "name": "y", "type": "field", "required": true }, { "name": "size", "type": "number", "array": true, "length": 2 }, { "name": "extent", "type": "array", "array": true, "length": 2, "default": [[-1e5, -1e5], [1e5, 1e5]], "content": {"type": "number", "array": true, "length": 2} }, { "name": "as", "type": "string", "default": "path" } ] }; var prototype$76 = inherits(Voronoi, Transform); var defaultExtent = [[-1e5, -1e5], [1e5, 1e5]]; prototype$76.transform = function(_, pulse) { var as = _.as || 'path', data = pulse.source, diagram, polygons, i, n; // configure and construct voronoi diagram diagram = voronoi$1().x(_.x).y(_.y); if (_.size) diagram.size(_.size); else diagram.extent(_.extent || defaultExtent); this.value = (diagram = diagram(data)); // map polygons to paths polygons = diagram.polygons(); for (i=0, n=data.length; i> 5; var ch = 1 << 11; var cloud = function() { var size = [256, 256], text, font, fontSize, fontStyle, fontWeight, rotate, padding, spiral = archimedeanSpiral, words = [], random = Math.random, cloud = {}, canvas = cloudCanvas; cloud.layout = function() { var contextAndRatio = getContext(canvas()), board = zeroArray((size[0] >> 5) * size[1]), bounds = null, n = words.length, i = -1, tags = [], data = words.map(function(d) { return { text: text(d), font: font(d), style: fontStyle(d), weight: fontWeight(d), rotate: rotate(d), size: ~~fontSize(d), padding: padding(d), xoff: 0, yoff: 0, x1: 0, y1: 0, x0: 0, y0: 0, hasText: false, sprite: null, datum: d }; }).sort(function(a, b) { return b.size - a.size; }); while (++i < n) { var d = data[i]; d.x = (size[0] * (random() + .5)) >> 1; d.y = (size[1] * (random() + .5)) >> 1; cloudSprite(contextAndRatio, d, data, i); if (d.hasText && place(board, d, bounds)) { tags.push(d); if (bounds) cloudBounds(bounds, d); else bounds = [{x: d.x + d.x0, y: d.y + d.y0}, {x: d.x + d.x1, y: d.y + d.y1}]; // Temporary hack d.x -= size[0] >> 1; d.y -= size[1] >> 1; } } return tags; }; function getContext(canvas) { canvas.width = canvas.height = 1; var ratio = Math.sqrt(canvas.getContext("2d").getImageData(0, 0, 1, 1).data.length >> 2); canvas.width = (cw << 5) / ratio; canvas.height = ch / ratio; var context = canvas.getContext("2d"); context.fillStyle = context.strokeStyle = "red"; context.textAlign = "center"; return {context: context, ratio: ratio}; } function place(board, tag, bounds) { var startX = tag.x, startY = tag.y, maxDelta = Math.sqrt(size[0] * size[0] + size[1] * size[1]), s = spiral(size), dt = random() < .5 ? 1 : -1, t = -dt, dxdy, dx, dy; while (dxdy = s(t += dt)) { dx = ~~dxdy[0]; dy = ~~dxdy[1]; if (Math.min(Math.abs(dx), Math.abs(dy)) >= maxDelta) break; tag.x = startX + dx; tag.y = startY + dy; if (tag.x + tag.x0 < 0 || tag.y + tag.y0 < 0 || tag.x + tag.x1 > size[0] || tag.y + tag.y1 > size[1]) continue; // TODO only check for collisions within current bounds. if (!bounds || !cloudCollide(tag, board, size[0])) { if (!bounds || collideRects(tag, bounds)) { var sprite = tag.sprite, w = tag.width >> 5, sw = size[0] >> 5, lx = tag.x - (w << 4), sx = lx & 0x7f, msx = 32 - sx, h = tag.y1 - tag.y0, x = (tag.y + tag.y0) * sw + (lx >> 5), last; for (var j = 0; j < h; j++) { last = 0; for (var i = 0; i <= w; i++) { board[x + i] |= (last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0); } x += sw; } tag.sprite = null; return true; } } } return false; } cloud.words = function(_) { if (arguments.length) { words = _; return cloud; } else { return words; } }; cloud.size = function(_) { if (arguments.length) { size = [+_[0], +_[1]]; return cloud; } else { return size; } }; cloud.font = function(_) { if (arguments.length) { font = functor(_); return cloud; } else { return font; } }; cloud.fontStyle = function(_) { if (arguments.length) { fontStyle = functor(_); return cloud; } else { return fontStyle; } }; cloud.fontWeight = function(_) { if (arguments.length) { fontWeight = functor(_); return cloud; } else { return fontWeight; } }; cloud.rotate = function(_) { if (arguments.length) { rotate = functor(_); return cloud; } else { return rotate; } }; cloud.text = function(_) { if (arguments.length) { text = functor(_); return cloud; } else { return text; } }; cloud.spiral = function(_) { if (arguments.length) { spiral = spirals[_] || _; return cloud; } else { return spiral; } }; cloud.fontSize = function(_) { if (arguments.length) { fontSize = functor(_); return cloud; } else { return fontSize; } }; cloud.padding = function(_) { if (arguments.length) { padding = functor(_); return cloud; } else { return padding; } }; cloud.random = function(_) { if (arguments.length) { random = _; return cloud; } else { return random; } }; return cloud; }; // Fetches a monochrome sprite bitmap for the specified text. // Load in batches for speed. function cloudSprite(contextAndRatio, d, data, di) { if (d.sprite) return; var c = contextAndRatio.context, ratio = contextAndRatio.ratio; c.clearRect(0, 0, (cw << 5) / ratio, ch / ratio); var x = 0, y = 0, maxh = 0, n = data.length, w, w32, h, i, j; --di; while (++di < n) { d = data[di]; c.save(); c.font = d.style + " " + d.weight + " " + ~~((d.size + 1) / ratio) + "px " + d.font; w = c.measureText(d.text + "m").width * ratio; h = d.size << 1; if (d.rotate) { var sr = Math.sin(d.rotate * cloudRadians), cr = Math.cos(d.rotate * cloudRadians), wcr = w * cr, wsr = w * sr, hcr = h * cr, hsr = h * sr; w = (Math.max(Math.abs(wcr + hsr), Math.abs(wcr - hsr)) + 0x1f) >> 5 << 5; h = ~~Math.max(Math.abs(wsr + hcr), Math.abs(wsr - hcr)); } else { w = (w + 0x1f) >> 5 << 5; } if (h > maxh) maxh = h; if (x + w >= (cw << 5)) { x = 0; y += maxh; maxh = 0; } if (y + h >= ch) break; c.translate((x + (w >> 1)) / ratio, (y + (h >> 1)) / ratio); if (d.rotate) c.rotate(d.rotate * cloudRadians); c.fillText(d.text, 0, 0); if (d.padding) { c.lineWidth = 2 * d.padding; c.strokeText(d.text, 0, 0); } c.restore(); d.width = w; d.height = h; d.xoff = x; d.yoff = y; d.x1 = w >> 1; d.y1 = h >> 1; d.x0 = -d.x1; d.y0 = -d.y1; d.hasText = true; x += w; } var pixels = c.getImageData(0, 0, (cw << 5) / ratio, ch / ratio).data, sprite = []; while (--di >= 0) { d = data[di]; if (!d.hasText) continue; w = d.width; w32 = w >> 5; h = d.y1 - d.y0; // Zero the buffer for (i = 0; i < h * w32; i++) sprite[i] = 0; x = d.xoff; if (x == null) return; y = d.yoff; var seen = 0, seenRow = -1; for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { var k = w32 * j + (i >> 5), m = pixels[((y + j) * (cw << 5) + (x + i)) << 2] ? 1 << (31 - (i % 32)) : 0; sprite[k] |= m; seen |= m; } if (seen) seenRow = j; else { d.y0++; h--; j--; y++; } } d.y1 = d.y0 + seenRow; d.sprite = sprite.slice(0, (d.y1 - d.y0) * w32); } } // Use mask-based collision detection. function cloudCollide(tag, board, sw) { sw >>= 5; var sprite = tag.sprite, w = tag.width >> 5, lx = tag.x - (w << 4), sx = lx & 0x7f, msx = 32 - sx, h = tag.y1 - tag.y0, x = (tag.y + tag.y0) * sw + (lx >> 5), last; for (var j = 0; j < h; j++) { last = 0; for (var i = 0; i <= w; i++) { if (((last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0)) & board[x + i]) return true; } x += sw; } return false; } function cloudBounds(bounds, d) { var b0 = bounds[0], b1 = bounds[1]; if (d.x + d.x0 < b0.x) b0.x = d.x + d.x0; if (d.y + d.y0 < b0.y) b0.y = d.y + d.y0; if (d.x + d.x1 > b1.x) b1.x = d.x + d.x1; if (d.y + d.y1 > b1.y) b1.y = d.y + d.y1; } function collideRects(a, b) { return a.x + a.x1 > b[0].x && a.x + a.x0 < b[1].x && a.y + a.y1 > b[0].y && a.y + a.y0 < b[1].y; } function archimedeanSpiral(size) { var e = size[0] / size[1]; return function(t) { return [e * (t *= .1) * Math.cos(t), t * Math.sin(t)]; }; } function rectangularSpiral(size) { var dy = 4, dx = dy * size[0] / size[1], x = 0, y = 0; return function(t) { var sign = t < 0 ? -1 : 1; // See triangular numbers: T_n = n * (n + 1) / 2. switch ((Math.sqrt(1 + 4 * sign * t) - sign) & 3) { case 0: x += dx; break; case 1: y += dy; break; case 2: x -= dx; break; default: y -= dy; break; } return [x, y]; }; } // TODO reuse arrays? function zeroArray(n) { var a = [], i = -1; while (++i < n) a[i] = 0; return a; } function cloudCanvas() { try { var canvas = typeof document !== 'undefined' && document.createElement ? document.createElement('canvas') : 0; return canvas && canvas.getContext ? canvas : new (require('canvas'))(); } catch (e) { error$1('Canvas unavailable. Run in browser or install node-canvas.'); } } function functor(d) { return typeof d === "function" ? d : function() { return d; }; } var spirals = { archimedean: archimedeanSpiral, rectangular: rectangularSpiral }; var Output$4 = ['x', 'y', 'font', 'fontSize', 'fontStyle', 'fontWeight', 'angle']; var Params$1 = ['text', 'font', 'rotate', 'fontSize', 'fontStyle', 'fontWeight']; function Wordcloud(params) { Transform.call(this, cloud(), params); } Wordcloud.Definition = { "type": "Wordcloud", "metadata": {"modifies": true}, "params": [ { "name": "size", "type": "number", "array": true, "length": 2 }, { "name": "font", "type": "string", "expr": true, "default": "sans-serif" }, { "name": "fontStyle", "type": "string", "expr": true, "default": "normal" }, { "name": "fontWeight", "type": "string", "expr": true, "default": "normal" }, { "name": "fontSize", "type": "number", "expr": true, "default": 14 }, { "name": "fontSizeRange", "type": "number", "array": "nullable", "default": [10, 50] }, { "name": "rotate", "type": "number", "expr": true, "default": 0 }, { "name": "text", "type": "field" }, { "name": "spiral", "type": "string", "values": ["archimedean", "rectangular"] }, { "name": "padding", "type": "number", "expr": true }, { "name": "as", "type": "string", "array": true, "length": 7, "default": Output$4 } ] }; var prototype$77 = inherits(Wordcloud, Transform); prototype$77.transform = function(_, pulse) { function modp(param) { var p = _[param]; return isFunction(p) && pulse.modified(p.fields); } var mod = _.modified(); if (!(mod || pulse.changed(pulse.ADD_REM) || Params$1.some(modp))) return; var data = pulse.materialize(pulse.SOURCE).source, layout = this.value, as = _.as || Output$4, fontSize = _.fontSize || 14, range; isFunction(fontSize) ? (range = _.fontSizeRange) : (fontSize = constant(fontSize)); // create font size scaling function as needed if (range) { var fsize = fontSize, sizeScale = scale$1('sqrt')() .domain(extent$2(fsize, data)) .range(range); fontSize = function(x) { return sizeScale(fsize(x)); }; } data.forEach(function(t) { t[as[0]] = NaN; t[as[1]] = NaN; t[as[3]] = 0; }); // configure layout var words = layout .words(data) .text(_.text) .size(_.size || [500, 500]) .padding(_.padding || 1) .spiral(_.spiral || 'archimedean') .rotate(_.rotate || 0) .font(_.font || 'sans-serif') .fontStyle(_.fontStyle || 'normal') .fontWeight(_.fontWeight || 'normal') .fontSize(fontSize) .layout(); var size = layout.size(), dx = size[0] >> 1, dy = size[1] >> 1, i = 0, n = words.length, w, t; for (; i max) max = v; } return [min, max]; } var wordcloud = Object.freeze({ wordcloud: Wordcloud }); function array8(n) { return new Uint8Array(n); } function array16(n) { return new Uint16Array(n); } function array32(n) { return new Uint32Array(n); } /** * Maintains CrossFilter state. */ function Bitmaps() { var width = 8, data = [], seen = array32(0), curr = array$5(0, width), prev = array$5(0, width); return { data: function() { return data; }, seen: function() { return (seen = lengthen(seen, data.length)); }, add: function(array) { for (var i=0, j=data.length, n=array.length, t; i boolean (true => remove) var n = data.length, copy = Array(n - num), reindex = data, // reuse old data array for index map t, i, j; // seek forward to first removal for (i=0; !map[i] && i k || m > width) { width = Math.max(m, width); curr = array$5(n, width, curr); prev = array$5(n, width); } } }; } function lengthen(array, length, copy) { if (array.length >= length) return array; copy = copy || new array.constructor(length); copy.set(array); return copy; } function array$5(n, m, array) { var copy = (m < 0x101 ? array8 : m < 0x10001 ? array16 : array32)(n); if (array) copy.set(array); return copy; } var Dimension = function(index, i, query) { var bit = (1 << i); return { one: bit, zero: ~bit, range: query.slice(), bisect: index.bisect, index: index.index, size: index.size, onAdd: function(added, curr) { var dim = this, range = dim.bisect(dim.range, added.value), idx = added.index, lo = range[0], hi = range[1], n1 = idx.length, i; for (i=0; i 0) for (i=0; i remove var n = size, idx, i, j; // seek forward to first removal for (i=0; !map[index[i]] && i y ? 1 : 0; }); return permute(values, index); } function merge$3(base, value0, index0, n0, value1, index1, n1, value, index) { var i0 = 0, i1 = 0, i; for (i=0; i0 < n0 && i1 < n1; ++i) { if (value0[i0] < value1[i1]) { value[i] = value0[i0]; index[i] = index0[i0++]; } else { value[i] = value1[i1]; index[i] = index1[i1++] + base; } } for (; i0 < n0; ++i0, ++i) { value[i] = value0[i0]; index[i] = index0[i0]; } for (; i1 < n1; ++i1, ++i) { value[i] = value1[i1]; index[i] = index1[i1] + base; } } /** * An indexed multi-dimensional filter. * @constructor * @param {object} params - The parameters for this operator. * @param {Array} params.fields - An array of dimension accessors to filter. * @param {Array} params.query - An array of per-dimension range queries. */ function CrossFilter(params) { Transform.call(this, Bitmaps(), params); this._indices = null; this._dims = null; } CrossFilter.Definition = { "type": "CrossFilter", "metadata": {}, "params": [ { "name": "fields", "type": "field", "array": true, "required": true }, { "name": "query", "type": "array", "array": true, "required": true, "content": {"type": "number", "array": true, "length": 2} } ] }; var prototype$78 = inherits(CrossFilter, Transform); prototype$78.transform = function(_, pulse) { if (!this._dims) { return this.init(_, pulse); } else { var init = _.modified('fields') || _.fields.some(function(f) { return pulse.modified(f.fields); }); return init ? this.reinit(_, pulse) : this.eval(_, pulse); } }; prototype$78.init = function(_, pulse) { var fields = _.fields, query = _.query, indices = this._indices = {}, dims = this._dims = [], m = query.length, i = 0, key$$1, index; // instantiate indices and dimensions for (; i lo0) { for (i = lo0, j = Math.min(lo1, hi0); i < j; ++i) { k = index[i]; if (seen[k] !== stamp) { prev[k] = curr[k]; seen[k] = stamp; out.push(k); } curr[k] ^= one$$1; } } // Fast incremental update based on previous hi index. if (hi1 > hi0) { for (i = Math.max(lo1, hi0), j = hi1; i < j; ++i) { k = index[i]; if (seen[k] !== stamp) { prev[k] = curr[k]; seen[k] = stamp; out.push(k); } curr[k] ^= one$$1; } } else if (hi1 < hi0) { for (i = Math.max(lo0, hi1), j = hi0; i < j; ++i) { k = index[i]; if (seen[k] !== stamp) { prev[k] = curr[k]; seen[k] = stamp; out.push(k); } curr[k] ^= one$$1; } } dim.range = query.slice(); }; prototype$78.incrementOne = function(dim, query, add, rem) { var bits = this.value, curr = bits.curr(), index = dim.index(), old = dim.bisect(dim.range), range = dim.bisect(query), lo1 = range[0], hi1 = range[1], lo0 = old[0], hi0 = old[1], one$$1 = dim.one, i, j, k; // Fast incremental update based on previous lo index. if (lo1 < lo0) { for (i = lo1, j = Math.min(lo0, hi1); i < j; ++i) { k = index[i]; curr[k] ^= one$$1; add.push(k); } } else if (lo1 > lo0) { for (i = lo0, j = Math.min(lo1, hi0); i < j; ++i) { k = index[i]; curr[k] ^= one$$1; rem.push(k); } } // Fast incremental update based on previous hi index. if (hi1 > hi0) { for (i = Math.max(lo1, hi0), j = hi1; i < j; ++i) { k = index[i]; curr[k] ^= one$$1; add.push(k); } } else if (hi1 < hi0) { for (i = Math.max(lo0, hi1), j = hi0; i < j; ++i) { k = index[i]; curr[k] ^= one$$1; rem.push(k); } } dim.range = query.slice(); }; /** * Selectively filters tuples by resolving against a filter bitmap. * Useful for processing the output of a cross-filter transform. * @constructor * @param {object} params - The parameters for this operator. * @param {object} params.ignore - A bit mask indicating which filters to ignore. * @param {object} params.filter - The per-tuple filter bitmaps. Typically this * parameter value is a reference to a {@link CrossFilter} transform. */ function ResolveFilter(params) { Transform.call(this, null, params); } ResolveFilter.Definition = { "type": "ResolveFilter", "metadata": {}, "params": [ { "name": "ignore", "type": "number", "required": true, "description": "A bit mask indicating which filters to ignore." }, { "name": "filter", "type": "object", "required": true, "description": "Per-tuple filter bitmaps from a CrossFilter transform." } ] }; var prototype$79 = inherits(ResolveFilter, Transform); prototype$79.transform = function(_, pulse) { var ignore = ~(_.ignore || 0), // bit mask where zeros -> dims to ignore bitmap = _.filter, mask = bitmap.mask; // exit early if no relevant filter changes if ((mask & ignore) === 0) return pulse.StopPropagation; var output = pulse.fork(pulse.ALL), data = bitmap.data(), curr = bitmap.curr(), prev = bitmap.prev(), pass = function(k) { return !(curr[k] & ignore) ? data[k] : null; }; // propagate all mod tuples that pass the filter output.filter(output.MOD, pass); // determine add & rem tuples via filter functions // for efficiency, we do *not* populate new arrays, // instead we add filter functions applied downstream if (!(mask & (mask-1))) { // only one filter changed output.filter(output.ADD, pass); output.filter(output.REM, function(k) { return (curr[k] & ignore) === mask ? data[k] : null; }); } else { // multiple filters changed output.filter(output.ADD, function(k) { var c = curr[k] & ignore, f = !c && (c ^ (prev[k] & ignore)); return f ? data[k] : null; }); output.filter(output.REM, function(k) { var c = curr[k] & ignore, f = c && !(c ^ (c ^ (prev[k] & ignore))); return f ? data[k] : null; }); } // add filter to source data in case of reflow... return output.filter(output.SOURCE, function(t) { return pass(t._index); }); }; var xf = Object.freeze({ crossfilter: CrossFilter, resolvefilter: ResolveFilter }); var version = "3.0.2"; var Default = 'default'; var cursor = function(view) { var cursor = view._signals.cursor; // add cursor signal to dataflow, if needed if (!cursor) { view._signals.cursor = (cursor = view.add({user: Default, item: null})); } // evaluate cursor on each mousemove event view.on(view.events('view', 'mousemove'), cursor, function(_, event) { var value = cursor.value, user = value ? (isString(value) ? value : value.user) : Default, item = event.item && event.item.cursor || null; return (value && user === value.user && item == value.item) ? value : {user: user, item: item}; } ); // when cursor signal updates, set visible cursor view.add(null, function(_) { var user = _.cursor, item = this.value; if (!isString(user)) { item = user.item; user = user.user; } setCursor(user && user !== Default ? user : (item || user)); return item; }, {cursor: cursor}); }; function setCursor(cursor) { // set cursor on document body // this ensures cursor applies even if dragging out of view if (typeof document !== 'undefined' && document.body) { document.body.style.cursor = cursor; } } function dataref(view, name) { var data = view._runtime.data; if (!data.hasOwnProperty(name)) { error$1('Unrecognized data set: ' + name); } return data[name]; } function data(name) { return dataref(this, name).values.value; } function change(name, changes) { if (!isChangeSet(changes)) { error$1('Second argument to changes must be a changeset.'); } var dataset = dataref(this, name); dataset.modified = true; return this.pulse(dataset.input, changes); } function insert(name, _) { return change.call(this, name, changeset().insert(_)); } function remove(name, _) { return change.call(this, name, changeset().remove(_)); } function width(view) { var padding = view.padding(); return Math.max(0, view._viewWidth + padding.left + padding.right); } function height$1(view) { var padding = view.padding(); return Math.max(0, view._viewHeight + padding.top + padding.bottom); } function offset$1(view) { var padding = view.padding(), origin = view._origin; return [ padding.left + origin[0], padding.top + origin[1] ]; } function resizeRenderer(view) { var origin = offset$1(view); view._renderer.background(view._background); view._renderer.resize(width(view), height$1(view), origin); view._handler.origin(origin); } /** * Extend an event with additional view-specific methods. * Adds a new property ('vega') to an event that provides a number * of methods for querying information about the current interaction. * The vega object provides the following methods: * view - Returns the backing View instance. * item - Returns the currently active scenegraph item (if any). * group - Returns the currently active scenegraph group (if any). * This method accepts a single string-typed argument indicating the name * of the desired parent group. The scenegraph will be traversed from * the item up towards the root to search for a matching group. If no * argument is provided the enclosing group for the active item is * returned, unless the item it itself a group, in which case it is * returned directly. * xy - Returns a two-element array containing the x and y coordinates for * mouse or touch events. For touch events, this is based on the first * elements in the changedTouches array. This method accepts a single * argument: either an item instance or mark name that should serve as * the reference coordinate system. If no argument is provided the * top-level view coordinate system is assumed. * x - Returns the current x-coordinate, accepts the same arguments as xy. * y - Returns the current y-coordinate, accepts the same arguments as xy. * @param {Event} event - The input event to extend. * @param {Item} item - The currently active scenegraph item (if any). * @return {Event} - The extended input event. */ var eventExtend = function(view, event, item) { var el = view._renderer.scene(), p, e, translate; if (el) { translate = offset$1(view); e = event.changedTouches ? event.changedTouches[0] : event; p = point$4(e, el); p[0] -= translate[0]; p[1] -= translate[1]; } event.dataflow = view; event.vega = extension(view, item, p); event.item = item; return event; }; function extension(view, item, point) { var itemGroup = item ? item.mark.marktype === 'group' ? item : item.mark.group : null; function group(name) { var g = itemGroup, i; if (name) for (i = item; i; i = i.mark.group) { if (i.mark.name === name) { g = i; break; } } return g && g.mark && g.mark.interactive ? g : {}; } function xy(item) { if (!item) return point; if (isString(item)) item = group(item); var p = point.slice(); while (item) { p[0] -= item.x || 0; p[1] -= item.y || 0; item = item.mark && item.mark.group; } return p; } return { view: constant(view), item: constant(item || {}), group: group, xy: xy, x: function(item) { return xy(item)[0]; }, y: function(item) { return xy(item)[1]; } }; } var VIEW = 'view'; var WINDOW = 'window'; /** * Initialize event handling configuration. * @param {object} config - The configuration settings. * @return {object} */ function initializeEventConfig(config) { config = extend({}, config); var def = config.defaults; if (def) { if (isArray(def.prevent)) { def.prevent = toSet(def.prevent); } if (isArray(def.allow)) { def.allow = toSet(def.allow); } } return config; } function prevent(view, type) { var def = view._eventConfig.defaults, prevent = def && def.prevent, allow = def && def.allow; return prevent === false || allow === true ? false : prevent === true || allow === false ? true : prevent ? prevent[type] : allow ? !allow[type] : view.preventDefault(); } /** * Create a new event stream from an event source. * @param {object} source - The event source to monitor. * @param {string} type - The event type. * @param {function(object): boolean} [filter] - Event filter function. * @return {EventStream} */ function events$1(source, type, filter) { var view = this, s = new EventStream(filter), send = function(e, item) { if (source === VIEW && prevent(view, type)) { e.preventDefault(); } try { s.receive(eventExtend(view, e, item)); } catch (error) { view.error(error); } finally { view.run(); } }, sources; if (source === VIEW) { view.addEventListener(type, send); return s; } if (source === WINDOW) { if (typeof window !== 'undefined') sources = [window]; } else if (typeof document !== 'undefined') { sources = document.querySelectorAll(source); } if (!sources) { view.warn('Can not resolve event source: ' + source); return s; } for (var i=0, n=sources.length; i= 0) { e = listeners[n]; m = e.sources.length; while (--m >= 0) { e.sources[m].removeEventListener(e.type, e.handler); } } }; var element$1 = function(tag, attr, text) { var el = document.createElement(tag); for (var key in attr) el.setAttribute(key, attr[key]); if (text != null) el.textContent = text; return el; }; var BindClass = 'vega-bind'; var NameClass = 'vega-bind-name'; var RadioClass = 'vega-bind-radio'; var OptionClass = 'vega-option-'; /** * Bind a signal to an external HTML input element. The resulting two-way * binding will propagate input changes to signals, and propagate signal * changes to the input element state. If this view instance has no parent * element, we assume the view is headless and no bindings are created. * @param {Element|string} el - The parent DOM element to which the input * element should be appended as a child. If string-valued, this argument * will be treated as a CSS selector. If null or undefined, the parent * element of this view will be used as the element. * @param {object} param - The binding parameters which specify the signal * to bind to, the input element type, and type-specific configuration. * @return {View} - This view instance. */ var bind$1 = function(view, el, binding) { if (!el) return; var param = binding.param, bind = binding.state; if (!bind) { bind = binding.state = { elements: null, active: false, set: null, update: function(value) { bind.source = true; view.signal(param.signal, value).run(); } }; if (param.debounce) { bind.update = debounce(param.debounce, bind.update); } } if (isString(el)) el = document.querySelector(el); generate(bind, el, param, view.signal(param.signal)); if (!bind.active) { view.on(view._signals[param.signal], null, function() { bind.source ? (bind.source = false) : bind.set(view.signal(param.signal)); }); bind.active = true; } return bind; }; /** * Generate an HTML input form element and bind it to a signal. */ function generate(bind, el, param, value) { var div = element$1('div', {'class': BindClass}); div.appendChild(element$1('span', {'class': NameClass}, (param.name || param.signal) )); el.appendChild(div); var input = form; switch (param.input) { case 'checkbox': input = checkbox; break; case 'select': input = select; break; case 'radio': input = radio; break; case 'range': input = range$1; break; } input(bind, div, param, value); } /** * Generates an arbitrary input form element. * The input type is controlled via user-provided parameters. */ function form(bind, el, param, value) { var node = element$1('input'); for (var key$$1 in param) { if (key$$1 !== 'signal' && key$$1 !== 'element') { node.setAttribute(key$$1 === 'input' ? 'type' : key$$1, param[key$$1]); } } node.setAttribute('name', param.signal); node.value = value; el.appendChild(node); node.addEventListener('input', function() { bind.update(node.value); }); bind.elements = [node]; bind.set = function(value) { node.value = value; }; } /** * Generates a checkbox input element. */ function checkbox(bind, el, param, value) { var attr = {type: 'checkbox', name: param.signal}; if (value) attr.checked = true; var node = element$1('input', attr); el.appendChild(node); node.addEventListener('change', function() { bind.update(node.checked); }); bind.elements = [node]; bind.set = function(value) { node.checked = !!value || null; }; } /** * Generates a selection list input element. */ function select(bind, el, param, value) { var node = element$1('select', {name: param.signal}); param.options.forEach(function(option) { var attr = {value: option}; if (valuesEqual(option, value)) attr.selected = true; node.appendChild(element$1('option', attr, option+'')); }); el.appendChild(node); node.addEventListener('change', function() { bind.update(param.options[node.selectedIndex]); }); bind.elements = [node]; bind.set = function(value) { for (var i=0, n=param.options.length; i Copyright (C) 2013 Thaddee Tyl Copyright (C) 2013 Mathias Bynens Copyright (C) 2012 Ariya Hidayat Copyright (C) 2012 Mathias Bynens Copyright (C) 2012 Joost-Wim Boekesteijn Copyright (C) 2012 Kris Kowal Copyright (C) 2012 Yusuke Suzuki Copyright (C) 2012 Arpad Borsos Copyright (C) 2011 Ariya Hidayat Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ var source$1; var index$1; var length$2; var lookahead; var TokenBooleanLiteral = 1; var TokenEOF = 2; var TokenIdentifier = 3; var TokenKeyword = 4; var TokenNullLiteral = 5; var TokenNumericLiteral = 6; var TokenPunctuator = 7; var TokenStringLiteral = 8; var SyntaxArrayExpression = 'ArrayExpression'; var SyntaxBinaryExpression = 'BinaryExpression'; var SyntaxCallExpression = 'CallExpression'; var SyntaxConditionalExpression = 'ConditionalExpression'; var SyntaxIdentifier = 'Identifier'; var SyntaxLiteral = 'Literal'; var SyntaxLogicalExpression = 'LogicalExpression'; var SyntaxMemberExpression = 'MemberExpression'; var SyntaxObjectExpression = 'ObjectExpression'; var SyntaxProperty = 'Property'; var SyntaxUnaryExpression = 'UnaryExpression'; // Error messages should be identical to V8. var MessageUnexpectedToken = 'Unexpected token %0'; var MessageUnexpectedNumber = 'Unexpected number'; var MessageUnexpectedString = 'Unexpected string'; var MessageUnexpectedIdentifier = 'Unexpected identifier'; var MessageUnexpectedReserved = 'Unexpected reserved word'; var MessageUnexpectedEOS = 'Unexpected end of input'; var MessageInvalidRegExp = 'Invalid regular expression'; var MessageUnterminatedRegExp = 'Invalid regular expression: missing /'; var MessageStrictOctalLiteral = 'Octal literals are not allowed in strict mode.'; var MessageStrictDuplicateProperty = 'Duplicate data property in object literal not allowed in strict mode'; var ILLEGAL = 'ILLEGAL'; var DISABLED = 'Disabled.'; // See also tools/generate-unicode-regex.py. var RegexNonAsciiIdentifierStart = new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B2\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]'); var RegexNonAsciiIdentifierPart = new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B2\u08E4-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA69D\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2D\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]'); // Ensure the condition is true, otherwise throw an error. // This is only to have a better contract semantic, i.e. another safety net // to catch a logic error. The condition shall be fulfilled in normal case. // Do NOT use this to enforce a certain condition on any user input. function assert(condition, message) { /* istanbul ignore next */ if (!condition) { throw new Error('ASSERT: ' + message); } } function isDecimalDigit(ch) { return (ch >= 0x30 && ch <= 0x39); // 0..9 } function isHexDigit(ch) { return '0123456789abcdefABCDEF'.indexOf(ch) >= 0; } function isOctalDigit(ch) { return '01234567'.indexOf(ch) >= 0; } // 7.2 White Space function isWhiteSpace(ch) { return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) || (ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0); } // 7.3 Line Terminators function isLineTerminator(ch) { return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029); } // 7.6 Identifier Names and Identifiers function isIdentifierStart(ch) { return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore) (ch >= 0x41 && ch <= 0x5A) || // A..Z (ch >= 0x61 && ch <= 0x7A) || // a..z (ch === 0x5C) || // \ (backslash) ((ch >= 0x80) && RegexNonAsciiIdentifierStart.test(String.fromCharCode(ch))); } function isIdentifierPart(ch) { return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore) (ch >= 0x41 && ch <= 0x5A) || // A..Z (ch >= 0x61 && ch <= 0x7A) || // a..z (ch >= 0x30 && ch <= 0x39) || // 0..9 (ch === 0x5C) || // \ (backslash) ((ch >= 0x80) && RegexNonAsciiIdentifierPart.test(String.fromCharCode(ch))); } // 7.6.1.1 Keywords var keywords$1 = { 'if':1, 'in':1, 'do':1, 'var':1, 'for':1, 'new':1, 'try':1, 'let':1, 'this':1, 'else':1, 'case':1, 'void':1, 'with':1, 'enum':1, 'while':1, 'break':1, 'catch':1, 'throw':1, 'const':1, 'yield':1, 'class':1, 'super':1, 'return':1, 'typeof':1, 'delete':1, 'switch':1, 'export':1, 'import':1, 'public':1, 'static':1, 'default':1, 'finally':1, 'extends':1, 'package':1, 'private':1, 'function':1, 'continue':1, 'debugger':1, 'interface':1, 'protected':1, 'instanceof':1, 'implements':1 }; function skipComment() { var ch; while (index$1 < length$2) { ch = source$1.charCodeAt(index$1); if (isWhiteSpace(ch) || isLineTerminator(ch)) { ++index$1; } else { break; } } } function scanHexEscape(prefix) { var i, len, ch, code = 0; len = (prefix === 'u') ? 4 : 2; for (i = 0; i < len; ++i) { if (index$1 < length$2 && isHexDigit(source$1[index$1])) { ch = source$1[index$1++]; code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); } else { throwError({}, MessageUnexpectedToken, ILLEGAL); } } return String.fromCharCode(code); } function scanUnicodeCodePointEscape() { var ch, code, cu1, cu2; ch = source$1[index$1]; code = 0; // At least, one hex digit is required. if (ch === '}') { throwError({}, MessageUnexpectedToken, ILLEGAL); } while (index$1 < length$2) { ch = source$1[index$1++]; if (!isHexDigit(ch)) { break; } code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); } if (code > 0x10FFFF || ch !== '}') { throwError({}, MessageUnexpectedToken, ILLEGAL); } // UTF-16 Encoding if (code <= 0xFFFF) { return String.fromCharCode(code); } cu1 = ((code - 0x10000) >> 10) + 0xD800; cu2 = ((code - 0x10000) & 1023) + 0xDC00; return String.fromCharCode(cu1, cu2); } function getEscapedIdentifier() { var ch, id; ch = source$1.charCodeAt(index$1++); id = String.fromCharCode(ch); // '\u' (U+005C, U+0075) denotes an escaped character. if (ch === 0x5C) { if (source$1.charCodeAt(index$1) !== 0x75) { throwError({}, MessageUnexpectedToken, ILLEGAL); } ++index$1; ch = scanHexEscape('u'); if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) { throwError({}, MessageUnexpectedToken, ILLEGAL); } id = ch; } while (index$1 < length$2) { ch = source$1.charCodeAt(index$1); if (!isIdentifierPart(ch)) { break; } ++index$1; id += String.fromCharCode(ch); // '\u' (U+005C, U+0075) denotes an escaped character. if (ch === 0x5C) { id = id.substr(0, id.length - 1); if (source$1.charCodeAt(index$1) !== 0x75) { throwError({}, MessageUnexpectedToken, ILLEGAL); } ++index$1; ch = scanHexEscape('u'); if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) { throwError({}, MessageUnexpectedToken, ILLEGAL); } id += ch; } } return id; } function getIdentifier() { var start, ch; start = index$1++; while (index$1 < length$2) { ch = source$1.charCodeAt(index$1); if (ch === 0x5C) { // Blackslash (U+005C) marks Unicode escape sequence. index$1 = start; return getEscapedIdentifier(); } if (isIdentifierPart(ch)) { ++index$1; } else { break; } } return source$1.slice(start, index$1); } function scanIdentifier() { var start, id, type; start = index$1; // Backslash (U+005C) starts an escaped character. id = (source$1.charCodeAt(index$1) === 0x5C) ? getEscapedIdentifier() : getIdentifier(); // There is no keyword or literal with only one character. // Thus, it must be an identifier. if (id.length === 1) { type = TokenIdentifier; } else if (keywords$1.hasOwnProperty(id)) { type = TokenKeyword; } else if (id === 'null') { type = TokenNullLiteral; } else if (id === 'true' || id === 'false') { type = TokenBooleanLiteral; } else { type = TokenIdentifier; } return { type: type, value: id, start: start, end: index$1 }; } // 7.7 Punctuators function scanPunctuator() { var start = index$1, code = source$1.charCodeAt(index$1), code2, ch1 = source$1[index$1], ch2, ch3, ch4; switch (code) { // Check for most common single-character punctuators. case 0x2E: // . dot case 0x28: // ( open bracket case 0x29: // ) close bracket case 0x3B: // ; semicolon case 0x2C: // , comma case 0x7B: // { open curly brace case 0x7D: // } close curly brace case 0x5B: // [ case 0x5D: // ] case 0x3A: // : case 0x3F: // ? case 0x7E: // ~ ++index$1; return { type: TokenPunctuator, value: String.fromCharCode(code), start: start, end: index$1 }; default: code2 = source$1.charCodeAt(index$1 + 1); // '=' (U+003D) marks an assignment or comparison operator. if (code2 === 0x3D) { switch (code) { case 0x2B: // + case 0x2D: // - case 0x2F: // / case 0x3C: // < case 0x3E: // > case 0x5E: // ^ case 0x7C: // | case 0x25: // % case 0x26: // & case 0x2A: // * index$1 += 2; return { type: TokenPunctuator, value: String.fromCharCode(code) + String.fromCharCode(code2), start: start, end: index$1 }; case 0x21: // ! case 0x3D: // = index$1 += 2; // !== and === if (source$1.charCodeAt(index$1) === 0x3D) { ++index$1; } return { type: TokenPunctuator, value: source$1.slice(start, index$1), start: start, end: index$1 }; } } } // 4-character punctuator: >>>= ch4 = source$1.substr(index$1, 4); if (ch4 === '>>>=') { index$1 += 4; return { type: TokenPunctuator, value: ch4, start: start, end: index$1 }; } // 3-character punctuators: === !== >>> <<= >>= ch3 = ch4.substr(0, 3); if (ch3 === '>>>' || ch3 === '<<=' || ch3 === '>>=') { index$1 += 3; return { type: TokenPunctuator, value: ch3, start: start, end: index$1 }; } // Other 2-character punctuators: ++ -- << >> && || ch2 = ch3.substr(0, 2); if ((ch1 === ch2[1] && ('+-<>&|'.indexOf(ch1) >= 0)) || ch2 === '=>') { index$1 += 2; return { type: TokenPunctuator, value: ch2, start: start, end: index$1 }; } // 1-character punctuators: < > = ! + - * % & | ^ / if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { ++index$1; return { type: TokenPunctuator, value: ch1, start: start, end: index$1 }; } throwError({}, MessageUnexpectedToken, ILLEGAL); } // 7.8.3 Numeric Literals function scanHexLiteral(start) { var number = ''; while (index$1 < length$2) { if (!isHexDigit(source$1[index$1])) { break; } number += source$1[index$1++]; } if (number.length === 0) { throwError({}, MessageUnexpectedToken, ILLEGAL); } if (isIdentifierStart(source$1.charCodeAt(index$1))) { throwError({}, MessageUnexpectedToken, ILLEGAL); } return { type: TokenNumericLiteral, value: parseInt('0x' + number, 16), start: start, end: index$1 }; } function scanOctalLiteral(start) { var number = '0' + source$1[index$1++]; while (index$1 < length$2) { if (!isOctalDigit(source$1[index$1])) { break; } number += source$1[index$1++]; } if (isIdentifierStart(source$1.charCodeAt(index$1)) || isDecimalDigit(source$1.charCodeAt(index$1))) { throwError({}, MessageUnexpectedToken, ILLEGAL); } return { type: TokenNumericLiteral, value: parseInt(number, 8), octal: true, start: start, end: index$1 }; } function scanNumericLiteral() { var number, start, ch; ch = source$1[index$1]; assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'), 'Numeric literal must start with a decimal digit or a decimal point'); start = index$1; number = ''; if (ch !== '.') { number = source$1[index$1++]; ch = source$1[index$1]; // Hex number starts with '0x'. // Octal number starts with '0'. if (number === '0') { if (ch === 'x' || ch === 'X') { ++index$1; return scanHexLiteral(start); } if (isOctalDigit(ch)) { return scanOctalLiteral(start); } // decimal number starts with '0' such as '09' is illegal. if (ch && isDecimalDigit(ch.charCodeAt(0))) { throwError({}, MessageUnexpectedToken, ILLEGAL); } } while (isDecimalDigit(source$1.charCodeAt(index$1))) { number += source$1[index$1++]; } ch = source$1[index$1]; } if (ch === '.') { number += source$1[index$1++]; while (isDecimalDigit(source$1.charCodeAt(index$1))) { number += source$1[index$1++]; } ch = source$1[index$1]; } if (ch === 'e' || ch === 'E') { number += source$1[index$1++]; ch = source$1[index$1]; if (ch === '+' || ch === '-') { number += source$1[index$1++]; } if (isDecimalDigit(source$1.charCodeAt(index$1))) { while (isDecimalDigit(source$1.charCodeAt(index$1))) { number += source$1[index$1++]; } } else { throwError({}, MessageUnexpectedToken, ILLEGAL); } } if (isIdentifierStart(source$1.charCodeAt(index$1))) { throwError({}, MessageUnexpectedToken, ILLEGAL); } return { type: TokenNumericLiteral, value: parseFloat(number), start: start, end: index$1 }; } // 7.8.4 String Literals function scanStringLiteral() { var str = '', quote, start, ch, code, octal = false; quote = source$1[index$1]; assert((quote === '\'' || quote === '"'), 'String literal must starts with a quote'); start = index$1; ++index$1; while (index$1 < length$2) { ch = source$1[index$1++]; if (ch === quote) { quote = ''; break; } else if (ch === '\\') { ch = source$1[index$1++]; if (!ch || !isLineTerminator(ch.charCodeAt(0))) { switch (ch) { case 'u': case 'x': if (source$1[index$1] === '{') { ++index$1; str += scanUnicodeCodePointEscape(); } else { str += scanHexEscape(ch); } break; case 'n': str += '\n'; break; case 'r': str += '\r'; break; case 't': str += '\t'; break; case 'b': str += '\b'; break; case 'f': str += '\f'; break; case 'v': str += '\x0B'; break; default: if (isOctalDigit(ch)) { code = '01234567'.indexOf(ch); // \0 is not octal escape sequence if (code !== 0) { octal = true; } if (index$1 < length$2 && isOctalDigit(source$1[index$1])) { octal = true; code = code * 8 + '01234567'.indexOf(source$1[index$1++]); // 3 digits are only allowed when string starts // with 0, 1, 2, 3 if ('0123'.indexOf(ch) >= 0 && index$1 < length$2 && isOctalDigit(source$1[index$1])) { code = code * 8 + '01234567'.indexOf(source$1[index$1++]); } } str += String.fromCharCode(code); } else { str += ch; } break; } } else { if (ch === '\r' && source$1[index$1] === '\n') { ++index$1; } } } else if (isLineTerminator(ch.charCodeAt(0))) { break; } else { str += ch; } } if (quote !== '') { throwError({}, MessageUnexpectedToken, ILLEGAL); } return { type: TokenStringLiteral, value: str, octal: octal, start: start, end: index$1 }; } function testRegExp(pattern, flags) { var tmp = pattern; if (flags.indexOf('u') >= 0) { // Replace each astral symbol and every Unicode code point // escape sequence with a single ASCII symbol to avoid throwing on // regular expressions that are only valid in combination with the // `/u` flag. // Note: replacing with the ASCII symbol `x` might cause false // negatives in unlikely scenarios. For example, `[\u{61}-b]` is a // perfectly valid pattern that is equivalent to `[a-b]`, but it // would be replaced by `[x-b]` which throws an error. tmp = tmp .replace(/\\u\{([0-9a-fA-F]+)\}/g, function($0, $1) { if (parseInt($1, 16) <= 0x10FFFF) { return 'x'; } throwError({}, MessageInvalidRegExp); }) .replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, 'x'); } // First, detect invalid regular expressions. try { new RegExp(tmp); } catch (e) { throwError({}, MessageInvalidRegExp); } // Return a regular expression object for this pattern-flag pair, or // `null` in case the current environment doesn't support the flags it // uses. try { return new RegExp(pattern, flags); } catch (exception) { return null; } } function scanRegExpBody() { var ch, str, classMarker, terminated, body; ch = source$1[index$1]; assert(ch === '/', 'Regular expression literal must start with a slash'); str = source$1[index$1++]; classMarker = false; terminated = false; while (index$1 < length$2) { ch = source$1[index$1++]; str += ch; if (ch === '\\') { ch = source$1[index$1++]; // ECMA-262 7.8.5 if (isLineTerminator(ch.charCodeAt(0))) { throwError({}, MessageUnterminatedRegExp); } str += ch; } else if (isLineTerminator(ch.charCodeAt(0))) { throwError({}, MessageUnterminatedRegExp); } else if (classMarker) { if (ch === ']') { classMarker = false; } } else { if (ch === '/') { terminated = true; break; } else if (ch === '[') { classMarker = true; } } } if (!terminated) { throwError({}, MessageUnterminatedRegExp); } // Exclude leading and trailing slash. body = str.substr(1, str.length - 2); return { value: body, literal: str }; } function scanRegExpFlags() { var ch, str, flags; str = ''; flags = ''; while (index$1 < length$2) { ch = source$1[index$1]; if (!isIdentifierPart(ch.charCodeAt(0))) { break; } ++index$1; if (ch === '\\' && index$1 < length$2) { throwError({}, MessageUnexpectedToken, ILLEGAL); } else { flags += ch; str += ch; } } if (flags.search(/[^gimuy]/g) >= 0) { throwError({}, MessageInvalidRegExp, flags); } return { value: flags, literal: str }; } function scanRegExp() { var start, body, flags, value; lookahead = null; skipComment(); start = index$1; body = scanRegExpBody(); flags = scanRegExpFlags(); value = testRegExp(body.value, flags.value); return { literal: body.literal + flags.literal, value: value, regex: { pattern: body.value, flags: flags.value }, start: start, end: index$1 }; } function isIdentifierName(token) { return token.type === TokenIdentifier || token.type === TokenKeyword || token.type === TokenBooleanLiteral || token.type === TokenNullLiteral; } function advance() { var ch; skipComment(); if (index$1 >= length$2) { return { type: TokenEOF, start: index$1, end: index$1 }; } ch = source$1.charCodeAt(index$1); if (isIdentifierStart(ch)) { return scanIdentifier(); } // Very common: ( and ) and ; if (ch === 0x28 || ch === 0x29 || ch === 0x3B) { return scanPunctuator(); } // String literal starts with single quote (U+0027) or double quote (U+0022). if (ch === 0x27 || ch === 0x22) { return scanStringLiteral(); } // Dot (.) U+002E can also start a floating-point number, hence the need // to check the next character. if (ch === 0x2E) { if (isDecimalDigit(source$1.charCodeAt(index$1 + 1))) { return scanNumericLiteral(); } return scanPunctuator(); } if (isDecimalDigit(ch)) { return scanNumericLiteral(); } return scanPunctuator(); } function lex() { var token; token = lookahead; index$1 = token.end; lookahead = advance(); index$1 = token.end; return token; } function peek$1() { var pos; pos = index$1; lookahead = advance(); index$1 = pos; } function finishArrayExpression(elements) { var node = new ASTNode(SyntaxArrayExpression); node.elements = elements; return node; } function finishBinaryExpression(operator, left, right) { var node = new ASTNode((operator === '||' || operator === '&&') ? SyntaxLogicalExpression : SyntaxBinaryExpression); node.operator = operator; node.left = left; node.right = right; return node; } function finishCallExpression(callee, args) { var node = new ASTNode(SyntaxCallExpression); node.callee = callee; node.arguments = args; return node; } function finishConditionalExpression(test, consequent, alternate) { var node = new ASTNode(SyntaxConditionalExpression); node.test = test; node.consequent = consequent; node.alternate = alternate; return node; } function finishIdentifier(name) { var node = new ASTNode(SyntaxIdentifier); node.name = name; return node; } function finishLiteral(token) { var node = new ASTNode(SyntaxLiteral); node.value = token.value; node.raw = source$1.slice(token.start, token.end); if (token.regex) { if (node.raw === '//') { node.raw = '/(?:)/'; } node.regex = token.regex; } return node; } function finishMemberExpression(accessor, object, property) { var node = new ASTNode(SyntaxMemberExpression); node.computed = accessor === '['; node.object = object; node.property = property; if (!node.computed) property.member = true; return node; } function finishObjectExpression(properties) { var node = new ASTNode(SyntaxObjectExpression); node.properties = properties; return node; } function finishProperty(kind, key, value) { var node = new ASTNode(SyntaxProperty); node.key = key; node.value = value; node.kind = kind; return node; } function finishUnaryExpression(operator, argument) { var node = new ASTNode(SyntaxUnaryExpression); node.operator = operator; node.argument = argument; node.prefix = true; return node; } // Throw an exception function throwError(token, messageFormat) { var error, args = Array.prototype.slice.call(arguments, 2), msg = messageFormat.replace( /%(\d)/g, function(whole, index) { assert(index < args.length, 'Message reference must be in range'); return args[index]; } ); error = new Error(msg); error.index = index$1; error.description = msg; throw error; } // Throw an exception because of the token. function throwUnexpected(token) { if (token.type === TokenEOF) { throwError(token, MessageUnexpectedEOS); } if (token.type === TokenNumericLiteral) { throwError(token, MessageUnexpectedNumber); } if (token.type === TokenStringLiteral) { throwError(token, MessageUnexpectedString); } if (token.type === TokenIdentifier) { throwError(token, MessageUnexpectedIdentifier); } if (token.type === TokenKeyword) { throwError(token, MessageUnexpectedReserved); } // BooleanLiteral, NullLiteral, or Punctuator. throwError(token, MessageUnexpectedToken, token.value); } // Expect the next token to match the specified punctuator. // If not, an exception will be thrown. function expect(value) { var token = lex(); if (token.type !== TokenPunctuator || token.value !== value) { throwUnexpected(token); } } // Return true if the next token matches the specified punctuator. function match(value) { return lookahead.type === TokenPunctuator && lookahead.value === value; } // Return true if the next token matches the specified keyword function matchKeyword(keyword) { return lookahead.type === TokenKeyword && lookahead.value === keyword; } // 11.1.4 Array Initialiser function parseArrayInitialiser() { var elements = []; index$1 = lookahead.start; expect('['); while (!match(']')) { if (match(',')) { lex(); elements.push(null); } else { elements.push(parseConditionalExpression()); if (!match(']')) { expect(','); } } } lex(); return finishArrayExpression(elements); } // 11.1.5 Object Initialiser function parseObjectPropertyKey() { var token; index$1 = lookahead.start; token = lex(); // Note: This function is called only from parseObjectProperty(), where // EOF and Punctuator tokens are already filtered out. if (token.type === TokenStringLiteral || token.type === TokenNumericLiteral) { if (token.octal) { throwError(token, MessageStrictOctalLiteral); } return finishLiteral(token); } return finishIdentifier(token.value); } function parseObjectProperty() { var token, key, id, value; index$1 = lookahead.start; token = lookahead; if (token.type === TokenIdentifier) { id = parseObjectPropertyKey(); expect(':'); value = parseConditionalExpression(); return finishProperty('init', id, value); } if (token.type === TokenEOF || token.type === TokenPunctuator) { throwUnexpected(token); } else { key = parseObjectPropertyKey(); expect(':'); value = parseConditionalExpression(); return finishProperty('init', key, value); } } function parseObjectInitialiser() { var properties = [], property, name, key, map = {}, toString = String; index$1 = lookahead.start; expect('{'); while (!match('}')) { property = parseObjectProperty(); if (property.key.type === SyntaxIdentifier) { name = property.key.name; } else { name = toString(property.key.value); } key = '$' + name; if (Object.prototype.hasOwnProperty.call(map, key)) { throwError({}, MessageStrictDuplicateProperty); } else { map[key] = true; } properties.push(property); if (!match('}')) { expect(','); } } expect('}'); return finishObjectExpression(properties); } // 11.1.6 The Grouping Operator function parseGroupExpression() { var expr; expect('('); expr = parseExpression$1(); expect(')'); return expr; } // 11.1 Primary Expressions var legalKeywords = { "if": 1, "this": 1 }; function parsePrimaryExpression() { var type, token, expr; if (match('(')) { return parseGroupExpression(); } if (match('[')) { return parseArrayInitialiser(); } if (match('{')) { return parseObjectInitialiser(); } type = lookahead.type; index$1 = lookahead.start; if (type === TokenIdentifier || legalKeywords[lookahead.value]) { expr = finishIdentifier(lex().value); } else if (type === TokenStringLiteral || type === TokenNumericLiteral) { if (lookahead.octal) { throwError(lookahead, MessageStrictOctalLiteral); } expr = finishLiteral(lex()); } else if (type === TokenKeyword) { throw new Error(DISABLED); } else if (type === TokenBooleanLiteral) { token = lex(); token.value = (token.value === 'true'); expr = finishLiteral(token); } else if (type === TokenNullLiteral) { token = lex(); token.value = null; expr = finishLiteral(token); } else if (match('/') || match('/=')) { expr = finishLiteral(scanRegExp()); peek$1(); } else { throwUnexpected(lex()); } return expr; } // 11.2 Left-Hand-Side Expressions function parseArguments() { var args = []; expect('('); if (!match(')')) { while (index$1 < length$2) { args.push(parseConditionalExpression()); if (match(')')) { break; } expect(','); } } expect(')'); return args; } function parseNonComputedProperty() { var token; index$1 = lookahead.start; token = lex(); if (!isIdentifierName(token)) { throwUnexpected(token); } return finishIdentifier(token.value); } function parseNonComputedMember() { expect('.'); return parseNonComputedProperty(); } function parseComputedMember() { var expr; expect('['); expr = parseExpression$1(); expect(']'); return expr; } function parseLeftHandSideExpressionAllowCall() { var expr, args, property; expr = parsePrimaryExpression(); for (;;) { if (match('.')) { property = parseNonComputedMember(); expr = finishMemberExpression('.', expr, property); } else if (match('(')) { args = parseArguments(); expr = finishCallExpression(expr, args); } else if (match('[')) { property = parseComputedMember(); expr = finishMemberExpression('[', expr, property); } else { break; } } return expr; } // 11.3 Postfix Expressions function parsePostfixExpression() { var expr = parseLeftHandSideExpressionAllowCall(); if (lookahead.type === TokenPunctuator) { if ((match('++') || match('--'))) { throw new Error(DISABLED); } } return expr; } // 11.4 Unary Operators function parseUnaryExpression() { var token, expr; if (lookahead.type !== TokenPunctuator && lookahead.type !== TokenKeyword) { expr = parsePostfixExpression(); } else if (match('++') || match('--')) { throw new Error(DISABLED); } else if (match('+') || match('-') || match('~') || match('!')) { token = lex(); expr = parseUnaryExpression(); expr = finishUnaryExpression(token.value, expr); } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { throw new Error(DISABLED); } else { expr = parsePostfixExpression(); } return expr; } function binaryPrecedence(token) { var prec = 0; if (token.type !== TokenPunctuator && token.type !== TokenKeyword) { return 0; } switch (token.value) { case '||': prec = 1; break; case '&&': prec = 2; break; case '|': prec = 3; break; case '^': prec = 4; break; case '&': prec = 5; break; case '==': case '!=': case '===': case '!==': prec = 6; break; case '<': case '>': case '<=': case '>=': case 'instanceof': case 'in': prec = 7; break; case '<<': case '>>': case '>>>': prec = 8; break; case '+': case '-': prec = 9; break; case '*': case '/': case '%': prec = 11; break; default: break; } return prec; } // 11.5 Multiplicative Operators // 11.6 Additive Operators // 11.7 Bitwise Shift Operators // 11.8 Relational Operators // 11.9 Equality Operators // 11.10 Binary Bitwise Operators // 11.11 Binary Logical Operators function parseBinaryExpression() { var marker, markers, expr, token, prec, stack, right, operator, left, i; marker = lookahead; left = parseUnaryExpression(); token = lookahead; prec = binaryPrecedence(token); if (prec === 0) { return left; } token.prec = prec; lex(); markers = [marker, lookahead]; right = parseUnaryExpression(); stack = [left, token, right]; while ((prec = binaryPrecedence(lookahead)) > 0) { // Reduce: make a binary expression from the three topmost entries. while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) { right = stack.pop(); operator = stack.pop().value; left = stack.pop(); markers.pop(); expr = finishBinaryExpression(operator, left, right); stack.push(expr); } // Shift. token = lex(); token.prec = prec; stack.push(token); markers.push(lookahead); expr = parseUnaryExpression(); stack.push(expr); } // Final reduce to clean-up the stack. i = stack.length - 1; expr = stack[i]; markers.pop(); while (i > 1) { markers.pop(); expr = finishBinaryExpression(stack[i - 1].value, stack[i - 2], expr); i -= 2; } return expr; } // 11.12 Conditional Operator function parseConditionalExpression() { var expr, consequent, alternate; expr = parseBinaryExpression(); if (match('?')) { lex(); consequent = parseConditionalExpression(); expect(':'); alternate = parseConditionalExpression(); expr = finishConditionalExpression(expr, consequent, alternate); } return expr; } // 11.14 Comma Operator function parseExpression$1() { var expr = parseConditionalExpression(); if (match(',')) { throw new Error(DISABLED); // no sequence expressions } return expr; } var parse$3 = function(code) { source$1 = code; index$1 = 0; length$2 = source$1.length; lookahead = null; peek$1(); var expr = parseExpression$1(); if (lookahead.type !== TokenEOF) { throw new Error("Unexpect token after expression."); } return expr; }; var Constants = { NaN: 'NaN', E: 'Math.E', LN2: 'Math.LN2', LN10: 'Math.LN10', LOG2E: 'Math.LOG2E', LOG10E: 'Math.LOG10E', PI: 'Math.PI', SQRT1_2: 'Math.SQRT1_2', SQRT2: 'Math.SQRT2', MIN_VALUE: 'Number.MIN_VALUE', MAX_VALUE: 'Number.MAX_VALUE' }; var Functions = function(codegen) { function fncall(name, args, cast, type) { var obj = codegen(args[0]); if (cast) { obj = cast + '(' + obj + ')'; if (cast.lastIndexOf('new ', 0) === 0) obj = '(' + obj + ')'; } return obj + '.' + name + (type < 0 ? '' : type === 0 ? '()' : '(' + args.slice(1).map(codegen).join(',') + ')'); } function fn(name, cast, type) { return function(args) { return fncall(name, args, cast, type); }; } var DATE = 'new Date', STRING = 'String', REGEXP = 'RegExp'; return { // MATH functions isNaN: 'isNaN', isFinite: 'isFinite', abs: 'Math.abs', acos: 'Math.acos', asin: 'Math.asin', atan: 'Math.atan', atan2: 'Math.atan2', ceil: 'Math.ceil', cos: 'Math.cos', exp: 'Math.exp', floor: 'Math.floor', log: 'Math.log', max: 'Math.max', min: 'Math.min', pow: 'Math.pow', random: 'Math.random', round: 'Math.round', sin: 'Math.sin', sqrt: 'Math.sqrt', tan: 'Math.tan', clamp: function(args) { if (args.length < 3) error$1('Missing arguments to clamp function.'); if (args.length > 3) error$1('Too many arguments to clamp function.'); var a = args.map(codegen); return 'Math.max('+a[1]+', Math.min('+a[2]+','+a[0]+'))'; }, // DATE functions now: 'Date.now', utc: 'Date.UTC', datetime: DATE, date: fn('getDate', DATE, 0), day: fn('getDay', DATE, 0), year: fn('getFullYear', DATE, 0), month: fn('getMonth', DATE, 0), hours: fn('getHours', DATE, 0), minutes: fn('getMinutes', DATE, 0), seconds: fn('getSeconds', DATE, 0), milliseconds: fn('getMilliseconds', DATE, 0), time: fn('getTime', DATE, 0), timezoneoffset: fn('getTimezoneOffset', DATE, 0), utcdate: fn('getUTCDate', DATE, 0), utcday: fn('getUTCDay', DATE, 0), utcyear: fn('getUTCFullYear', DATE, 0), utcmonth: fn('getUTCMonth', DATE, 0), utchours: fn('getUTCHours', DATE, 0), utcminutes: fn('getUTCMinutes', DATE, 0), utcseconds: fn('getUTCSeconds', DATE, 0), utcmilliseconds: fn('getUTCMilliseconds', DATE, 0), // shared sequence functions length: fn('length', null, -1), indexof: fn('indexOf', null), lastindexof: fn('lastIndexOf', null), slice: fn('slice', null), // STRING functions parseFloat: 'parseFloat', parseInt: 'parseInt', upper: fn('toUpperCase', STRING, 0), lower: fn('toLowerCase', STRING, 0), substring: fn('substring', STRING), replace: fn('replace', STRING), // REGEXP functions regexp: REGEXP, test: fn('test', REGEXP), // Control Flow functions if: function(args) { if (args.length < 3) error$1('Missing arguments to if function.'); if (args.length > 3) error$1('Too many arguments to if function.'); var a = args.map(codegen); return '('+a[0]+'?'+a[1]+':'+a[2]+')'; } }; }; var codegen = function(opt) { opt = opt || {}; var whitelist = opt.whitelist ? toSet(opt.whitelist) : {}, blacklist = opt.blacklist ? toSet(opt.blacklist) : {}, constants = opt.constants || Constants, functions = (opt.functions || Functions)(visit), globalvar = opt.globalvar, fieldvar = opt.fieldvar, globals = {}, fields = {}, memberDepth = 0; var outputGlobal = isFunction(globalvar) ? globalvar : function (id$$1) { return globalvar + '["' + id$$1 + '"]'; }; function visit(ast) { if (isString(ast)) return ast; var generator = Generators[ast.type]; if (generator == null) error$1('Unsupported type: ' + ast.type); return generator(ast); } var Generators = { Literal: function(n) { return n.raw; }, Identifier: function(n) { var id$$1 = n.name; if (memberDepth > 0) { return id$$1; } else if (blacklist.hasOwnProperty(id$$1)) { return error$1('Illegal identifier: ' + id$$1); } else if (constants.hasOwnProperty(id$$1)) { return constants[id$$1]; } else if (whitelist.hasOwnProperty(id$$1)) { return id$$1; } else { globals[id$$1] = 1; return outputGlobal(id$$1); } }, MemberExpression: function(n) { var d = !n.computed; var o = visit(n.object); if (d) memberDepth += 1; var p = visit(n.property); if (o === fieldvar) { fields[p] = 1; } // HACKish... if (d) memberDepth -= 1; return o + (d ? '.'+p : '['+p+']'); }, CallExpression: function(n) { if (n.callee.type !== 'Identifier') { error$1('Illegal callee type: ' + n.callee.type); } var callee = n.callee.name; var args = n.arguments; var fn = functions.hasOwnProperty(callee) && functions[callee]; if (!fn) error$1('Unrecognized function: ' + callee); return isFunction(fn) ? fn(args) : fn + '(' + args.map(visit).join(',') + ')'; }, ArrayExpression: function(n) { return '[' + n.elements.map(visit).join(',') + ']'; }, BinaryExpression: function(n) { return '(' + visit(n.left) + n.operator + visit(n.right) + ')'; }, UnaryExpression: function(n) { return '(' + n.operator + visit(n.argument) + ')'; }, ConditionalExpression: function(n) { return '(' + visit(n.test) + '?' + visit(n.consequent) + ':' + visit(n.alternate) + ')'; }, LogicalExpression: function(n) { return '(' + visit(n.left) + n.operator + visit(n.right) + ')'; }, ObjectExpression: function(n) { return '{' + n.properties.map(visit).join(',') + '}'; }, Property: function(n) { memberDepth += 1; var k = visit(n.key); memberDepth -= 1; return k + ':' + visit(n.value); } }; function codegen(ast) { var result = { code: visit(ast), globals: Object.keys(globals), fields: Object.keys(fields) }; globals = {}; fields = {}; return result; } codegen.functions = functions; codegen.constants = constants; return codegen; }; var formatCache = {}; function formatter(type, method, specifier) { var k = type + ':' + specifier, e = formatCache[k]; if (!e || e[0] !== method) { formatCache[k] = (e = [method, method(specifier)]); } return e[1]; } function format$1(_, specifier) { return formatter('format', format, specifier)(_); } function timeFormat$1(_, specifier) { return formatter('timeFormat', timeFormat, specifier)(_); } function utcFormat$1(_, specifier) { return formatter('utcFormat', utcFormat, specifier)(_); } function timeParse$1(_, specifier) { return formatter('timeParse', timeParse, specifier)(_); } function utcParse$1(_, specifier) { return formatter('utcParse', utcParse, specifier)(_); } var dateObj = new Date(2000, 0, 1); function time$2(month, day, specifier) { dateObj.setMonth(month); dateObj.setDate(day); return timeFormat$1(dateObj, specifier); } function monthFormat(month) { return time$2(month, 1, '%B'); } function monthAbbrevFormat(month) { return time$2(month, 1, '%b'); } function dayFormat(day) { return time$2(0, 2 + day, '%A'); } function dayAbbrevFormat(day) { return time$2(0, 2 + day, '%a'); } function quarter(date) { return 1 + ~~(new Date(date).getMonth() / 3); } function utcquarter(date) { return 1 + ~~(new Date(date).getUTCMonth() / 3); } function log$3(df, method, args) { try { df[method].apply(df, ['EXPRESSION'].concat([].slice.call(args))); } catch (err) { df.warn(err); } return args[args.length-1]; } function warn() { return log$3(this.context.dataflow, 'warn', arguments); } function info() { return log$3(this.context.dataflow, 'info', arguments); } function debug() { return log$3(this.context.dataflow, 'debug', arguments); } var inScope = function(item) { var group = this.context.group, value = false; if (group) while (item) { if (item === group) { value = true; break; } item = item.mark.group; } return value; }; /** * 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. */ var clampRange = function(range, min, max) { var 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] : [ Math.min(Math.max(lo, min), max - span), Math.min(Math.max(hi, span), max) ]; }; function pinchDistance(event) { var t = event.touches, dx = t[0].clientX - t[1].clientX, dy = t[0].clientY - t[1].clientY; return Math.sqrt(dx * dx + dy * dy); } function pinchAngle(event) { var t = event.touches; return Math.atan2( t[0].clientY - t[1].clientY, t[0].clientX - t[1].clientX ); } var _window = (typeof window !== 'undefined' && window) || null; function screen() { return _window ? _window.screen : {}; } function windowSize() { return _window ? [_window.innerWidth, _window.innerHeight] : [undefined, undefined]; } function containerSize() { var view = this.context.dataflow, el = view.container && view.container(); return el ? [el.clientWidth, el.clientHeight] : [undefined, undefined]; } var span = function(array) { return (array[array.length-1] - array[0]) || 0; }; var Literal = 'Literal'; var Identifier$1 = 'Identifier'; var indexPrefix = '@'; var scalePrefix = '%'; var dataPrefix = ':'; function getScale(name, ctx) { var s; return isFunction(name) ? name : isString(name) ? (s = ctx.scales[name]) && s.value : undefined; } function addScaleDependency(scope, params, name) { var scaleName = scalePrefix + name; if (!params.hasOwnProperty(scaleName)) { try { params[scaleName] = scope.scaleRef(name); } catch (err) { // TODO: error handling? warning? } } } function scaleVisitor(name, args, scope, params) { if (args[0].type === Literal) { // add scale dependency addScaleDependency(scope, params, args[0].value); } else if (args[0].type === Identifier$1) { // indirect scale lookup; add all scales as parameters for (name in scope.scales) { addScaleDependency(scope, params, name); } } } function range$2(name, group) { var s = getScale(name, (group || this).context); return s && s.range ? s.range() : []; } function domain(name, group) { var s = getScale(name, (group || this).context); return s ? s.domain() : []; } function bandwidth(name, group) { var s = getScale(name, (group || this).context); return s && s.bandwidth ? s.bandwidth() : 0; } function bandspace(count, paddingInner, paddingOuter) { return bandSpace(count || 0, paddingInner || 0, paddingOuter || 0); } function copy$1(name, group) { var s = getScale(name, (group || this).context); return s ? s.copy() : undefined; } function scale$2(name, value, group) { var s = getScale(name, (group || this).context); return s ? s(value) : undefined; } function invert(name, range, group) { var s = getScale(name, (group || this).context); return !s ? undefined : isArray(range) ? (s.invertRange || s.invert)(range) : (s.invert || s.invertExtent)(range); } var scaleGradient = function(scale, p0, p1, count) { var gradient = Gradient(p0, p1), stops = scale.domain(), min = stops[0], max = stops[stops.length-1], fraction = scaleFraction(scale, min, max); if (scale.ticks) { stops = scale.ticks(+count || 15); if (min !== stops[0]) stops.unshift(min); if (max !== stops[stops.length-1]) stops.push(max); } for (var i=0, n=stops.length; i 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); }; var encode$1 = function(item, name, retval) { if (item) { var df = this.context.dataflow, target = item.mark.source; df.pulse(target, df.changeset().encode(item, name)); } return retval !== undefined ? retval : item; }; function equal(a, b) { return a === b || a !== a && b !== b ? true : isArray(a) && isArray(b) && a.length === b.length ? equalArray(a, b) : false; } function equalArray(a, b) { for (var i=0, n=a.length; i, fields: array, values: array<*>, bins: object} function vlPoint(name, datum, op) { return vlSelection.call(this, name, datum, op, testPoint); } // Assumes interval selection typles are of the form: // {unit: string, intervals: array<{encoding: string, field:string, extent:array}>} function vlInterval(name, datum, op) { return vlSelection.call(this, name, datum, op, testInterval); } function vlMultiVisitor(name, args, scope, params) { if (args[0].type !== Literal) error$1('First argument to indata must be a string literal.'); var data = args[0].value, // vlMulti, vlMultiDomain have different # of params, but op is always last. op = args.length >= 2 && args[args.length-1].value, field$$1 = 'unit', indexName = indexPrefix + field$$1; if (op === INTERSECT && !params.hasOwnProperty(indexName)) { params[indexName] = scope.getData(data).indataRef(scope, field$$1); } dataVisitor(name, args, scope, params); } /** * Materializes a point selection as a scale domain. * @param {string} name - The name of the dataset representing the selection. * @param {string} [encoding] - A particular encoding channel to materialize. * @param {string} [field] - A particular field to materialize. * @param {string} [op='intersect'] - The set operation for combining selections. * One of 'intersect' (default) or 'union'. * @returns {array} An array of values to serve as a scale domain. */ function vlPointDomain(name, encoding, field$$1, op) { var data = this.context.data[name], entries = data ? data.values.value : [], unitIdx = data ? data[UNIT_INDEX] && data[UNIT_INDEX].value : undefined, entry = entries[0], i = 0, n, index, values, continuous, units; if (!entry) return undefined; for (n = encoding ? entry.encodings.length : entry.fields.length; i 2; break; } } values = entries.reduce(function(acc, entry) { var extent = entry.intervals[index].extent, value = discrete ? extent.map(function (d) { return {unit: entry.unit, value: d}; }) : {unit: entry.unit, value: extent}; if (discrete) { acc.push.apply(acc, value); } else { acc.push(value); } return acc; }, []); return discrete ? discreteDomain(values, op) : continuousDomain(values, op); } function discreteDomain(entries, op) { var units = {}, count = 0, values = {}, domain = [], i = 0, n = entries.length, entry, unit, v, key$$1; for (; i hi) { hi = extent[0]; lo = extent[1]; } domain = domain ? merge$$1(domain, lo, hi) : [lo, hi]; } return domain && domain.length && (+domain[0] !== +domain[1]) ? domain : undefined; } function unionInterval(domain, lo, hi) { if (domain[0] > lo) domain[0] = lo; if (domain[1] < hi) domain[1] = hi; return domain; } function intersectInterval(domain, lo, hi) { if (hi < domain[0] || domain[1] < lo) { return []; } else { if (domain[0] < lo) domain[0] = lo; if (domain[1] > hi) domain[1] = hi; } return domain; } // Expression function context object var functionContext = { isArray: isArray, isBoolean: isBoolean, isDate: isDate, isNumber: isNumber, isObject: isObject, isRegExp: isRegExp, isString: isString, isTuple: isTuple, toBoolean: toBoolean, toDate: toDate, toNumber: toNumber, toString: toString, pad: pad, peek: peek, truncate: truncate, rgb: rgb, lab: lab, hcl: hcl, hsl: hsl, sequence: sequence, format: format$1, utcFormat: utcFormat$1, utcParse: utcParse$1, timeFormat: timeFormat$1, timeParse: timeParse$1, monthFormat: monthFormat, monthAbbrevFormat: monthAbbrevFormat, dayFormat: dayFormat, dayAbbrevFormat: dayAbbrevFormat, quarter: quarter, utcquarter: utcquarter, warn: warn, info: info, debug: debug, inScope: inScope, clampRange: clampRange, pinchDistance: pinchDistance, pinchAngle: pinchAngle, screen: screen, containerSize: containerSize, windowSize: windowSize, span: span, bandspace: bandspace, inrange: inrange, setdata: setdata, panLinear: panLinear, panLog: panLog, panPow: panPow, zoomLinear: zoomLinear, zoomLog: zoomLog, zoomPow: zoomPow, encode: encode$1, modify: modify }; var eventFunctions = ['view', 'item', 'group', 'xy', 'x', 'y']; var eventPrefix = 'event.vega.'; var thisPrefix = 'this.'; var astVisitors = {}; // AST visitors for dependency analysis function expressionFunction(name, fn, visitor) { if (arguments.length === 1) { return functionContext[name]; } // register with the functionContext functionContext[name] = fn; // if there is an astVisitor register that, too if (visitor) astVisitors[name] = visitor; // if the code generator has already been initialized, // we need to also register the function with it if (codeGenerator) codeGenerator.functions[name] = thisPrefix + name; return this; } // register expression functions with ast visitors expressionFunction('bandwidth', bandwidth, scaleVisitor); expressionFunction('copy', copy$1, scaleVisitor); expressionFunction('domain', domain, scaleVisitor); expressionFunction('range', range$2, scaleVisitor); expressionFunction('invert', invert, scaleVisitor); expressionFunction('scale', scale$2, scaleVisitor); expressionFunction('gradient', scaleGradient, scaleVisitor); expressionFunction('geoArea', geoArea, scaleVisitor); expressionFunction('geoBounds', geoBounds, scaleVisitor); expressionFunction('geoCentroid', geoCentroid, scaleVisitor); expressionFunction('indata', indata, indataVisitor); expressionFunction('data', data$1, dataVisitor); expressionFunction('vlSingle', vlPoint, dataVisitor); expressionFunction('vlSingleDomain', vlPointDomain, dataVisitor); expressionFunction('vlMulti', vlPoint, vlMultiVisitor); expressionFunction('vlMultiDomain', vlPointDomain, vlMultiVisitor); expressionFunction('vlInterval', vlInterval, dataVisitor); expressionFunction('vlIntervalDomain', vlIntervalDomain, dataVisitor); expressionFunction('treePath', treePath, dataVisitor); expressionFunction('treeAncestors', treeAncestors, dataVisitor); // Build expression function registry function buildFunctions(codegen$$1) { var fn = Functions(codegen$$1); eventFunctions.forEach(function(name) { fn[name] = eventPrefix + name; }); for (var name in functionContext) { fn[name] = thisPrefix + name; } return fn; } // Export code generator and parameters var codegenParams = { blacklist: ['_'], whitelist: ['datum', 'event', 'item'], fieldvar: 'datum', globalvar: function(id$$1) { return '_[' + $('$' + id$$1) + ']'; }, functions: buildFunctions, constants: Constants, visitors: astVisitors }; var codeGenerator = codegen(codegenParams); var signalPrefix = '$'; var parseExpression = function(expr, scope, preamble) { var params = {}, ast, gen; // parse the expression to an abstract syntax tree (ast) try { ast = parse$3(expr); } catch (err) { error$1('Expression parse error: ' + $(expr)); } // analyze ast function calls for dependencies ast.visit(function visitor(node) { if (node.type !== 'CallExpression') return; var name = node.callee.name, visit = codegenParams.visitors[name]; if (visit) visit(name, node.arguments, scope, params); }); // perform code generation gen = codeGenerator(ast); // collect signal dependencies gen.globals.forEach(function(name) { var signalName = signalPrefix + name; if (!params.hasOwnProperty(signalName) && scope.getSignal(name)) { params[signalName] = scope.signalRef(name); } }); // return generated expression code and dependencies return { $expr: preamble ? preamble + 'return(' + gen.code + ');' : gen.code, $fields: gen.fields, $params: params }; }; var VIEW$1 = 'view'; var SCOPE = 'scope'; var parseStream = function(stream, scope) { return stream.signal ? scope.getSignal(stream.signal).id : stream.scale ? scope.getScale(stream.scale).id : parseStream$1(stream, scope); }; function eventSource(source) { return source === SCOPE ? VIEW$1 : (source || VIEW$1); } function parseStream$1(stream, scope) { var method = stream.merge ? mergeStream : stream.stream ? nestedStream : stream.type ? eventStream : error$1('Invalid stream specification: ' + $(stream)); return method(stream, scope); } function mergeStream(stream, scope) { var list = stream.merge.map(function(s) { return parseStream$1(s, scope); }); var entry = streamParameters({merge: list}, stream, scope); return scope.addStream(entry).id; } function nestedStream(stream, scope) { var id$$1 = parseStream$1(stream.stream, scope), entry = streamParameters({stream: id$$1}, stream, scope); return scope.addStream(entry).id; } function eventStream(stream, scope) { var id$$1 = scope.event(eventSource(stream.source), stream.type), entry = streamParameters({stream: id$$1}, stream, scope); return Object.keys(entry).length === 1 ? id$$1 : scope.addStream(entry).id; } function streamParameters(entry, stream, scope) { var param = stream.between; if (param) { if (param.length !== 2) { error$1('Stream "between" parameter must have 2 entries: ' + $(stream)); } entry.between = [ parseStream$1(param[0], scope), parseStream$1(param[1], scope) ]; } param = stream.filter ? array(stream.filter) : []; if (stream.marktype || stream.markname || stream.markrole) { // add filter for mark type, name and/or role param.push(filterMark(stream.marktype, stream.markname, stream.markrole)); } if (stream.source === SCOPE) { // add filter to limit events from sub-scope only param.push('inScope(event.item)'); } if (param.length) { entry.filter = parseExpression('(' + param.join(')&&(') + ')').$expr; } if ((param = stream.throttle) != null) { entry.throttle = +param; } if ((param = stream.debounce) != null) { entry.debounce = +param; } if (stream.consume) { entry.consume = true; } return entry; } function filterMark(type, name, role) { var item = 'event.item'; return item + (type && type !== '*' ? '&&' + item + '.mark.marktype===\'' + type + '\'' : '') + (role ? '&&' + item + '.mark.role===\'' + role + '\'' : '') + (name ? '&&' + item + '.mark.name===\'' + name + '\'' : ''); } /** * Parse an event selector string. * Returns an array of event stream definitions. */ var selector = function(selector, source, marks) { DEFAULT_SOURCE = source || VIEW$2; MARKS = marks || DEFAULT_MARKS; return parseMerge(selector.trim()).map(parseSelector); }; var VIEW$2 = 'view'; var LBRACK = '['; var RBRACK = ']'; var LBRACE = '{'; var RBRACE = '}'; var COLON = ':'; var COMMA = ','; var NAME = '@'; var GT = '>'; var ILLEGAL$1 = /[[\]{}]/; var DEFAULT_SOURCE; var MARKS; var DEFAULT_MARKS = { '*': 1, arc: 1, area: 1, group: 1, image: 1, line: 1, path: 1, rect: 1, rule: 1, shape: 1, symbol: 1, text: 1, trail: 1 }; function isMarkType(type) { return MARKS.hasOwnProperty(type); } function find$1(s, i, endChar, pushChar, popChar) { var count = 0, n = s.length, c; for (; i= 0) --count; else if (pushChar && pushChar.indexOf(c) >= 0) ++count; } return i; } function parseMerge(s) { var output = [], start = 0, n = s.length, i = 0; while (i < n) { i = find$1(s, i, COMMA, LBRACK + LBRACE, RBRACK + RBRACE); output.push(s.substring(start, i).trim()); start = ++i; } if (output.length === 0) { throw 'Empty event selector: ' + s; } return output; } function parseSelector(s) { return s[0] === '[' ? parseBetween(s) : parseStream$2(s); } function parseBetween(s) { var n = s.length, i = 1, b, stream; i = find$1(s, i, RBRACK, LBRACK, RBRACK); if (i === n) { throw 'Empty between selector: ' + s; } b = parseMerge(s.substring(1, i)); if (b.length !== 2) { throw 'Between selector must have two elements: ' + s; } s = s.slice(i + 1).trim(); if (s[0] !== GT) { throw 'Expected \'>\' after between selector: ' + s; } b = b.map(parseSelector); stream = parseSelector(s.slice(1).trim()); if (stream.between) { return { between: b, stream: stream }; } else { stream.between = b; } return stream; } function parseStream$2(s) { var stream = {source: DEFAULT_SOURCE}, source = [], throttle = [0, 0], markname = 0, start = 0, n = s.length, i = 0, j, filter; // extract throttle from end if (s[n-1] === RBRACE) { i = s.lastIndexOf(LBRACE); if (i >= 0) { try { throttle = parseThrottle(s.substring(i+1, n-1)); } catch (e) { throw 'Invalid throttle specification: ' + s; } s = s.slice(0, i).trim(); n = s.length; } else throw 'Unmatched right brace: ' + s; i = 0; } if (!n) throw s; // set name flag based on first char if (s[0] === NAME) markname = ++i; // extract first part of multi-part stream selector j = find$1(s, i, COLON); if (j < n) { source.push(s.substring(start, j).trim()); start = i = ++j; } // extract remaining part of stream selector i = find$1(s, i, LBRACK); if (i === n) { source.push(s.substring(start, n).trim()); } else { source.push(s.substring(start, i).trim()); filter = []; start = ++i; if (start === n) throw 'Unmatched left bracket: ' + s; } // extract filters while (i < n) { i = find$1(s, i, RBRACK); if (i === n) throw 'Unmatched left bracket: ' + s; filter.push(s.substring(start, i).trim()); if (i < n-1 && s[++i] !== LBRACK) throw 'Expected left bracket: ' + s; start = ++i; } // marshall event stream specification if (!(n = source.length) || ILLEGAL$1.test(source[n-1])) { throw 'Invalid event selector: ' + s; } if (n > 1) { stream.type = source[1]; if (markname) { stream.markname = source[0].slice(1); } else if (isMarkType(source[0])) { stream.marktype = source[0]; } else { stream.source = source[0]; } } else { stream.type = source[0]; } if (stream.type.slice(-1) === '!') { stream.consume = true; stream.type = stream.type.slice(0, -1); } if (filter != null) stream.filter = filter; if (throttle[0]) stream.throttle = throttle[0]; if (throttle[1]) stream.debounce = throttle[1]; return stream; } function parseThrottle(s) { var a = s.split(COMMA); if (!s.length || a.length > 2) throw s; return a.map(function(_) { var x = +_; if (x !== x) throw s; return x; }); } var preamble = 'var datum=event.item&&event.item.datum;'; var parseUpdate = function(spec, scope, target) { var events = spec.events, update = spec.update, encode = spec.encode, sources = [], value = '', entry; if (!events) { error$1('Signal update missing events specification.'); } // interpret as an event selector string if (isString(events)) { events = selector(events); } // separate event streams from signal updates events = array(events).filter(function(stream) { if (stream.signal || stream.scale) { sources.push(stream); return 0; } else { return 1; } }); // merge event streams, include as source if (events.length) { sources.push(events.length > 1 ? {merge: events} : events[0]); } if (encode != null) { if (update) error$1('Signal encode and update are mutually exclusive.'); update = 'encode(item(),' + $(encode) + ')'; } // resolve update value value = isString(update) ? parseExpression(update, scope, preamble) : update.expr != null ? parseExpression(update.expr, scope, preamble) : update.value != null ? update.value : update.signal != null ? { $expr: '_.value', $params: {value: scope.signalRef(update.signal)} } : error$1('Invalid signal update specification.'); entry = { target: target, update: value }; if (spec.force) { entry.options = {force: true}; } sources.forEach(function(source) { source = {source: parseStream(source, scope)}; scope.addUpdate(extend(source, entry)); }); }; var parseSignalUpdates = function(signal, scope) { var op = scope.getSignal(signal.name); if (signal.update) { var expr = parseExpression(signal.update, scope); op.update = expr.$expr; op.params = expr.$params; } if (signal.on) { signal.on.forEach(function(_) { parseUpdate(_, scope, op.id); }); } }; function Entry(type, value, params, parent) { this.id = -1; this.type = type; this.value = value; this.params = params; if (parent) this.parent = parent; } function entry(type, value, params, parent) { return new Entry(type, value, params, parent); } function operator(value, params) { return entry('operator', value, params); } // ----- function ref(op) { var ref = {$ref: op.id}; // if operator not yet registered, cache ref to resolve later if (op.id < 0) (op.refs = op.refs || []).push(ref); return ref; } var tupleidRef = { $tupleid: 1, toString: function() { return ':_tupleid_:'; } }; function fieldRef$1(field$$1, name) { return name ? {$field: field$$1, $name: name} : {$field: field$$1}; } var keyFieldRef = fieldRef$1('key'); function compareRef(fields, orders) { return {$compare: fields, $order: orders}; } function keyRef(fields) { return {$key: fields}; } // ----- var Ascending = 'ascending'; var Descending = 'descending'; function sortKey(sort) { return !isObject(sort) ? '' : (sort.order === Descending ? '-' : '+') + aggrField(sort.op, sort.field); } function aggrField(op, field$$1) { return (op && op.signal ? '$' + op.signal : op || '') + (op && field$$1 ? '_' : '') + (field$$1 && field$$1.signal ? '$' + field$$1.signal : field$$1 || ''); } // ----- function isSignal(_) { return _ && _.signal; } function value(specValue, defaultValue) { return specValue != null ? specValue : defaultValue; } function transform$2(name) { return function(params, value$$1, parent) { return entry(name, value$$1, params || undefined, parent); }; } var Aggregate$1 = transform$2('aggregate'); var AxisTicks$1 = transform$2('axisticks'); var Bound$1 = transform$2('bound'); var Collect$1 = transform$2('collect'); var Compare$1 = transform$2('compare'); var DataJoin$1 = transform$2('datajoin'); var Encode$1 = transform$2('encode'); var Facet$1 = transform$2('facet'); var Field$1 = transform$2('field'); var Key$1 = transform$2('key'); var LegendEntries$1 = transform$2('legendentries'); var Mark$1 = transform$2('mark'); var MultiExtent$1 = transform$2('multiextent'); var MultiValues$1 = transform$2('multivalues'); var Overlap$1 = transform$2('overlap'); var Params$2 = transform$2('params'); var PreFacet$1 = transform$2('prefacet'); var Projection$1 = transform$2('projection'); var Proxy$1 = transform$2('proxy'); var Relay$1 = transform$2('relay'); var Render$1 = transform$2('render'); var Scale$1 = transform$2('scale'); var Sieve$1 = transform$2('sieve'); var SortItems$1 = transform$2('sortitems'); var ViewLayout$1 = transform$2('viewlayout'); var Values$1 = transform$2('values'); var FIELD_REF_ID = 0; var types = [ 'identity', 'ordinal', 'band', 'point', 'bin-linear', 'bin-ordinal', 'linear', 'pow', 'sqrt', 'log', 'sequential', 'time', 'utc', 'quantize', 'quantile', 'threshold' ]; var allTypes = toSet(types); var ordinalTypes = toSet(types.slice(1, 6)); function isOrdinal(type) { return ordinalTypes.hasOwnProperty(type); } function isQuantile(type) { return type === 'quantile'; } function initScale(spec, scope) { var type = spec.type || 'linear'; if (!allTypes.hasOwnProperty(type)) { error$1('Unrecognized scale type: ' + $(type)); } scope.addScale(spec.name, { type: type, domain: undefined }); } function parseScale(spec, scope) { var params = scope.getScale(spec.name).params, key$$1; params.domain = parseScaleDomain(spec.domain, spec, scope); if (spec.range != null) { params.range = parseScaleRange(spec, scope, params); } if (spec.interpolate != null) { parseScaleInterpolate(spec.interpolate, params); } if (spec.nice != null) { parseScaleNice(spec.nice, params); } for (key$$1 in spec) { if (params.hasOwnProperty(key$$1) || key$$1 === 'name') continue; params[key$$1] = parseLiteral(spec[key$$1], scope); } } function parseLiteral(v, scope) { return !isObject(v) ? v : v.signal ? scope.signalRef(v.signal) : error$1('Unsupported object: ' + $(v)); } function parseArray(v, scope) { return v.signal ? scope.signalRef(v.signal) : v.map(function(v) { return parseLiteral(v, scope); }); } function dataLookupError(name) { error$1('Can not find data set: ' + $(name)); } // -- SCALE DOMAIN ---- function parseScaleDomain(domain, spec, scope) { if (!domain) { if (spec.domainMin != null || spec.domainMax != null) { error$1('No scale domain defined for domainMin/domainMax to override.'); } return; // default domain } return domain.signal ? scope.signalRef(domain.signal) : (isArray(domain) ? explicitDomain : domain.fields ? multipleDomain : singularDomain)(domain, spec, scope); } function explicitDomain(domain, spec, scope) { return domain.map(function(v) { return parseLiteral(v, scope); }); } function singularDomain(domain, spec, scope) { var data = scope.getData(domain.data); if (!data) dataLookupError(domain.data); return isOrdinal(spec.type) ? data.valuesRef(scope, domain.field, parseSort(domain.sort, false)) : isQuantile(spec.type) ? data.domainRef(scope, domain.field) : data.extentRef(scope, domain.field); } function multipleDomain(domain, spec, scope) { var data = domain.data, fields = domain.fields.reduce(function(dom, d) { d = isString(d) ? {data: data, field: d} : (isArray(d) || d.signal) ? fieldRef(d, scope) : d; dom.push(d); return dom; }, []); return (isOrdinal(spec.type) ? ordinalMultipleDomain : isQuantile(spec.type) ? quantileMultipleDomain : numericMultipleDomain)(domain, scope, fields); } function fieldRef(data, scope) { var name = '_:vega:_' + (FIELD_REF_ID++), coll = Collect$1({}); if (isArray(data)) { coll.value = {$ingest: data}; } else if (data.signal) { scope.signalRef('setdata(' + $(name) + ',' + data.signal + ')'); } scope.addDataPipeline(name, [coll, Sieve$1({})]); return {data: name, field: 'data'}; } function ordinalMultipleDomain(domain, scope, fields) { var counts, a, c, v; // get value counts for each domain field counts = fields.map(function(f) { var data = scope.getData(f.data); if (!data) dataLookupError(f.data); return data.countsRef(scope, f.field); }); // sum counts from all fields a = scope.add(Aggregate$1({ groupby: keyFieldRef, ops:['sum'], fields: [scope.fieldRef('count')], as:['count'], pulse: counts })); // collect aggregate output c = scope.add(Collect$1({pulse: ref(a)})); // extract values for combined domain v = scope.add(Values$1({ field: keyFieldRef, sort: scope.sortRef(parseSort(domain.sort, true)), pulse: ref(c) })); return ref(v); } function parseSort(sort, multidomain) { if (sort) { if (!sort.field && !sort.op) { if (isObject(sort)) sort.field = 'key'; else sort = {field: 'key'}; } else if (!sort.field && sort.op !== 'count') { error$1('No field provided for sort aggregate op: ' + sort.op); } else if (multidomain && sort.field) { error$1('Multiple domain scales can not sort by field.'); } else if (multidomain && sort.op && sort.op !== 'count') { error$1('Multiple domain scales support op count only.'); } } return sort; } function quantileMultipleDomain(domain, scope, fields) { // get value arrays for each domain field var values = fields.map(function(f) { var data = scope.getData(f.data); if (!data) dataLookupError(f.data); return data.domainRef(scope, f.field); }); // combine value arrays return ref(scope.add(MultiValues$1({values: values}))); } function numericMultipleDomain(domain, scope, fields) { // get extents for each domain field var extents = fields.map(function(f) { var data = scope.getData(f.data); if (!data) dataLookupError(f.data); return data.extentRef(scope, f.field); }); // combine extents return ref(scope.add(MultiExtent$1({extents: extents}))); } // -- SCALE NICE ----- function parseScaleNice(nice, params) { params.nice = isObject(nice) ? { interval: parseLiteral(nice.interval), step: parseLiteral(nice.step) } : parseLiteral(nice); } // -- SCALE INTERPOLATION ----- function parseScaleInterpolate(interpolate, params) { params.interpolate = parseLiteral(interpolate.type || interpolate); if (interpolate.gamma != null) { params.interpolateGamma = parseLiteral(interpolate.gamma); } } // -- SCALE RANGE ----- function parseScaleRange(spec, scope, params) { var range = spec.range, config = scope.config.range; if (range.signal) { return scope.signalRef(range.signal); } else if (isString(range)) { if (config && config.hasOwnProperty(range)) { spec = extend({}, spec, {range: config[range]}); return parseScaleRange(spec, scope, params); } else if (range === 'width') { range = [0, {signal: 'width'}]; } else if (range === 'height') { range = isOrdinal(spec.type) ? [0, {signal: 'height'}] : [{signal: 'height'}, 0]; } else { error$1('Unrecognized scale range value: ' + $(range)); } } else if (range.scheme) { params.scheme = parseLiteral(range.scheme, scope); if (range.extent) params.schemeExtent = parseArray(range.extent, scope); if (range.count) params.schemeCount = parseLiteral(range.count, scope); return; } else if (range.step) { params.rangeStep = parseLiteral(range.step, scope); return; } else if (isOrdinal(spec.type) && !isArray(range)) { return parseScaleDomain(range, spec, scope); } else if (!isArray(range)) { error$1('Unsupported range type: ' + $(range)); } return range.map(function(v) { return parseLiteral(v, scope); }); } var parseProjection = function(proj, scope) { var params = {}; for (var name in proj) { if (name === 'name') continue; params[name] = parseParameter(proj[name], scope); } scope.addProjection(proj.name, params); }; function parseParameter(_, scope) { return isArray(_) ? _.map(function(_) { return parseParameter(_, scope); }) : !isObject(_) ? _ : _.signal ? scope.signalRef(_.signal) : error$1('Unsupported parameter object: ' + $(_)); } var Top$1 = 'top'; var Left$1 = 'left'; var Right$1 = 'right'; var Bottom$1 = 'bottom'; var Index = 'index'; var Label = 'label'; var Offset = 'offset'; var Perc = 'perc'; var Size = 'size'; var Total = 'total'; var Value = 'value'; var GuideLabelStyle = 'guide-label'; var GuideTitleStyle = 'guide-title'; var GroupTitleStyle = 'group-title'; var LegendScales = [ 'shape', 'size', 'fill', 'stroke', 'strokeDash', 'opacity' ]; var Skip = { name: 1, interactive: 1 }; var Skip$1 = toSet(['rule']); var Swap = toSet(['group', 'image', 'rect']); var adjustSpatial = function(encode, marktype) { var code = ''; if (Skip$1[marktype]) return code; if (encode.x2) { if (encode.x) { if (Swap[marktype]) { code += 'if(o.x>o.x2)$=o.x,o.x=o.x2,o.x2=$;'; } code += 'o.width=o.x2-o.x;'; } else { code += 'o.x=o.x2-(o.width||0);'; } } if (encode.xc) { code += 'o.x=o.xc-(o.width||0)/2;'; } if (encode.y2) { if (encode.y) { if (Swap[marktype]) { code += 'if(o.y>o.y2)$=o.y,o.y=o.y2,o.y2=$;'; } code += 'o.height=o.y2-o.y;'; } else { code += 'o.y=o.y2-(o.height||0);'; } } if (encode.yc) { code += 'o.y=o.yc-(o.height||0)/2;'; } return code; }; var color$2 = function(enc, scope, params, fields) { function color(type, x, y, z) { var a = entry$1(null, x, scope, params, fields), b = entry$1(null, y, scope, params, fields), c = entry$1(null, z, scope, params, fields); return 'this.' + type + '(' + [a, b, c].join(',') + ').toString()'; } return (enc.c) ? color('hcl', enc.h, enc.c, enc.l) : (enc.h || enc.s) ? color('hsl', enc.h, enc.s, enc.l) : (enc.l || enc.a) ? color('lab', enc.l, enc.a, enc.b) : (enc.r || enc.g || enc.b) ? color('rgb', enc.r, enc.g, enc.b) : null; }; var expression = function(code, scope, params, fields) { var expr = parseExpression(code, scope); expr.$fields.forEach(function(name) { fields[name] = 1; }); extend(params, expr.$params); return expr.$expr; }; var field$1 = function(ref, scope, params, fields) { return resolve$1(isObject(ref) ? ref : {datum: ref}, scope, params, fields); }; function resolve$1(ref, scope, params, fields) { var object, level, field$$1; if (ref.signal) { object = 'datum'; field$$1 = expression(ref.signal, scope, params, fields); } else if (ref.group || ref.parent) { level = Math.max(1, ref.level || 1); object = 'item'; while (level-- > 0) { object += '.mark.group'; } if (ref.parent) { field$$1 = ref.parent; object += '.datum'; } else { field$$1 = ref.group; } } else if (ref.datum) { object = 'datum'; field$$1 = ref.datum; } else { error$1('Invalid field reference: ' + $(ref)); } if (!ref.signal) { if (isString(field$$1)) { fields[field$$1] = 1; // TODO review field tracking? field$$1 = splitAccessPath(field$$1).map($).join(']['); } else { field$$1 = resolve$1(field$$1, scope, params, fields); } } return object + '[' + field$$1 + ']'; } var scale$3 = function(enc, value, scope, params, fields) { var scale = getScale$1(enc.scale, scope, params, fields), interp, func, flag; if (enc.range != null) { // pull value from scale range interp = +enc.range; func = scale + '.range()'; value = (interp === 0) ? (func + '[0]') : '($=' + func + ',' + ((interp === 1) ? '$[$.length-1]' : '$[0]+' + interp + '*($[$.length-1]-$[0])') + ')'; } else { // run value through scale and/or pull scale bandwidth if (value !== undefined) value = scale + '(' + value + ')'; if (enc.band && (flag = hasBandwidth(enc.scale, scope))) { func = scale + '.bandwidth'; interp = +enc.band; interp = func + '()' + (interp===1 ? '' : '*' + interp); // if we don't know the scale type, check for bandwidth if (flag < 0) interp = '(' + func + '?' + interp + ':0)'; value = (value ? value + '+' : '') + interp; if (enc.extra) { // include logic to handle extraneous elements value = '(datum.extra?' + scale + '(datum.extra.value):' + value + ')'; } } if (value == null) value = '0'; } return value; }; function hasBandwidth(name, scope) { if (!isString(name)) return -1; var type = scope.scaleType(name); return type === 'band' || type === 'point' ? 1 : 0; } function getScale$1(name, scope, params, fields) { var scaleName; if (isString(name)) { // direct scale lookup; add scale as parameter scaleName = scalePrefix + name; if (!params.hasOwnProperty(scaleName)) { params[scaleName] = scope.scaleRef(name); } scaleName = $(scaleName); } else { // indirect scale lookup; add all scales as parameters for (scaleName in scope.scales) { params[scalePrefix + scaleName] = scope.scaleRef(scaleName); } scaleName = $(scalePrefix) + '+' + (name.signal ? '(' + expression(name.signal, scope, params, fields) + ')' : field$1(name, scope, params, fields)); } return '_[' + scaleName + ']'; } var gradient$1 = function(enc, scope, params, fields) { return 'this.gradient(' + getScale$1(enc.gradient, scope, params, fields) + ',' + $(enc.start) + ',' + $(enc.stop) + ',' + $(enc.count) + ')'; }; var property = function(property, scope, params, fields) { return isObject(property) ? '(' + entry$1(null, property, scope, params, fields) + ')' : property; }; var entry$1 = function(channel, enc, scope, params, fields) { if (enc.gradient != null) { return gradient$1(enc, scope, params, fields); } var value = enc.signal ? expression(enc.signal, scope, params, fields) : enc.color ? color$2(enc.color, scope, params, fields) : enc.field != null ? field$1(enc.field, scope, params, fields) : enc.value !== undefined ? $(enc.value) : undefined; if (enc.scale != null) { value = scale$3(enc, value, scope, params, fields); } if (value === undefined) { value = null; } if (enc.exponent != null) { value = 'Math.pow(' + value + ',' + property(enc.exponent, scope, params, fields) + ')'; } if (enc.mult != null) { value += '*' + property(enc.mult, scope, params, fields); } if (enc.offset != null) { value += '+' + property(enc.offset, scope, params, fields); } if (enc.round) { value = 'Math.round(' + value + ')'; } return value; }; var set$5 = function(obj, key$$1, value) { return obj + '[' + $(key$$1) + ']=' + value + ';'; }; var rule$1 = function(channel, rules, scope, params, fields) { var code = ''; rules.forEach(function(rule) { var value = entry$1(channel, rule, scope, params, fields); code += rule.test ? expression(rule.test, scope, params, fields) + '?' + value + ':' : value; }); return set$5('o', channel, code); }; function parseEncode(encode, marktype, params, scope) { var fields = {}, code = 'var o=item,datum=o.datum,$;', channel, enc, value; for (channel in encode) { enc = encode[channel]; if (isArray(enc)) { // rule code += rule$1(channel, enc, scope, params, fields); } else { value = entry$1(channel, enc, scope, params, fields); code += set$5('o', channel, value); } } code += adjustSpatial(encode, marktype); code += 'return 1;'; return { $expr: code, $fields: Object.keys(fields), $output: Object.keys(encode) }; } var MarkRole = 'mark'; var FrameRole$1 = 'frame'; var ScopeRole$1 = 'scope'; var AxisRole$2 = 'axis'; var AxisDomainRole = 'axis-domain'; var AxisGridRole = 'axis-grid'; var AxisLabelRole = 'axis-label'; var AxisTickRole = 'axis-tick'; var AxisTitleRole = 'axis-title'; var LegendRole$2 = 'legend'; var LegendEntryRole = 'legend-entry'; var LegendGradientRole = 'legend-gradient'; var LegendLabelRole = 'legend-label'; var LegendSymbolRole = 'legend-symbol'; var LegendTitleRole = 'legend-title'; var TitleRole$1 = 'title'; function encoder(_) { return isObject(_) ? _ : {value: _}; } function addEncode(object, name, value) { if (value != null) { object[name] = {value: value}; return 1; } else { return 0; } } function extendEncode(encode, extra, skip) { for (var name in extra) { if (skip && skip.hasOwnProperty(name)) continue; encode[name] = extend(encode[name] || {}, extra[name]); } return encode; } function encoders(encode, type, role, style, scope, params) { var enc, key$$1; params = params || {}; params.encoders = {$encode: (enc = {})}; encode = applyDefaults(encode, type, role, style, scope.config); for (key$$1 in encode) { enc[key$$1] = parseEncode(encode[key$$1], type, params, scope); } return params; } function applyDefaults(encode, type, role, style, config) { var enter = {}, key$$1, skip, props; // ignore legend and axis if (role == 'legend' || String(role).indexOf('axis') === 0) { role = null; } // resolve mark config props = role === FrameRole$1 ? config.group : (role === MarkRole) ? extend({}, config.mark, config[type]) : null; for (key$$1 in props) { // do not apply defaults if relevant fields are defined skip = has(key$$1, encode) || (key$$1 === 'fill' || key$$1 === 'stroke') && (has('fill', encode) || has('stroke', encode)); if (!skip) enter[key$$1] = {value: props[key$$1]}; } // resolve styles, apply with increasing precedence array(style).forEach(function(name) { var props = config.style && config.style[name]; for (var key$$1 in props) { if (!has(key$$1, encode)) { enter[key$$1] = {value: props[key$$1]}; } } }); encode = extend({}, encode); // defensive copy encode.enter = extend(enter, encode.enter); return encode; } function has(key$$1, encode) { return encode && ( (encode.enter && encode.enter[key$$1]) || (encode.update && encode.update[key$$1]) ); } var guideMark = function(type, role, style, key, dataRef, encode, extras) { return { type: type, name: extras ? extras.name : undefined, role: role, style: (extras && extras.style) || style, key: key, from: dataRef, interactive: !!(extras && extras.interactive), encode: extendEncode(encode, extras, Skip) }; }; var GroupMark = 'group'; var RectMark = 'rect'; var RuleMark = 'rule'; var SymbolMark = 'symbol'; var TextMark = 'text'; var legendGradient = function(spec, scale, config, userEncode) { var zero = {value: 0}, encode = {}, enter, update; encode.enter = enter = { opacity: zero, x: zero, y: zero }; addEncode(enter, 'width', config.gradientWidth); addEncode(enter, 'height', config.gradientHeight); addEncode(enter, 'stroke', config.gradientStrokeColor); addEncode(enter, 'strokeWidth', config.gradientStrokeWidth); encode.exit = { opacity: zero }; encode.update = update = { x: zero, y: zero, fill: {gradient: scale}, opacity: {value: 1} }; addEncode(update, 'width', config.gradientWidth); addEncode(update, 'height', config.gradientHeight); return guideMark(RectMark, LegendGradientRole, null, undefined, undefined, encode, userEncode); }; var alignExpr = 'datum.' + Perc + '<=0?"left"' + ':datum.' + Perc + '>=1?"right":"center"'; var legendGradientLabels = function(spec, config, userEncode, dataRef) { var zero = {value: 0}, encode = {}, enter, update; encode.enter = enter = { opacity: zero, text: {field: Label} }; addEncode(enter, 'fill', config.labelColor); addEncode(enter, 'font', config.labelFont); addEncode(enter, 'fontSize', config.labelFontSize); addEncode(enter, 'baseline', config.gradientLabelBaseline); addEncode(enter, 'limit', config.gradientLabelLimit); encode.exit = { opacity: zero }; encode.update = update = { opacity: {value: 1} }; enter.x = update.x = { field: Perc, mult: config.gradientWidth }; enter.y = update.y = { value: config.gradientHeight, offset: config.gradientLabelOffset }; enter.align = update.align = {signal: alignExpr}; return guideMark(TextMark, LegendLabelRole, GuideLabelStyle, Perc, dataRef, encode, userEncode); }; var legendLabels = function(spec, config, userEncode, dataRef) { var zero = {value: 0}, encode = {}, enter, update; encode.enter = enter = { opacity: zero }; addEncode(enter, 'align', config.labelAlign); addEncode(enter, 'baseline', config.labelBaseline); addEncode(enter, 'fill', config.labelColor); addEncode(enter, 'font', config.labelFont); addEncode(enter, 'fontSize', config.labelFontSize); addEncode(enter, 'limit', config.labelLimit); encode.exit = { opacity: zero }; encode.update = update = { opacity: {value: 1}, text: {field: Label} }; enter.x = update.x = { field: Offset, offset: config.labelOffset }; enter.y = update.y = { field: Size, mult: 0.5, offset: { field: Total, offset: { field: {group: 'entryPadding'}, mult: {field: Index} } } }; return guideMark(TextMark, LegendLabelRole, GuideLabelStyle, Value, dataRef, encode, userEncode); }; var legendSymbols = function(spec, config, userEncode, dataRef) { var zero = {value: 0}, encode = {}, enter, update; encode.enter = enter = { opacity: zero }; addEncode(enter, 'shape', config.symbolType); addEncode(enter, 'size', config.symbolSize); addEncode(enter, 'strokeWidth', config.symbolStrokeWidth); if (!spec.fill) { addEncode(enter, 'fill', config.symbolFillColor); addEncode(enter, 'stroke', config.symbolStrokeColor); } encode.exit = { opacity: zero }; encode.update = update = { opacity: {value: 1} }; enter.x = update.x = { field: Offset, mult: 0.5 }; enter.y = update.y = { field: Size, mult: 0.5, offset: { field: Total, offset: { field: {group: 'entryPadding'}, mult: {field: Index} } } }; LegendScales.forEach(function(scale) { if (spec[scale]) { update[scale] = enter[scale] = {scale: spec[scale], field: Value}; } }); return guideMark(SymbolMark, LegendSymbolRole, null, Value, dataRef, encode, userEncode); }; var legendTitle = function(spec, config, userEncode, dataRef) { var zero = {value: 0}, title = spec.title, encode = {}, enter; encode.enter = enter = { x: {field: {group: 'padding'}}, y: {field: {group: 'padding'}}, opacity: zero }; addEncode(enter, 'align', config.titleAlign); addEncode(enter, 'baseline', config.titleBaseline); addEncode(enter, 'fill', config.titleColor); addEncode(enter, 'font', config.titleFont); addEncode(enter, 'fontSize', config.titleFontSize); addEncode(enter, 'fontWeight', config.titleFontWeight); addEncode(enter, 'limit', config.titleLimit); encode.exit = { opacity: zero }; encode.update = { opacity: {value: 1}, text: title && title.signal ? {signal: title.signal} : {value: title + ''} }; return guideMark(TextMark, LegendTitleRole, GuideTitleStyle, null, dataRef, encode, userEncode); }; var guideGroup = function(role, style, name, dataRef, interactive, encode, marks) { return { type: GroupMark, name: name, role: role, style: style, from: dataRef, interactive: interactive, encode: encode, marks: marks }; }; var role = function(spec) { var role = spec.role || ''; return (!role.indexOf('axis') || !role.indexOf('legend')) ? role : spec.type === GroupMark ? ScopeRole$1 : (role || MarkRole); }; var definition$1 = function(spec) { return { clip: spec.clip || false, interactive: spec.interactive === false ? false : true, marktype: spec.type, name: spec.name || undefined, role: spec.role || role(spec), zindex: +spec.zindex || undefined }; }; /** * Parse a data transform specification. */ var parseTransform = function(spec, scope) { var def = definition(spec.type); if (!def) error$1('Unrecognized transform type: ' + $(spec.type)); var t = entry(def.type.toLowerCase(), null, parseParameters(def, spec, scope)); if (spec.signal) scope.addSignal(spec.signal, scope.proxy(t)); t.metadata = def.metadata || {}; return t; }; /** * Parse all parameters of a data transform. */ function parseParameters(def, spec, scope) { var params = {}, pdef, i, n; for (i=0, n=def.params.length; i 0 ? ',' : '') + (isObject(value$$1) ? (value$$1.signal || propertyLambda(value$$1)) : $(value$$1)); } return code + ']'; } function objectLambda(obj) { var code = '{', i = 0, key$$1, value$$1; for (key$$1 in obj) { value$$1 = obj[key$$1]; code += (++i > 1 ? ',' : '') + $(key$$1) + ':' + (isObject(value$$1) ? (value$$1.signal || propertyLambda(value$$1)) : $(value$$1)); } return code + '}'; } prototype$82.addBinding = function(name, bind) { if (!this.bindings) { error$1('Nested signals do not support binding: ' + $(name)); } this.bindings.push(extend({signal: name}, bind)); }; // ---- prototype$82.addScaleProj = function(name, transform) { if (this.scales.hasOwnProperty(name)) { error$1('Duplicate scale or projection name: ' + $(name)); } this.scales[name] = this.add(transform); }; prototype$82.addScale = function(name, params) { this.addScaleProj(name, Scale$1(params)); }; prototype$82.addProjection = function(name, params) { this.addScaleProj(name, Projection$1(params)); }; prototype$82.getScale = function(name) { if (!this.scales[name]) { error$1('Unrecognized scale name: ' + $(name)); } return this.scales[name]; }; prototype$82.projectionRef = prototype$82.scaleRef = function(name) { return ref(this.getScale(name)); }; prototype$82.projectionType = prototype$82.scaleType = function(name) { return this.getScale(name).params.type; }; // ---- prototype$82.addData = function(name, dataScope) { if (this.data.hasOwnProperty(name)) { error$1('Duplicate data set name: ' + $(name)); } return (this.data[name] = dataScope); }; prototype$82.getData = function(name) { if (!this.data[name]) { error$1('Undefined data set name: ' + $(name)); } return this.data[name]; }; prototype$82.addDataPipeline = function(name, entries) { if (this.data.hasOwnProperty(name)) { error$1('Duplicate data set name: ' + $(name)); } return this.addData(name, DataScope.fromEntries(this, entries)); }; var defaults = function(configs) { var output = defaults$1(); (configs || []).forEach(function(config) { var key$$1; if (config) for (key$$1 in config) { output[key$$1] = isObject(output[key$$1]) ? extend(output[key$$1], config[key$$1]) : output[key$$1] = config[key$$1]; } }); return output; }; var defaultFont = 'sans-serif'; var defaultSymbolSize = 30; var defaultStrokeWidth = 2; var defaultColor = '#4c78a8'; var black = "#000"; var gray = '#888'; var lightGray = '#ddd'; /** * Standard configuration defaults for Vega specification parsing. * Users can provide their own (sub-)set of these default values * by passing in a config object to the top-level parse method. */ function defaults$1() { return { // default padding around visualization padding: 0, // default for automatic sizing; options: "none", "pad", "fit" // or provide an object (e.g., {"type": "pad", "resize": true}) autosize: 'pad', // default view background color // covers the entire view component background: null, // default event handling configuration // preventDefault for view-sourced event types except 'wheel' events: { defaults: {allow: ['wheel']} }, // defaults for top-level group marks // accepts mark properties (fill, stroke, etc) // covers the data rectangle within group width/height group: null, // defaults for basic mark types // each subset accepts mark properties (fill, stroke, etc) mark: null, arc: { fill: defaultColor }, area: { fill: defaultColor }, image: null, line: { stroke: defaultColor, strokeWidth: defaultStrokeWidth }, path: { stroke: defaultColor }, rect: { fill: defaultColor }, rule: { stroke: black }, shape: { stroke: defaultColor }, symbol: { fill: defaultColor, size: 64 }, text: { fill: black, font: defaultFont, fontSize: 11 }, // style definitions style: { // axis & legend labels "guide-label": { fill: black, font: defaultFont, fontSize: 10 }, // axis & legend titles "guide-title": { fill: black, font: defaultFont, fontSize: 11, fontWeight: 'bold' }, // headers, including chart title "group-title": { fill: black, font: defaultFont, fontSize: 13, fontWeight: 'bold' }, // defaults for styled point marks in Vega-Lite point: { size: defaultSymbolSize, strokeWidth: defaultStrokeWidth, shape: 'circle' }, circle: { size: defaultSymbolSize, strokeWidth: defaultStrokeWidth }, square: { size: defaultSymbolSize, strokeWidth: defaultStrokeWidth, shape: 'square' }, // defaults for styled group marks in Vega-Lite cell: { fill: 'transparent', stroke: lightGray } }, // defaults for axes axis: { minExtent: 0, maxExtent: 200, bandPosition: 0.5, domain: true, domainWidth: 1, domainColor: gray, grid: false, gridWidth: 1, gridColor: lightGray, gridDash: [], gridOpacity: 1, labels: true, labelAngle: 0, labelLimit: 180, labelPadding: 2, ticks: true, tickColor: gray, tickOffset: 0, tickRound: true, tickSize: 5, tickWidth: 1, titleAlign: 'center', titlePadding: 2 }, // correction for centering bias axisBand: { tickOffset: -1 }, // defaults for legends legend: { orient: 'right', offset: 18, padding: 0, entryPadding: 5, titlePadding: 5, gradientWidth: 100, gradientHeight: 20, gradientStrokeColor: lightGray, gradientStrokeWidth: 0, gradientLabelBaseline: 'top', gradientLabelOffset: 2, labelAlign: 'left', labelBaseline: 'middle', labelOffset: 8, labelLimit: 160, symbolType: 'circle', symbolSize: 100, symbolFillColor: 'transparent', symbolStrokeColor: gray, symbolStrokeWidth: 1.5, titleAlign: 'left', titleBaseline: 'top', titleLimit: 180 }, // defaults for group title title: { orient: 'top', anchor: 'middle', offset: 2 }, // defaults for scale ranges range: { category: { scheme: 'tableau10' }, ordinal: { scheme: 'blues', extent: [0.2, 1] }, heatmap: { scheme: 'viridis' }, ramp: { scheme: 'blues', extent: [0.2, 1] }, diverging: { scheme: 'blueorange' }, symbol: [ 'circle', 'square', 'triangle-up', 'cross', 'diamond', 'triangle-right', 'triangle-down', 'triangle-left' ] } }; } var parse$2 = function(spec, config) { if (!isObject(spec)) error$1('Input Vega specification must be an object.'); return parseView(spec, new Scope(defaults([config, spec.config]))) .toRuntime(); }; /** * Parse an expression given the argument signature and body code. */ function expression$1(args, code, ctx) { // wrap code in return statement if expression does not terminate if (code[code.length-1] !== ';') { code = 'return(' + code + ');'; } var fn = Function.apply(null, args.concat(code)); return ctx && ctx.functions ? fn.bind(ctx.functions) : fn; } /** * Parse an expression used to update an operator value. */ function operatorExpression(code, ctx) { return expression$1(['_'], code, ctx); } /** * Parse an expression provided as an operator parameter value. */ function parameterExpression(code, ctx) { return expression$1(['datum', '_'], code, ctx); } /** * Parse an expression applied to an event stream. */ function eventExpression(code, ctx) { return expression$1(['event'], code, ctx); } /** * Parse an expression used to handle an event-driven operator update. */ function handlerExpression(code, ctx) { return expression$1(['_', 'event'], code, ctx); } /** * Parse an expression that performs visual encoding. */ function encodeExpression(code, ctx) { return expression$1(['item', '_'], code, ctx); } /** * Parse a set of operator parameters. */ function parseParameters$1(spec, ctx, params) { params = params || {}; var key$$1, value; for (key$$1 in spec) { value = spec[key$$1]; if (value && value.$expr && value.$params) { // if expression, parse its parameters parseParameters$1(value.$params, ctx, params); } params[key$$1] = isArray(value) ? value.map(function(v) { return parseParameter$2(v, ctx); }) : parseParameter$2(value, ctx); } return params; } /** * Parse a single parameter. */ function parseParameter$2(spec, ctx) { if (!spec || !isObject(spec)) return spec; for (var i=0, n=PARSERS.length, p; i