vega-dataflow
Advanced tools
Comparing version 3.1.0 to 4.0.0
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vega-util'), require('vega-loader')) : | ||
typeof define === 'function' && define.amd ? define(['exports', 'vega-util', 'vega-loader'], factory) : | ||
(factory((global.vega = global.vega || {}),global.vega,global.vega)); | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vega-util'), require('vega-loader')) : | ||
typeof define === 'function' && define.amd ? define(['exports', 'vega-util', 'vega-loader'], factory) : | ||
(factory((global.vega = {}),global.vega,global.vega)); | ||
}(this, (function (exports,vegaUtil,vegaLoader) { 'use strict'; | ||
function UniqueList(idFunc) { | ||
var $ = idFunc || vegaUtil.identity, | ||
list = [], | ||
ids = {}; | ||
function UniqueList(idFunc) { | ||
var $ = idFunc || vegaUtil.identity, | ||
list = [], | ||
ids = {}; | ||
list.add = function(_) { | ||
var id$$1 = $(_); | ||
if (!ids[id$$1]) { | ||
ids[id$$1] = 1; | ||
list.push(_); | ||
} | ||
return list; | ||
}; | ||
list.add = function(_) { | ||
var id = $(_); | ||
if (!ids[id]) { | ||
ids[id] = 1; | ||
list.push(_); | ||
} | ||
return list; | ||
}; | ||
list.remove = function(_) { | ||
var id$$1 = $(_), idx; | ||
if (ids[id$$1]) { | ||
ids[id$$1] = 0; | ||
if ((idx = list.indexOf(_)) >= 0) { | ||
list.splice(idx, 1); | ||
list.remove = function(_) { | ||
var id = $(_), idx; | ||
if (ids[id]) { | ||
ids[id] = 0; | ||
if ((idx = list.indexOf(_)) >= 0) { | ||
list.splice(idx, 1); | ||
} | ||
} | ||
} | ||
return list; | ||
}; | ||
return list; | ||
}; | ||
} | ||
return list; | ||
} | ||
var TUPLE_ID_KEY = Symbol('vega_id'), | ||
TUPLE_ID = 1; | ||
var TUPLE_ID_KEY = Symbol('vega_id'); | ||
var TUPLE_ID = 1; | ||
/** | ||
* 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)); | ||
} | ||
/** | ||
* Resets the internal tuple id counter to one. | ||
*/ | ||
/** | ||
* 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; | ||
} | ||
/** | ||
* 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)); | ||
} | ||
/** | ||
* 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++); | ||
} | ||
/** | ||
* Returns the id of a tuple. | ||
* @param {object} t - The input tuple. | ||
* @return {*} the tuple id. | ||
*/ | ||
function tupleid(t) { | ||
return t[TUPLE_ID_KEY]; | ||
} | ||
/** | ||
* 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({})); | ||
} | ||
/** | ||
* 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$$1) { | ||
t[TUPLE_ID_KEY] = id$$1; | ||
return t; | ||
} | ||
/** | ||
* 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; | ||
} | ||
/** | ||
* 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++); | ||
} | ||
/** | ||
* 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)); | ||
} | ||
/** | ||
* 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({})); | ||
} | ||
function isChangeSet(v) { | ||
return v && v.constructor === changeset; | ||
} | ||
/** | ||
* 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; | ||
} | ||
function changeset() { | ||
var add = [], // insert tuples | ||
rem = [], // remove tuples | ||
mod = [], // modify tuples | ||
remp = [], // remove by predicate | ||
modp = [], // modify by predicate | ||
reflow = false; | ||
/** | ||
* 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)); | ||
} | ||
return { | ||
constructor: changeset, | ||
insert: function(t) { | ||
var d = vegaUtil.array(t), i = 0, n = d.length; | ||
for (; i<n; ++i) add.push(d[i]); | ||
return this; | ||
}, | ||
remove: function(t) { | ||
var a = vegaUtil.isFunction(t) ? remp : rem, | ||
d = vegaUtil.array(t), i = 0, n = d.length; | ||
for (; i<n; ++i) a.push(d[i]); | ||
return this; | ||
}, | ||
modify: function(t, field, value) { | ||
var m = {field: field, value: vegaUtil.constant(value)}; | ||
if (vegaUtil.isFunction(t)) { | ||
m.filter = t; | ||
modp.push(m); | ||
} else { | ||
m.tuple = t; | ||
mod.push(m); | ||
} | ||
return this; | ||
}, | ||
encode: function(t, set) { | ||
if (vegaUtil.isFunction(t)) modp.push({filter: t, field: set}); | ||
else mod.push({tuple: t, field: set}); | ||
return this; | ||
}, | ||
reflow: function() { | ||
reflow = true; | ||
return this; | ||
}, | ||
pulse: function(pulse, tuples) { | ||
var out, i, n, m, f, t, id; | ||
function isChangeSet(v) { | ||
return v && v.constructor === changeset; | ||
} | ||
// add | ||
for (i=0, n=add.length; i<n; ++i) { | ||
pulse.add.push(ingest(add[i])); | ||
} | ||
function changeset() { | ||
var add = [], // insert tuples | ||
rem = [], // remove tuples | ||
mod = [], // modify tuples | ||
remp = [], // remove by predicate | ||
modp = [], // modify by predicate | ||
reflow = false; | ||
// remove | ||
for (out={}, i=0, n=rem.length; i<n; ++i) { | ||
t = rem[i]; | ||
out[tupleid(t)] = t; | ||
} | ||
for (i=0, n=remp.length; i<n; ++i) { | ||
f = remp[i]; | ||
tuples.forEach(function(t) { | ||
if (f(t)) out[tupleid(t)] = t; | ||
}); | ||
} | ||
for (id in out) pulse.rem.push(out[id]); | ||
return { | ||
constructor: changeset, | ||
insert: function(t) { | ||
var d = vegaUtil.array(t), i = 0, n = d.length; | ||
for (; i<n; ++i) add.push(d[i]); | ||
return this; | ||
}, | ||
remove: function(t) { | ||
var a = vegaUtil.isFunction(t) ? remp : rem, | ||
d = vegaUtil.array(t), i = 0, n = d.length; | ||
for (; i<n; ++i) a.push(d[i]); | ||
return this; | ||
}, | ||
modify: function(t, field, value) { | ||
var m = {field: field, value: vegaUtil.constant(value)}; | ||
if (vegaUtil.isFunction(t)) { | ||
m.filter = t; | ||
modp.push(m); | ||
} else { | ||
m.tuple = t; | ||
mod.push(m); | ||
} | ||
return this; | ||
}, | ||
encode: function(t, set) { | ||
if (vegaUtil.isFunction(t)) modp.push({filter: t, field: set}); | ||
else mod.push({tuple: t, field: set}); | ||
return this; | ||
}, | ||
reflow: function() { | ||
reflow = true; | ||
return this; | ||
}, | ||
pulse: function(pulse, tuples) { | ||
var out, i, n, m, f, t, id$$1; | ||
// modify | ||
function modify(t, f, v) { | ||
if (v) t[f] = v(t); else pulse.encode = f; | ||
if (!reflow) out[tupleid(t)] = t; | ||
} | ||
for (out={}, i=0, n=mod.length; i<n; ++i) { | ||
m = mod[i]; | ||
modify(m.tuple, m.field, m.value); | ||
pulse.modifies(m.field); | ||
} | ||
for (i=0, n=modp.length; i<n; ++i) { | ||
m = modp[i]; | ||
f = m.filter; | ||
tuples.forEach(function(t) { | ||
if (f(t)) modify(t, m.field, m.value); | ||
}); | ||
pulse.modifies(m.field); | ||
} | ||
// add | ||
for (i=0, n=add.length; i<n; ++i) { | ||
pulse.add.push(ingest(add[i])); | ||
} | ||
// reflow? | ||
if (reflow) { | ||
pulse.mod = rem.length || remp.length | ||
? tuples.filter(function(t) { return out.hasOwnProperty(tupleid(t)); }) | ||
: tuples.slice(); | ||
} else { | ||
for (id in out) pulse.mod.push(out[id]); | ||
} | ||
// remove | ||
for (out={}, i=0, n=rem.length; i<n; ++i) { | ||
t = rem[i]; | ||
out[tupleid(t)] = t; | ||
return pulse; | ||
} | ||
for (i=0, n=remp.length; i<n; ++i) { | ||
f = remp[i]; | ||
tuples.forEach(function(t) { | ||
if (f(t)) out[tupleid(t)] = t; | ||
}); | ||
} | ||
for (id$$1 in out) pulse.rem.push(out[id$$1]); | ||
}; | ||
} | ||
// modify | ||
function modify(t, f, v) { | ||
if (v) t[f] = v(t); else pulse.encode = f; | ||
if (!reflow) out[tupleid(t)] = t; | ||
var CACHE = '_:mod:_'; | ||
/** | ||
* Hash that tracks modifications to assigned values. | ||
* Callers *must* use the set method to update values. | ||
*/ | ||
function Parameters() { | ||
Object.defineProperty(this, CACHE, {writable:true, value: {}}); | ||
} | ||
var prototype = Parameters.prototype; | ||
/** | ||
* Set a parameter value. If the parameter value changes, the parameter | ||
* will be recorded as modified. | ||
* @param {string} name - The parameter name. | ||
* @param {number} index - The index into an array-value parameter. Ignored if | ||
* the argument is undefined, null or less than zero. | ||
* @param {*} value - The parameter value to set. | ||
* @param {boolean} [force=false] - If true, records the parameter as modified | ||
* even if the value is unchanged. | ||
* @return {Parameters} - This parameter object. | ||
*/ | ||
prototype.set = function(name, index, value, force) { | ||
var o = this, | ||
v = o[name], | ||
mod = o[CACHE]; | ||
if (index != null && index >= 0) { | ||
if (v[index] !== value || force) { | ||
v[index] = value; | ||
mod[index + ':' + name] = -1; | ||
mod[name] = -1; | ||
} | ||
for (out={}, i=0, n=mod.length; i<n; ++i) { | ||
m = mod[i]; | ||
modify(m.tuple, m.field, m.value); | ||
pulse.modifies(m.field); | ||
} | ||
for (i=0, n=modp.length; i<n; ++i) { | ||
m = modp[i]; | ||
f = m.filter; | ||
tuples.forEach(function(t) { | ||
if (f(t)) modify(t, m.field, m.value); | ||
}); | ||
pulse.modifies(m.field); | ||
} | ||
} else if (v !== value || force) { | ||
o[name] = value; | ||
mod[name] = vegaUtil.isArray(value) ? 1 + value.length : -1; | ||
} | ||
// reflow? | ||
if (reflow) { | ||
pulse.mod = rem.length || remp.length | ||
? tuples.filter(function(t) { return out.hasOwnProperty(tupleid(t)); }) | ||
: tuples.slice(); | ||
} else { | ||
for (id$$1 in out) pulse.mod.push(out[id$$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.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 (vegaUtil.isArray(name)) { | ||
for (k=0; k<name.length; ++k) { | ||
if (mod[name[k]]) return true; | ||
} | ||
return pulse; | ||
return false; | ||
} | ||
return (index != null && index >= 0) | ||
? (index + 1 < mod[name] || !!mod[index + ':' + name]) | ||
: !!mod[name]; | ||
}; | ||
} | ||
var CACHE = '_:mod:_'; | ||
/** | ||
* Clears the modification records. After calling this method, | ||
* all parameters are considered unmodified. | ||
*/ | ||
prototype.clear = function() { | ||
this[CACHE] = {}; | ||
return this; | ||
}; | ||
/** | ||
* Hash that tracks modifications to assigned values. | ||
* Callers *must* use the set method to update values. | ||
*/ | ||
function Parameters() { | ||
Object.defineProperty(this, CACHE, {writable:true, value: {}}); | ||
} | ||
var OP_ID = 0; | ||
var PULSE = 'pulse'; | ||
var NO_PARAMS = new Parameters(); | ||
var prototype$2 = Parameters.prototype; | ||
// Boolean Flags | ||
var SKIP = 1, | ||
MODIFIED = 2; | ||
/** | ||
* Set a parameter value. If the parameter value changes, the parameter | ||
* will be recorded as modified. | ||
* @param {string} name - The parameter name. | ||
* @param {number} index - The index into an array-value parameter. Ignored if | ||
* the argument is undefined, null or less than zero. | ||
* @param {*} value - The parameter value to set. | ||
* @param {boolean} [force=false] - If true, records the parameter as modified | ||
* even if the value is unchanged. | ||
* @return {Parameters} - This parameter object. | ||
*/ | ||
prototype$2.set = function(name, index, value, force) { | ||
var o = this, | ||
v = o[name], | ||
mod = o[CACHE]; | ||
/** | ||
* 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 (index != null && index >= 0) { | ||
if (v[index] !== value || force) { | ||
v[index] = value; | ||
mod[index + ':' + name] = -1; | ||
mod[name] = -1; | ||
if (update) { | ||
this._update = update; | ||
} | ||
} else if (v !== value || force) { | ||
o[name] = value; | ||
mod[name] = vegaUtil.isArray(value) ? 1 + value.length : -1; | ||
if (params) this.parameters(params, react); | ||
} | ||
return o; | ||
}; | ||
var prototype$1 = Operator.prototype; | ||
/** | ||
* 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 (vegaUtil.isArray(name)) { | ||
for (k=0; k<name.length; ++k) { | ||
if (mod[name[k]]) return true; | ||
/** | ||
* 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(vegaUtil.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; | ||
} | ||
return false; | ||
}; | ||
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; | ||
}; | ||
} | ||
return (index != null && index >= 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; | ||
}; | ||
/** | ||
* 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); | ||
var OP_ID = 0; | ||
var PULSE = 'pulse'; | ||
var NO_PARAMS = new Parameters(); | ||
/** | ||
* 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); | ||
// Boolean Flags | ||
var SKIP = 1; | ||
var MODIFIED = 2; | ||
/** | ||
* 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; | ||
/** | ||
* 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; | ||
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); | ||
} | ||
} | ||
if (update) { | ||
this._update = update; | ||
} | ||
if (params) this.parameters(params, react); | ||
} | ||
for (name in params) { | ||
value = params[name]; | ||
var prototype$1 = Operator.prototype; | ||
if (name === PULSE) { | ||
vegaUtil.array(value).forEach(function(op) { | ||
if (!(op instanceof Operator)) { | ||
vegaUtil.error('Pulse parameters must be operator instances.'); | ||
} else if (op !== self) { | ||
op.targets().add(self); | ||
deps.push(op); | ||
} | ||
}); | ||
self.source = value; | ||
} else if (vegaUtil.isArray(value)) { | ||
argval.set(name, -1, Array(n = value.length)); | ||
for (i=0; i<n; ++i) add(name, i, value[i]); | ||
} else { | ||
add(name, -1, value); | ||
} | ||
} | ||
/** | ||
* 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(vegaUtil.id)); | ||
}; | ||
this.marshall().clear(); // initialize values | ||
return deps; | ||
}; | ||
/** | ||
* 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; | ||
} | ||
}; | ||
/** | ||
* Internal method for marshalling parameter values. | ||
* Visits each operator dependency to pull the latest value. | ||
* @return {Parameters} A Parameters object to pass to the update function. | ||
*/ | ||
prototype$1.marshall = function(stamp) { | ||
var argval = this._argval || NO_PARAMS, | ||
argops = this._argops, item, i, n, op, mod; | ||
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; | ||
if (argops && (n = argops.length)) { | ||
for (i=0; i<n; ++i) { | ||
item = argops[i]; | ||
op = item.op; | ||
mod = op.modified() && op.stamp === stamp; | ||
argval.set(item.name, item.index, op.value, mod); | ||
} | ||
} | ||
return argval; | ||
}; | ||
} | ||
/** | ||
* 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); | ||
/** | ||
* Delegate method to perform operator processing. | ||
* Subclasses can override this method to perform custom processing. | ||
* By default, it marshalls parameters and calls the update function | ||
* if that function is defined. If the update function does not | ||
* change the operator value then StopPropagation is returned. | ||
* If no update function is defined, this method does nothing. | ||
* @param {Pulse} pulse - the current dataflow pulse. | ||
* @return The output pulse or StopPropagation. A falsy return value | ||
* (including undefined) will let the input pulse pass through. | ||
*/ | ||
prototype$1.evaluate = function(pulse) { | ||
if (this._update) { | ||
var params = this.marshall(pulse.stamp), | ||
v = this._update(params, pulse); | ||
/** | ||
* 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); | ||
params.clear(); | ||
if (v !== this.value) { | ||
this.value = v; | ||
} else if (!this.modified()) { | ||
return pulse.StopPropagation; | ||
} | ||
} | ||
}; | ||
/** | ||
* 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}); | ||
/** | ||
* Run this operator for the current pulse. If this operator has already | ||
* been run at (or after) the pulse timestamp, returns StopPropagation. | ||
* 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$1.run = function(pulse) { | ||
if (pulse.stamp <= this.stamp) return pulse.StopPropagation; | ||
var rv; | ||
if (this.skip()) { | ||
this.skip(false); | ||
rv = 0; | ||
} else { | ||
argval.set(name, index, value); | ||
rv = this.evaluate(pulse); | ||
} | ||
} | ||
this.stamp = pulse.stamp; | ||
this.pulse = rv; | ||
return rv || pulse; | ||
}; | ||
for (name in params) { | ||
value = params[name]; | ||
/** | ||
* Add an operator to the dataflow graph. This function accepts a | ||
* variety of input argument types. The basic signature supports an | ||
* initial value, update function and parameters. If the first parameter | ||
* is an Operator instance, it will be added directly. If it is a | ||
* constructor for an Operator subclass, a new instance will be instantiated. | ||
* Otherwise, if the first parameter is a function instance, it will be used | ||
* as the update function and a null initial value is assumed. | ||
* @param {*} init - One of: the operator to add, the initial value of | ||
* the operator, an operator class to instantiate, or an update function. | ||
* @param {function} [update] - The operator update function. | ||
* @param {object} [params] - The operator parameters. | ||
* @param {boolean} [react=true] - Flag indicating if this operator should | ||
* listen for changes to upstream operators included as parameters. | ||
* @return {Operator} - The added operator. | ||
*/ | ||
function add(init, update, params, react) { | ||
var shift = 1, | ||
op; | ||
if (name === PULSE) { | ||
vegaUtil.array(value).forEach(function(op) { | ||
if (!(op instanceof Operator)) { | ||
vegaUtil.error('Pulse parameters must be operator instances.'); | ||
} else if (op !== self) { | ||
op.targets().add(self); | ||
deps.push(op); | ||
} | ||
}); | ||
self.source = value; | ||
} else if (vegaUtil.isArray(value)) { | ||
argval.set(name, -1, Array(n = value.length)); | ||
for (i=0; i<n; ++i) add(name, i, value[i]); | ||
if (init instanceof Operator) { | ||
op = init; | ||
} else if (init && init.prototype instanceof Operator) { | ||
op = new init(); | ||
} else if (vegaUtil.isFunction(init)) { | ||
op = new Operator(null, init); | ||
} else { | ||
add(name, -1, value); | ||
shift = 0; | ||
op = new Operator(init, update); | ||
} | ||
} | ||
this.marshall().clear(); // initialize values | ||
return deps; | ||
}; | ||
this.rank(op); | ||
if (shift) { | ||
react = params; | ||
params = update; | ||
} | ||
if (params) this.connect(op, op.parameters(params, react)); | ||
this.touch(op); | ||
/** | ||
* Internal method for marshalling parameter values. | ||
* Visits each operator dependency to pull the latest value. | ||
* @return {Parameters} A Parameters object to pass to the update function. | ||
*/ | ||
prototype$1.marshall = function(stamp) { | ||
var argval = this._argval || NO_PARAMS, | ||
argops = this._argops, item, i, n, op, mod; | ||
if (argops && (n = argops.length)) { | ||
for (i=0; i<n; ++i) { | ||
item = argops[i]; | ||
op = item.op; | ||
mod = op.modified() && op.stamp === stamp; | ||
argval.set(item.name, item.index, op.value, mod); | ||
} | ||
return op; | ||
} | ||
return argval; | ||
}; | ||
/** | ||
* Delegate method to perform operator processing. | ||
* Subclasses can override this method to perform custom processing. | ||
* By default, it marshalls parameters and calls the update function | ||
* if that function is defined. If the update function does not | ||
* change the operator value then StopPropagation is returned. | ||
* If no update function is defined, this method does nothing. | ||
* @param {Pulse} pulse - the current dataflow pulse. | ||
* @return The output pulse or StopPropagation. A falsy return value | ||
* (including undefined) will let the input pulse pass through. | ||
*/ | ||
prototype$1.evaluate = function(pulse) { | ||
if (this._update) { | ||
var params = this.marshall(pulse.stamp), | ||
v = this._update(params, pulse); | ||
/** | ||
* Connect a target operator as a dependent of source operators. | ||
* If necessary, this method will rerank the target operator and its | ||
* dependents to ensure propagation proceeds in a topologically sorted order. | ||
* @param {Operator} target - The target operator. | ||
* @param {Array<Operator>} - The source operators that should propagate | ||
* to the target operator. | ||
*/ | ||
function connect(target, sources) { | ||
var targetRank = target.rank, i, n; | ||
params.clear(); | ||
if (v !== this.value) { | ||
this.value = v; | ||
} else if (!this.modified()) { | ||
return pulse.StopPropagation; | ||
for (i=0, n=sources.length; i<n; ++i) { | ||
if (targetRank < sources[i].rank) { | ||
this.rerank(target); | ||
return; | ||
} | ||
} | ||
} | ||
}; | ||
/** | ||
* Run this operator for the current pulse. If this operator has already | ||
* been run at (or after) the pulse timestamp, returns StopPropagation. | ||
* 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$1.run = function(pulse) { | ||
if (pulse.stamp <= this.stamp) return pulse.StopPropagation; | ||
var rv; | ||
if (this.skip()) { | ||
this.skip(false); | ||
rv = 0; | ||
} else { | ||
rv = this.evaluate(pulse); | ||
} | ||
this.stamp = pulse.stamp; | ||
this.pulse = rv; | ||
return rv || pulse; | ||
}; | ||
var STREAM_ID = 0; | ||
/** | ||
* Add an operator to the dataflow graph. This function accepts a | ||
* variety of input argument types. The basic signature supports an | ||
* initial value, update function and parameters. If the first parameter | ||
* is an Operator instance, it will be added directly. If it is a | ||
* constructor for an Operator subclass, a new instance will be instantiated. | ||
* Otherwise, if the first parameter is a function instance, it will be used | ||
* as the update function and a null initial value is assumed. | ||
* @param {*} init - One of: the operator to add, the initial value of | ||
* the operator, an operator class to instantiate, or an update function. | ||
* @param {function} [update] - The operator update function. | ||
* @param {object} [params] - The operator parameters. | ||
* @param {boolean} [react=true] - Flag indicating if this operator should | ||
* listen for changes to upstream operators included as parameters. | ||
* @return {Operator} - The added operator. | ||
*/ | ||
var add = function(init, update, params, react) { | ||
var shift = 1, | ||
op; | ||
if (init instanceof Operator) { | ||
op = init; | ||
} else if (init && init.prototype instanceof Operator) { | ||
op = new init(); | ||
} else if (vegaUtil.isFunction(init)) { | ||
op = new Operator(null, init); | ||
} else { | ||
shift = 0; | ||
op = new Operator(init, update); | ||
/** | ||
* Models an event stream. | ||
* @constructor | ||
* @param {function(Object, number): boolean} [filter] - Filter predicate. | ||
* Events pass through when truthy, events are suppressed when falsy. | ||
* @param {function(Object): *} [apply] - Applied to input events to produce | ||
* new event values. | ||
* @param {function(Object)} [receive] - Event callback function to invoke | ||
* upon receipt of a new event. Use to override standard event processing. | ||
*/ | ||
function EventStream(filter, apply, receive) { | ||
this.id = ++STREAM_ID; | ||
this.value = null; | ||
if (receive) this.receive = receive; | ||
if (filter) this._filter = filter; | ||
if (apply) this._apply = apply; | ||
} | ||
this.rank(op); | ||
if (shift) { | ||
react = params; | ||
params = update; | ||
/** | ||
* Creates a new event stream instance with the provided | ||
* (optional) filter, apply and receive functions. | ||
* @param {function(Object, number): boolean} [filter] - Filter predicate. | ||
* Events pass through when truthy, events are suppressed when falsy. | ||
* @param {function(Object): *} [apply] - Applied to input events to produce | ||
* new event values. | ||
* @see EventStream | ||
*/ | ||
function stream(filter, apply, receive) { | ||
return new EventStream(filter, apply, receive); | ||
} | ||
if (params) this.connect(op, op.parameters(params, react)); | ||
this.touch(op); | ||
return op; | ||
}; | ||
var prototype$2 = EventStream.prototype; | ||
/** | ||
* Connect a target operator as a dependent of source operators. | ||
* If necessary, this method will rerank the target operator and its | ||
* dependents to ensure propagation proceeds in a topologically sorted order. | ||
* @param {Operator} target - The target operator. | ||
* @param {Array<Operator>} - The source operators that should propagate | ||
* to the target operator. | ||
*/ | ||
var connect = function(target, sources) { | ||
var targetRank = target.rank, i, n; | ||
prototype$2._filter = vegaUtil.truthy; | ||
for (i=0, n=sources.length; i<n; ++i) { | ||
if (targetRank < sources[i].rank) { | ||
this.rerank(target); | ||
return; | ||
} | ||
} | ||
}; | ||
prototype$2._apply = vegaUtil.identity; | ||
var STREAM_ID = 0; | ||
prototype$2.targets = function() { | ||
return this._targets || (this._targets = UniqueList(vegaUtil.id)); | ||
}; | ||
/** | ||
* Models an event stream. | ||
* @constructor | ||
* @param {function(Object, number): boolean} [filter] - Filter predicate. | ||
* Events pass through when truthy, events are suppressed when falsy. | ||
* @param {function(Object): *} [apply] - Applied to input events to produce | ||
* new event values. | ||
* @param {function(Object)} [receive] - Event callback function to invoke | ||
* upon receipt of a new event. Use to override standard event processing. | ||
*/ | ||
function EventStream(filter, apply, receive) { | ||
this.id = ++STREAM_ID; | ||
this.value = null; | ||
if (receive) this.receive = receive; | ||
if (filter) this._filter = filter; | ||
if (apply) this._apply = apply; | ||
} | ||
prototype$2.consume = function(_) { | ||
if (!arguments.length) return !!this._consume; | ||
this._consume = !!_; | ||
return this; | ||
}; | ||
/** | ||
* Creates a new event stream instance with the provided | ||
* (optional) filter, apply and receive functions. | ||
* @param {function(Object, number): boolean} [filter] - Filter predicate. | ||
* Events pass through when truthy, events are suppressed when falsy. | ||
* @param {function(Object): *} [apply] - Applied to input events to produce | ||
* new event values. | ||
* @see EventStream | ||
*/ | ||
function stream(filter, apply, receive) { | ||
return new EventStream(filter, apply, receive); | ||
} | ||
prototype$2.receive = function(evt) { | ||
if (this._filter(evt)) { | ||
var val = (this.value = this._apply(evt)), | ||
trg = this._targets, | ||
n = trg ? trg.length : 0, | ||
i = 0; | ||
var prototype$3 = EventStream.prototype; | ||
for (; i<n; ++i) trg[i].receive(val); | ||
prototype$3._filter = vegaUtil.truthy; | ||
if (this._consume) { | ||
evt.preventDefault(); | ||
evt.stopPropagation(); | ||
} | ||
} | ||
}; | ||
prototype$3._apply = vegaUtil.identity; | ||
prototype$2.filter = function(filter) { | ||
var s = stream(filter); | ||
this.targets().add(s); | ||
return s; | ||
}; | ||
prototype$3.targets = function() { | ||
return this._targets || (this._targets = UniqueList(vegaUtil.id)); | ||
}; | ||
prototype$2.apply = function(apply) { | ||
var s = stream(null, apply); | ||
this.targets().add(s); | ||
return s; | ||
}; | ||
prototype$3.consume = function(_) { | ||
if (!arguments.length) return !!this._consume; | ||
this._consume = !!_; | ||
return this; | ||
}; | ||
prototype$2.merge = function() { | ||
var s = stream(); | ||
prototype$3.receive = function(evt) { | ||
if (this._filter(evt)) { | ||
var val = (this.value = this._apply(evt)), | ||
trg = this._targets, | ||
n = trg ? trg.length : 0, | ||
i = 0; | ||
this.targets().add(s); | ||
for (var i=0, n=arguments.length; i<n; ++i) { | ||
arguments[i].targets().add(s); | ||
} | ||
for (; i<n; ++i) trg[i].receive(val); | ||
return s; | ||
}; | ||
if (this._consume) { | ||
evt.preventDefault(); | ||
evt.stopPropagation(); | ||
} | ||
} | ||
}; | ||
prototype$2.throttle = function(pause) { | ||
var t = -1; | ||
return this.filter(function() { | ||
var now = Date.now(); | ||
if ((now - t) > pause) { | ||
t = now; | ||
return 1; | ||
} else { | ||
return 0; | ||
} | ||
}); | ||
}; | ||
prototype$3.filter = function(filter) { | ||
var s = stream(filter); | ||
this.targets().add(s); | ||
return s; | ||
}; | ||
prototype$2.debounce = function(delay) { | ||
var s = stream(); | ||
prototype$3.apply = function(apply) { | ||
var s = stream(null, apply); | ||
this.targets().add(s); | ||
return s; | ||
}; | ||
this.targets().add(stream(null, null, | ||
vegaUtil.debounce(delay, function(e) { | ||
var df = e.dataflow; | ||
s.receive(e); | ||
if (df && df.run) df.run(); | ||
}) | ||
)); | ||
prototype$3.merge = function() { | ||
var s = stream(); | ||
return s; | ||
}; | ||
this.targets().add(s); | ||
for (var i=0, n=arguments.length; i<n; ++i) { | ||
arguments[i].targets().add(s); | ||
} | ||
prototype$2.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; }); | ||
}; | ||
return s; | ||
}; | ||
/** | ||
* 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} | ||
*/ | ||
function events(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; | ||
prototype$3.throttle = function(pause) { | ||
var t = -1; | ||
return this.filter(function() { | ||
var now = Date.now(); | ||
if ((now - t) > pause) { | ||
t = now; | ||
return 1; | ||
if (typeof source === 'string' && typeof document !== 'undefined') { | ||
sources = document.querySelectorAll(source); | ||
} else { | ||
return 0; | ||
sources = vegaUtil.array(source); | ||
} | ||
}); | ||
}; | ||
prototype$3.debounce = function(delay) { | ||
var s = stream(); | ||
for (var i=0, n=sources.length; i<n; ++i) { | ||
sources[i].addEventListener(type, send); | ||
} | ||
this.targets().add(stream(null, null, | ||
vegaUtil.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 = vegaUtil.array(source); | ||
return s; | ||
} | ||
for (var i=0, n=sources.length; i<n; ++i) { | ||
sources[i].addEventListener(type, send); | ||
function ingest$1(target, data, format) { | ||
return this.pulse(target, this.changeset().insert(vegaLoader.read(data, format))); | ||
} | ||
return s; | ||
}; | ||
function loadPending(df) { | ||
var accept, reject, | ||
pending = new Promise(function(a, r) { | ||
accept = a; | ||
reject = r; | ||
}); | ||
function ingest$1(target, data, format) { | ||
return this.pulse(target, this.changeset().insert(vegaLoader.read(data, format))); | ||
} | ||
pending.requests = 0; | ||
function loadPending(df) { | ||
var accept, reject, | ||
pending = new Promise(function(a, r) { | ||
accept = a; | ||
reject = r; | ||
}); | ||
pending.done = function() { | ||
if (--pending.requests === 0) { | ||
df.runAfter(function() { | ||
df._pending = null; | ||
try { | ||
df.run(); | ||
accept(df); | ||
} catch (err) { | ||
reject(err); | ||
} | ||
}); | ||
} | ||
}; | ||
pending.requests = 0; | ||
return (df._pending = pending); | ||
} | ||
pending.done = function() { | ||
if (--pending.requests === 0) { | ||
df.runAfter(function() { | ||
df._pending = null; | ||
try { | ||
df.run(); | ||
accept(df); | ||
} catch (err) { | ||
reject(err); | ||
} | ||
}); | ||
} | ||
}; | ||
function request(target, url, format) { | ||
var df = this, | ||
pending = df._pending || loadPending(df); | ||
return (df._pending = pending); | ||
} | ||
pending.requests += 1; | ||
function request(target, url, format) { | ||
var df = this, | ||
pending = df._pending || loadPending(df); | ||
df.loader() | ||
.load(url, {context:'dataflow'}) | ||
.then( | ||
function(data) { df.ingest(target, data, format); }, | ||
function(error) { df.error('Loading failed', url, error); }) | ||
.catch( | ||
function(error) { df.error('Data ingestion failed', url, error); }) | ||
.then(pending.done, pending.done); | ||
} | ||
pending.requests += 1; | ||
var SKIP$1 = {skip: true}; | ||
df.loader() | ||
.load(url, {context:'dataflow'}) | ||
.then( | ||
function(data) { df.ingest(target, data, format); }, | ||
function(error) { df.error('Loading failed', url, error); }) | ||
.catch( | ||
function(error) { df.error('Data ingestion failed', url, error); }) | ||
.then(pending.done, pending.done); | ||
} | ||
/** | ||
* Perform operator updates in response to events. Applies an | ||
* update function to compute a new operator value. If the update function | ||
* returns a {@link ChangeSet}, the operator will be pulsed with those tuple | ||
* changes. Otherwise, the operator value will be updated to the return value. | ||
* @param {EventStream|Operator} source - The event source to react to. | ||
* This argument can be either an EventStream or an Operator. | ||
* @param {Operator|function(object):Operator} target - The operator to update. | ||
* This argument can either be an Operator instance or (if the source | ||
* argument is an EventStream), a function that accepts an event object as | ||
* input and returns an Operator to target. | ||
* @param {function(Parameters,Event): *} [update] - Optional update function | ||
* to compute the new operator value, or a literal value to set. Update | ||
* functions expect to receive a parameter object and event as arguments. | ||
* This function can either return a new operator value or (if the source | ||
* argument is an EventStream) a {@link ChangeSet} instance to pulse | ||
* the target operator with tuple changes. | ||
* @param {object} [params] - The update function parameters. | ||
* @param {object} [options] - Additional options hash. If not overridden, | ||
* updated operators will be skipped by default. | ||
* @param {boolean} [options.skip] - If true, the operator will | ||
* be skipped: it will not be evaluated, but its dependents will be. | ||
* @param {boolean} [options.force] - If true, the operator will | ||
* be re-evaluated even if its value has not changed. | ||
* @return {Dataflow} | ||
*/ | ||
function on(source, target, update, params, options) { | ||
var fn = source instanceof Operator ? onOperator : onStream; | ||
fn(this, source, target, update, params, options); | ||
return this; | ||
} | ||
var SKIP$1 = {skip: true}; | ||
function onStream(df, stream, target, update, params, options) { | ||
var opt = vegaUtil.extend({}, options, SKIP$1), func, op; | ||
/** | ||
* Perform operator updates in response to events. Applies an | ||
* update function to compute a new operator value. If the update function | ||
* returns a {@link ChangeSet}, the operator will be pulsed with those tuple | ||
* changes. Otherwise, the operator value will be updated to the return value. | ||
* @param {EventStream|Operator} source - The event source to react to. | ||
* This argument can be either an EventStream or an Operator. | ||
* @param {Operator|function(object):Operator} target - The operator to update. | ||
* This argument can either be an Operator instance or (if the source | ||
* argument is an EventStream), a function that accepts an event object as | ||
* input and returns an Operator to target. | ||
* @param {function(Parameters,Event): *} [update] - Optional update function | ||
* to compute the new operator value, or a literal value to set. Update | ||
* functions expect to receive a parameter object and event as arguments. | ||
* This function can either return a new operator value or (if the source | ||
* argument is an EventStream) a {@link ChangeSet} instance to pulse | ||
* the target operator with tuple changes. | ||
* @param {object} [params] - The update function parameters. | ||
* @param {object} [options] - Additional options hash. If not overridden, | ||
* updated operators will be skipped by default. | ||
* @param {boolean} [options.skip] - If true, the operator will | ||
* be skipped: it will not be evaluated, but its dependents will be. | ||
* @param {boolean} [options.force] - If true, the operator will | ||
* be re-evaluated even if its value has not changed. | ||
* @return {Dataflow} | ||
*/ | ||
var on = function(source, target, update, params, options) { | ||
var fn = source instanceof Operator ? onOperator : onStream; | ||
fn(this, source, target, update, params, options); | ||
return this; | ||
}; | ||
if (!vegaUtil.isFunction(target)) target = vegaUtil.constant(target); | ||
function onStream(df, stream, target, update, params, options) { | ||
var opt = vegaUtil.extend({}, options, SKIP$1), func, op; | ||
if (update === undefined) { | ||
func = function(e) { | ||
df.touch(target(e)); | ||
}; | ||
} else if (vegaUtil.isFunction(update)) { | ||
op = new Operator(null, update, params, false); | ||
func = function(e) { | ||
var v, t = target(e); | ||
op.evaluate(e); | ||
isChangeSet(v = op.value) ? df.pulse(t, v, options) : df.update(t, v, opt); | ||
}; | ||
} else { | ||
func = function(e) { | ||
df.update(target(e), update, opt); | ||
}; | ||
} | ||
if (!vegaUtil.isFunction(target)) target = vegaUtil.constant(target); | ||
if (update === undefined) { | ||
func = function(e) { | ||
df.touch(target(e)); | ||
}; | ||
} else if (vegaUtil.isFunction(update)) { | ||
op = new Operator(null, update, params, false); | ||
func = function(e) { | ||
var v, t = target(e); | ||
op.evaluate(e); | ||
isChangeSet(v = op.value) ? df.pulse(t, v, options) : df.update(t, v, opt); | ||
}; | ||
} else { | ||
func = function(e) { | ||
df.update(target(e), update, opt); | ||
}; | ||
stream.apply(func); | ||
} | ||
stream.apply(func); | ||
} | ||
function onOperator(df, source, target, update, params, options) { | ||
var func, op; | ||
function onOperator(df, source, target, update, params, options) { | ||
var func, op; | ||
if (update === undefined) { | ||
op = target; | ||
} else { | ||
func = vegaUtil.isFunction(update) ? update : vegaUtil.constant(update); | ||
update = !target ? func : function(_, pulse) { | ||
var value = func(_, pulse); | ||
return target.skip() | ||
? value | ||
: (target.skip(true).value = value); | ||
}; | ||
if (update === undefined) { | ||
op = target; | ||
} else { | ||
func = vegaUtil.isFunction(update) ? update : vegaUtil.constant(update); | ||
update = !target ? func : function(_, pulse) { | ||
var value = func(_, pulse); | ||
return target.skip() | ||
? value | ||
: (target.skip(true).value = value); | ||
}; | ||
op = new Operator(null, update, params, false); | ||
op.modified(options && options.force); | ||
op.rank = 0; | ||
op = new Operator(null, update, params, false); | ||
op.modified(options && options.force); | ||
op.rank = 0; | ||
if (target) { | ||
op.skip(true); // skip first invocation | ||
op.value = target.value; | ||
op.targets().add(target); | ||
} | ||
} | ||
if (target) { | ||
op.skip(true); // skip first invocation | ||
op.value = target.value; | ||
op.targets().add(target); | ||
} | ||
source.targets().add(op); | ||
} | ||
source.targets().add(op); | ||
} | ||
/** | ||
* Assigns a rank to an operator. Ranks are assigned in increasing order | ||
* by incrementing an internal rank counter. | ||
* @param {Operator} op - The operator to assign a rank. | ||
*/ | ||
function rank(op) { | ||
op.rank = ++this._rank; | ||
} | ||
/** | ||
* Assigns a rank to an operator. Ranks are assigned in increasing order | ||
* by incrementing an internal rank counter. | ||
* @param {Operator} op - The operator to assign a rank. | ||
*/ | ||
function rank(op) { | ||
op.rank = ++this._rank; | ||
} | ||
/** | ||
* Re-ranks an operator and all downstream target dependencies. This | ||
* is necessary when upstream depencies of higher rank are added to | ||
* a target operator. | ||
* @param {Operator} op - The operator to re-rank. | ||
*/ | ||
function rerank(op) { | ||
var queue = [op], | ||
cur, list, i; | ||
/** | ||
* Re-ranks an operator and all downstream target dependencies. This | ||
* is necessary when upstream depencies of higher rank are added to | ||
* a target operator. | ||
* @param {Operator} op - The operator to re-rank. | ||
*/ | ||
function rerank(op) { | ||
var queue = [op], | ||
cur, list, i; | ||
while (queue.length) { | ||
this.rank(cur = queue.pop()); | ||
if (list = cur._targets) { | ||
for (i=list.length; --i >= 0;) { | ||
queue.push(cur = list[i]); | ||
if (cur === op) vegaUtil.error('Cycle detected in dataflow graph.'); | ||
while (queue.length) { | ||
this.rank(cur = queue.pop()); | ||
if (list = cur._targets) { | ||
for (i=list.length; --i >= 0;) { | ||
queue.push(cur = list[i]); | ||
if (cur === op) vegaUtil.error('Cycle detected in dataflow graph.'); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
/** | ||
* Sentinel value indicating pulse propagation should stop. | ||
*/ | ||
var StopPropagation = {}; | ||
/** | ||
* 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); | ||
// Pulse visit type flags | ||
var ADD = (1 << 0), | ||
REM = (1 << 1), | ||
MOD = (1 << 2), | ||
ADD_REM = ADD | REM, | ||
ADD_MOD = ADD | MOD, | ||
ALL = ADD | REM | MOD, | ||
REFLOW = (1 << 3), | ||
SOURCE = (1 << 4), | ||
NO_SOURCE = (1 << 5), | ||
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; | ||
} | ||
/** | ||
* 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; | ||
var prototype$3 = Pulse.prototype; | ||
/** | ||
* Sentinel value indicating pulse propagation should stop. | ||
*/ | ||
prototype$4.StopPropagation = StopPropagation; | ||
/** | ||
* Sentinel value indicating pulse propagation should stop. | ||
*/ | ||
prototype$3.StopPropagation = StopPropagation; | ||
/** | ||
* Boolean flag indicating ADD (added) tuples. | ||
*/ | ||
prototype$4.ADD = ADD; | ||
/** | ||
* Boolean flag indicating ADD (added) tuples. | ||
*/ | ||
prototype$3.ADD = ADD; | ||
/** | ||
* Boolean flag indicating REM (removed) tuples. | ||
*/ | ||
prototype$4.REM = REM; | ||
/** | ||
* Boolean flag indicating REM (removed) tuples. | ||
*/ | ||
prototype$3.REM = REM; | ||
/** | ||
* Boolean flag indicating MOD (modified) tuples. | ||
*/ | ||
prototype$4.MOD = MOD; | ||
/** | ||
* Boolean flag indicating MOD (modified) tuples. | ||
*/ | ||
prototype$3.MOD = MOD; | ||
/** | ||
* Boolean flag indicating ADD (added) and REM (removed) tuples. | ||
*/ | ||
prototype$4.ADD_REM = ADD_REM; | ||
/** | ||
* Boolean flag indicating ADD (added) and REM (removed) tuples. | ||
*/ | ||
prototype$3.ADD_REM = ADD_REM; | ||
/** | ||
* Boolean flag indicating ADD (added) and MOD (modified) tuples. | ||
*/ | ||
prototype$4.ADD_MOD = ADD_MOD; | ||
/** | ||
* Boolean flag indicating ADD (added) and MOD (modified) tuples. | ||
*/ | ||
prototype$3.ADD_MOD = ADD_MOD; | ||
/** | ||
* Boolean flag indicating ADD, REM and MOD tuples. | ||
*/ | ||
prototype$4.ALL = ALL; | ||
/** | ||
* Boolean flag indicating ADD, REM and MOD tuples. | ||
*/ | ||
prototype$3.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 all tuples in a data source | ||
* except for the ADD, REM and MOD tuples. | ||
*/ | ||
prototype$3.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 a 'pass-through' to a | ||
* backing data source, ignoring ADD, REM and MOD tuples. | ||
*/ | ||
prototype$3.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 source data should be | ||
* suppressed when creating a forked pulse. | ||
*/ | ||
prototype$3.NO_SOURCE = NO_SOURCE; | ||
/** | ||
* Boolean flag indicating that field modifications should be | ||
* suppressed when creating a forked pulse. | ||
*/ | ||
prototype$4.NO_FIELDS = NO_FIELDS; | ||
/** | ||
* Boolean flag indicating that field modifications should be | ||
* suppressed when creating a forked pulse. | ||
*/ | ||
prototype$3.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); | ||
}; | ||
/** | ||
* 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$3.fork = function(flags) { | ||
return new Pulse(this.dataflow).init(this, flags); | ||
}; | ||
/** | ||
* Creates a copy of this pulse with new materialized array | ||
* instances for the ADD, REM, MOD, and SOURCE arrays. | ||
* The dataflow, time stamp and field modification values are copied over. | ||
* @return {Pulse} - The cloned pulse instance. | ||
* @see init | ||
*/ | ||
prototype$4.clone = function() { | ||
var p = this.fork(ALL); | ||
p.add = p.add.slice(); | ||
p.rem = p.rem.slice(); | ||
p.mod = p.mod.slice(); | ||
if (p.source) p.source = p.source.slice(); | ||
return p.materialize(ALL | SOURCE); | ||
}; | ||
/** | ||
* Creates a copy of this pulse with new materialized array | ||
* instances for the ADD, REM, MOD, and SOURCE arrays. | ||
* The dataflow, time stamp and field modification values are copied over. | ||
* @return {Pulse} - The cloned pulse instance. | ||
* @see init | ||
*/ | ||
prototype$3.clone = function() { | ||
var p = this.fork(ALL); | ||
p.add = p.add.slice(); | ||
p.rem = p.rem.slice(); | ||
p.mod = p.mod.slice(); | ||
if (p.source) p.source = p.source.slice(); | ||
return p.materialize(ALL | SOURCE); | ||
}; | ||
/** | ||
* 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; | ||
} | ||
}; | ||
/** | ||
* 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$3.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; | ||
/** | ||
* 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$3.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 (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 & 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 & 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 & 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; | ||
} | ||
if (flags & NO_SOURCE) { | ||
p.srcF = null; | ||
p.source = null; | ||
} else { | ||
p.srcF = src.srcF; | ||
p.source = src.source; | ||
} | ||
return p; | ||
}; | ||
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); | ||
}; | ||
/** | ||
* Schedules a function to run after pulse propagation completes. | ||
* @param {function} func - The function to run. | ||
*/ | ||
prototype$3.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); | ||
}; | ||
/** | ||
* 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$3.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(); | ||
/** | ||
* 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$3.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; | ||
}; | ||
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<string>} _ - The field(s) to mark as modified. | ||
* @return {Pulse} - This pulse instance. | ||
*/ | ||
prototype$4.modifies = function(_) { | ||
var fields = vegaUtil.array(_), | ||
hash = this.fields || (this.fields = {}); | ||
fields.forEach(function(f) { hash[f] = true; }); | ||
return this; | ||
}; | ||
/** | ||
* Marks one or more data field names as modified to assist dependency | ||
* tracking and incremental processing by transform operators. | ||
* @param {string|Array<string>} _ - The field(s) to mark as modified. | ||
* @return {Pulse} - This pulse instance. | ||
*/ | ||
prototype$3.modifies = function(_) { | ||
var fields = vegaUtil.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<string>} _ - 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 | ||
: vegaUtil.isArray(_) ? _.some(function(f) { return fields[f]; }) | ||
: fields[_]; | ||
}; | ||
/** | ||
* Checks if one or more data fields have been modified during this pulse | ||
* propagation timestamp. | ||
* @param {string|Array<string>} _ - 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$3.modified = function(_) { | ||
var fields = this.fields; | ||
return !(this.mod.length && fields) ? false | ||
: !arguments.length ? !!fields | ||
: vegaUtil.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; | ||
}; | ||
/** | ||
* 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$3.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; | ||
} | ||
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; | ||
/** | ||
* 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$3.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 = []; | ||
vegaUtil.visitArray(data, filter, function(_) { out.push(_); }); | ||
return out; | ||
} | ||
if ((flags & REM) && p.remF) { | ||
p.rem = materialize(p.rem, p.remF); | ||
p.remF = null; | ||
function filter(pulse, flags) { | ||
var map = {}; | ||
pulse.visit(flags, function(t) { map[tupleid(t)] = 1; }); | ||
return function(t) { return map[tupleid(t)] ? null : t; }; | ||
} | ||
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 = []; | ||
vegaUtil.visitArray(data, filter, function(_) { out.push(_); }); | ||
return out; | ||
} | ||
/** | ||
* 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$3.visit = function(flags, visitor) { | ||
var p = this, v = visitor, src, sum; | ||
function filter(pulse, flags) { | ||
var map = {}; | ||
pulse.visit(flags, function(t) { map[tupleid(t)] = 1; }); | ||
return function(t) { return map[tupleid(t)] ? null : t; }; | ||
} | ||
if (flags & SOURCE) { | ||
vegaUtil.visitArray(p.source, p.srcF, v); | ||
return p; | ||
} | ||
/** | ||
* 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 & ADD) vegaUtil.visitArray(p.add, p.addF, v); | ||
if (flags & REM) vegaUtil.visitArray(p.rem, p.remF, v); | ||
if (flags & MOD) vegaUtil.visitArray(p.mod, p.modF, v); | ||
if (flags & SOURCE) { | ||
vegaUtil.visitArray(p.source, p.srcF, v); | ||
if ((flags & REFLOW) && (src = p.source)) { | ||
sum = p.add.length + p.mod.length; | ||
if (sum === src.length) ; else if (sum) { | ||
vegaUtil.visitArray(src, filter(p, ADD_MOD), v); | ||
} else { | ||
// if no add/rem/mod tuples, visit source | ||
vegaUtil.visitArray(src, p.srcF, v); | ||
} | ||
} | ||
return p; | ||
} | ||
}; | ||
if (flags & ADD) vegaUtil.visitArray(p.add, p.addF, v); | ||
if (flags & REM) vegaUtil.visitArray(p.rem, p.remF, v); | ||
if (flags & MOD) vegaUtil.visitArray(p.mod, p.modF, v); | ||
/** | ||
* 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<Pulse>} pulses - The sub-pulses for this multi-pulse. | ||
*/ | ||
function MultiPulse(dataflow, stamp, pulses, encode) { | ||
var p = this, | ||
c = 0, | ||
pulse, hash, i, n, f; | ||
if ((flags & REFLOW) && (src = p.source)) { | ||
sum = p.add.length + p.mod.length; | ||
if (sum === src.length) { | ||
// do nothing | ||
} else if (sum) { | ||
vegaUtil.visitArray(src, filter(p, ADD_MOD), v); | ||
} else { | ||
// if no add/rem/mod tuples, visit source | ||
vegaUtil.visitArray(src, p.srcF, v); | ||
} | ||
} | ||
this.dataflow = dataflow; | ||
this.stamp = stamp; | ||
this.fields = null; | ||
this.encode = encode || null; | ||
this.pulses = pulses; | ||
return p; | ||
}; | ||
for (i=0, n=pulses.length; i<n; ++i) { | ||
pulse = pulses[i]; | ||
if (pulse.stamp !== stamp) continue; | ||
/** | ||
* 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<Pulse>} pulses - The sub-pulses for this multi-pulse. | ||
*/ | ||
function MultiPulse(dataflow, stamp, pulses, encode) { | ||
var p = this, | ||
c = 0, | ||
pulse, hash, i, n, f; | ||
if (pulse.fields) { | ||
hash = p.fields || (p.fields = {}); | ||
for (f in pulse.fields) { hash[f] = 1; } | ||
} | ||
this.dataflow = dataflow; | ||
this.stamp = stamp; | ||
this.fields = null; | ||
this.encode = encode || null; | ||
this.pulses = pulses; | ||
for (i=0, n=pulses.length; i<n; ++i) { | ||
pulse = pulses[i]; | ||
if (pulse.stamp !== stamp) continue; | ||
if (pulse.fields) { | ||
hash = p.fields || (p.fields = {}); | ||
for (f in pulse.fields) { hash[f] = 1; } | ||
if (pulse.changed(p.ADD)) c |= p.ADD; | ||
if (pulse.changed(p.REM)) c |= p.REM; | ||
if (pulse.changed(p.MOD)) c |= p.MOD; | ||
} | ||
if (pulse.changed(p.ADD)) c |= p.ADD; | ||
if (pulse.changed(p.REM)) c |= p.REM; | ||
if (pulse.changed(p.MOD)) c |= p.MOD; | ||
this.changes = c; | ||
} | ||
this.changes = c; | ||
} | ||
var prototype$4 = vegaUtil.inherits(MultiPulse, Pulse); | ||
var prototype$5 = vegaUtil.inherits(MultiPulse, Pulse); | ||
/** | ||
* Creates a new pulse based on the values of this pulse. | ||
* The dataflow, time stamp and field modification values are copied over. | ||
* @return {Pulse} | ||
*/ | ||
prototype$5.fork = function(flags) { | ||
var p = new Pulse(this.dataflow).init(this, flags & this.NO_FIELDS); | ||
if (flags !== undefined) { | ||
if (flags & p.ADD) { | ||
this.visit(p.ADD, function(t) { return p.add.push(t); }); | ||
/** | ||
* Creates a new pulse based on the values of this pulse. | ||
* The dataflow, time stamp and field modification values are copied over. | ||
* @return {Pulse} | ||
*/ | ||
prototype$4.fork = function(flags) { | ||
var p = new Pulse(this.dataflow).init(this, flags & this.NO_FIELDS); | ||
if (flags !== undefined) { | ||
if (flags & p.ADD) { | ||
this.visit(p.ADD, function(t) { return p.add.push(t); }); | ||
} | ||
if (flags & p.REM) { | ||
this.visit(p.REM, function(t) { return p.rem.push(t); }); | ||
} | ||
if (flags & p.MOD) { | ||
this.visit(p.MOD, function(t) { return p.mod.push(t); }); | ||
} | ||
} | ||
if (flags & p.REM) { | ||
this.visit(p.REM, function(t) { return p.rem.push(t); }); | ||
} | ||
if (flags & p.MOD) { | ||
this.visit(p.MOD, function(t) { return p.mod.push(t); }); | ||
} | ||
} | ||
return p; | ||
}; | ||
return p; | ||
}; | ||
prototype$5.changed = function(flags) { | ||
return this.changes & flags; | ||
}; | ||
prototype$4.changed = function(flags) { | ||
return this.changes & flags; | ||
}; | ||
prototype$5.modified = function(_) { | ||
var p = this, fields = p.fields; | ||
return !(fields && (p.changes & p.MOD)) ? 0 | ||
: vegaUtil.isArray(_) ? _.some(function(f) { return fields[f]; }) | ||
: fields[_]; | ||
}; | ||
prototype$4.modified = function(_) { | ||
var p = this, fields = p.fields; | ||
return !(fields && (p.changes & p.MOD)) ? 0 | ||
: vegaUtil.isArray(_) ? _.some(function(f) { return fields[f]; }) | ||
: fields[_]; | ||
}; | ||
prototype$5.filter = function() { | ||
vegaUtil.error('MultiPulse does not support filtering.'); | ||
}; | ||
prototype$4.filter = function() { | ||
vegaUtil.error('MultiPulse does not support filtering.'); | ||
}; | ||
prototype$5.materialize = function() { | ||
vegaUtil.error('MultiPulse does not support materialization.'); | ||
}; | ||
prototype$4.materialize = function() { | ||
vegaUtil.error('MultiPulse does not support materialization.'); | ||
}; | ||
prototype$5.visit = function(flags, visitor) { | ||
var p = this, | ||
pulses = p.pulses, | ||
n = pulses.length, | ||
i = 0; | ||
prototype$4.visit = function(flags, visitor) { | ||
var p = this, | ||
pulses = p.pulses, | ||
n = pulses.length, | ||
i = 0; | ||
if (flags & p.SOURCE) { | ||
for (; i<n; ++i) { | ||
pulses[i].visit(flags, visitor); | ||
} | ||
} else { | ||
for (; i<n; ++i) { | ||
if (pulses[i].stamp === p.stamp) { | ||
if (flags & p.SOURCE) { | ||
for (; i<n; ++i) { | ||
pulses[i].visit(flags, visitor); | ||
} | ||
} else { | ||
for (; i<n; ++i) { | ||
if (pulses[i].stamp === p.stamp) { | ||
pulses[i].visit(flags, visitor); | ||
} | ||
} | ||
} | ||
} | ||
return p; | ||
}; | ||
return p; | ||
}; | ||
/** | ||
* Runs the dataflow. This method will increment the current timestamp | ||
* and process all updated, pulsed and touched operators. When run for | ||
* the first time, all registered operators will be processed. If there | ||
* are pending data loading operations, this method will return immediately | ||
* without evaluating the dataflow. Instead, the dataflow will be | ||
* asynchronously invoked when data loading completes. To track when dataflow | ||
* evaluation completes, use the {@link runAsync} method instead. | ||
* @param {string} [encode] - The name of an encoding set to invoke during | ||
* propagation. This value is added to generated Pulse instances; | ||
* operators can then 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 run(encode) { | ||
var df = this, | ||
count = 0, | ||
level = df.logLevel(), | ||
op, next, dt, error; | ||
/** | ||
* Runs the dataflow. This method will increment the current timestamp | ||
* and process all updated, pulsed and touched operators. When run for | ||
* the first time, all registered operators will be processed. If there | ||
* are pending data loading operations, this method will return immediately | ||
* without evaluating the dataflow. Instead, the dataflow will be | ||
* asynchronously invoked when data loading completes. To track when dataflow | ||
* evaluation completes, use the {@link runAsync} method instead. | ||
* @param {string} [encode] - The name of an encoding set to invoke during | ||
* propagation. This value is added to generated Pulse instances; | ||
* operators can then 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 run(encode) { | ||
var df = this, | ||
count = 0, | ||
level = df.logLevel(), | ||
op, next, dt, error; | ||
if (df._pending) { | ||
df.info('Awaiting requests, delaying dataflow run.'); | ||
return 0; | ||
} | ||
if (df._pending) { | ||
df.info('Awaiting requests, delaying dataflow run.'); | ||
return 0; | ||
} | ||
if (df._pulse) { | ||
df.error('Dataflow invoked recursively. Use the runAfter method to queue invocation.'); | ||
return 0; | ||
} | ||
if (df._pulse) { | ||
df.error('Dataflow invoked recursively. Use the runAfter method to queue invocation.'); | ||
return 0; | ||
} | ||
if (!df._touched.length) { | ||
df.info('Dataflow invoked, but nothing to do.'); | ||
return 0; | ||
} | ||
if (!df._touched.length) { | ||
df.info('Dataflow invoked, but nothing to do.'); | ||
return 0; | ||
} | ||
df._pulse = new Pulse(df, ++df._clock, encode); | ||
df._pulse = new Pulse(df, ++df._clock, encode); | ||
if (level >= vegaUtil.Info) { | ||
dt = Date.now(); | ||
df.debug('-- START PROPAGATION (' + df._clock + ') -----'); | ||
} | ||
if (level >= vegaUtil.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(vegaUtil.id); | ||
// initialize queue, reset touched operators | ||
df._touched.forEach(function(op) { df._enqueue(op, true); }); | ||
df._touched = UniqueList(vegaUtil.id); | ||
try { | ||
while (df._heap.size() > 0) { | ||
op = df._heap.pop(); | ||
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; } | ||
// 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)); | ||
// otherwise, evaluate the operator | ||
next = op.run(df._getPulse(op, encode)); | ||
if (level >= vegaUtil.Debug) { | ||
df.debug(op.id, next === StopPropagation ? 'STOP' : next, op); | ||
} | ||
if (level >= vegaUtil.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); }); | ||
// 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; | ||
} | ||
// increment visit counter | ||
++count; | ||
// reset pulse map | ||
df._pulses = {}; | ||
df._pulse = null; | ||
if (level >= vegaUtil.Info) { | ||
dt = Date.now() - dt; | ||
df.info('> Pulse ' + df._clock + ': ' + count + ' operators; ' + dt + 'ms'); | ||
} | ||
} catch (err) { | ||
error = err; | ||
} | ||
// reset pulse map | ||
df._pulses = {}; | ||
df._pulse = null; | ||
if (error) { | ||
df._postrun = []; | ||
df.error(error); | ||
} | ||
if (level >= vegaUtil.Info) { | ||
dt = Date.now() - dt; | ||
df.info('> Pulse ' + df._clock + ': ' + count + ' operators; ' + dt + 'ms'); | ||
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 | ||
.sort(function(a, b) { return b.priority - a.priority; }) | ||
.forEach(function(_) { invokeCallback(df, _.callback); }); | ||
} | ||
return count; | ||
} | ||
if (error) { | ||
df._postrun = []; | ||
df.error(error); | ||
function invokeCallback(df, callback) { | ||
try { callback(df); } catch (err) { df.error(err); } | ||
} | ||
if (df._onrun) { | ||
try { df._onrun(df, count, error); } catch (err) { df.error(err); } | ||
/** | ||
* 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()); | ||
} | ||
// invoke callbacks queued via runAfter | ||
if (df._postrun.length) { | ||
var postrun = df._postrun; | ||
df._postrun = []; | ||
postrun | ||
.sort(function(a, b) { return b.priority - a.priority; }) | ||
.forEach(function(_) { invokeCallback(df, _.callback); }); | ||
/** | ||
* 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 invocation when propagation is not | ||
* currently occurring. | ||
*/ | ||
function runAfter(callback, enqueue, priority) { | ||
if (this._pulse || enqueue) { | ||
// pulse propagation is currently running, queue to run after | ||
this._postrun.push({ | ||
priority: priority || 0, | ||
callback: callback | ||
}); | ||
} else { | ||
// pulse propagation already complete, invoke immediately | ||
invokeCallback(this, callback); | ||
} | ||
} | ||
return count; | ||
} | ||
/** | ||
* 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); | ||
} | ||
} | ||
function invokeCallback(df, callback) { | ||
try { callback(df); } catch (err) { df.error(err); } | ||
} | ||
/** | ||
* 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; | ||
/** | ||
* 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()); | ||
} | ||
if (s && vegaUtil.isArray(s)) { | ||
p = s.map(function(_) { return _.pulse; }); | ||
return new MultiPulse(this, stamp, p, encode); | ||
} | ||
/** | ||
* 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 invocation when propagation is not | ||
* currently occurring. | ||
*/ | ||
function runAfter(callback, enqueue, priority) { | ||
if (this._pulse || enqueue) { | ||
// pulse propagation is currently running, queue to run after | ||
this._postrun.push({ | ||
priority: priority || 0, | ||
callback: callback | ||
}); | ||
} else { | ||
// pulse propagation already complete, invoke immediately | ||
invokeCallback(this, callback); | ||
} | ||
} | ||
p = this._pulses[op.id]; | ||
if (s) { | ||
s = s.pulse; | ||
if (!s || s === StopPropagation) { | ||
p.source = []; | ||
} else if (s.stamp === stamp && p.target !== op) { | ||
p = s; | ||
} else { | ||
p.source = s.source; | ||
} | ||
} | ||
/** | ||
* 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); | ||
return p; | ||
} | ||
} | ||
/** | ||
* 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; | ||
var NO_OPT = {skip: false, force: false}; | ||
if (s && vegaUtil.isArray(s)) { | ||
p = s.map(function(_) { return _.pulse; }); | ||
return new MultiPulse(this, stamp, p, encode); | ||
/** | ||
* 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; | ||
} | ||
p = this._pulses[op.id]; | ||
if (s) { | ||
s = s.pulse; | ||
if (!s || s === StopPropagation) { | ||
p.source = []; | ||
} else if (s.stamp === stamp && p.target !== op) { | ||
p = s; | ||
} else { | ||
p.source = s.source; | ||
/** | ||
* 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; | ||
} | ||
return p; | ||
} | ||
/** | ||
* 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 NO_OPT = {skip: false, force: false}; | ||
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); | ||
/** | ||
* 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); | ||
return this; | ||
} | ||
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); | ||
function Heap(comparator) { | ||
this.cmp = comparator; | ||
this.nodes = []; | ||
} | ||
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 prototype$5 = Heap.prototype; | ||
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); | ||
prototype$5.size = function() { | ||
return this.nodes.length; | ||
}; | ||
return this; | ||
} | ||
prototype$5.clear = function() { | ||
this.nodes = []; | ||
return this; | ||
}; | ||
function Heap(comparator) { | ||
this.cmp = comparator; | ||
this.nodes = []; | ||
} | ||
prototype$5.peek = function() { | ||
return this.nodes[0]; | ||
}; | ||
var prototype$6 = Heap.prototype; | ||
prototype$5.push = function(x) { | ||
var array = this.nodes; | ||
array.push(x); | ||
return siftdown(array, 0, array.length-1, this.cmp); | ||
}; | ||
prototype$6.size = function() { | ||
return this.nodes.length; | ||
}; | ||
prototype$5.pop = function() { | ||
var array = this.nodes, | ||
last = array.pop(), | ||
item; | ||
prototype$6.clear = function() { | ||
this.nodes = []; | ||
return this; | ||
}; | ||
if (array.length) { | ||
item = array[0]; | ||
array[0] = last; | ||
siftup(array, 0, this.cmp); | ||
} else { | ||
item = last; | ||
} | ||
return item; | ||
}; | ||
prototype$6.peek = function() { | ||
return this.nodes[0]; | ||
}; | ||
prototype$5.replace = function(item) { | ||
var array = this.nodes, | ||
retval = array[0]; | ||
array[0] = item; | ||
siftup(array, 0, this.cmp); | ||
return retval; | ||
}; | ||
prototype$6.push = function(x) { | ||
var array$$1 = this.nodes; | ||
array$$1.push(x); | ||
return siftdown(array$$1, 0, array$$1.length-1, this.cmp); | ||
}; | ||
prototype$5.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; | ||
}; | ||
prototype$6.pop = function() { | ||
var array$$1 = this.nodes, | ||
last = array$$1.pop(), | ||
item; | ||
function siftdown(array, start, idx, cmp) { | ||
var item, parent, pidx; | ||
if (array$$1.length) { | ||
item = array$$1[0]; | ||
array$$1[0] = last; | ||
siftup(array$$1, 0, this.cmp); | ||
} else { | ||
item = last; | ||
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); | ||
} | ||
return item; | ||
}; | ||
prototype$6.replace = function(item) { | ||
var array$$1 = this.nodes, | ||
retval = array$$1[0]; | ||
array$$1[0] = item; | ||
siftup(array$$1, 0, this.cmp); | ||
return retval; | ||
}; | ||
function siftup(array, idx, cmp) { | ||
var start = idx, | ||
end = array.length, | ||
item = array[idx], | ||
cidx = 2 * idx + 1, ridx; | ||
prototype$6.pushpop = function(item) { | ||
var array$$1 = this.nodes, ref = array$$1[0]; | ||
if (array$$1.length && this.cmp(ref, item) < 0) { | ||
array$$1[0] = item; | ||
item = ref; | ||
siftup(array$$1, 0, this.cmp); | ||
} | ||
return item; | ||
}; | ||
function siftdown(array$$1, start, idx, cmp) { | ||
var item, parent, pidx; | ||
item = array$$1[idx]; | ||
while (idx > start) { | ||
pidx = (idx - 1) >> 1; | ||
parent = array$$1[pidx]; | ||
if (cmp(item, parent) < 0) { | ||
array$$1[idx] = parent; | ||
idx = pidx; | ||
continue; | ||
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; | ||
} | ||
break; | ||
array[idx] = item; | ||
return siftdown(array, start, idx, cmp); | ||
} | ||
return (array$$1[idx] = item); | ||
} | ||
function siftup(array$$1, idx, cmp) { | ||
var start = idx, | ||
end = array$$1.length, | ||
item = array$$1[idx], | ||
cidx = 2 * idx + 1, ridx; | ||
/** | ||
* A dataflow graph for reactive processing of data streams. | ||
* @constructor | ||
*/ | ||
function Dataflow() { | ||
this._log = vegaUtil.logger(); | ||
this.logLevel(vegaUtil.Error); | ||
while (cidx < end) { | ||
ridx = cidx + 1; | ||
if (ridx < end && cmp(array$$1[cidx], array$$1[ridx]) >= 0) { | ||
cidx = ridx; | ||
this._clock = 0; | ||
this._rank = 0; | ||
try { | ||
this._loader = vegaLoader.loader(); | ||
} catch (e) { | ||
// do nothing if loader module is unavailable | ||
} | ||
array$$1[idx] = array$$1[cidx]; | ||
idx = cidx; | ||
cidx = 2 * idx + 1; | ||
} | ||
array$$1[idx] = item; | ||
return siftdown(array$$1, start, idx, cmp); | ||
} | ||
/** | ||
* A dataflow graph for reactive processing of data streams. | ||
* @constructor | ||
*/ | ||
function Dataflow() { | ||
this._log = vegaUtil.logger(); | ||
this.logLevel(vegaUtil.Error); | ||
this._touched = UniqueList(vegaUtil.id); | ||
this._pulses = {}; | ||
this._pulse = null; | ||
this._clock = 0; | ||
this._rank = 0; | ||
try { | ||
this._loader = vegaLoader.loader(); | ||
} catch (e) { | ||
// do nothing if loader module is unavailable | ||
this._heap = new Heap(function(a, b) { return a.qrank - b.qrank; }); | ||
this._postrun = []; | ||
} | ||
this._touched = UniqueList(vegaUtil.id); | ||
this._pulses = {}; | ||
this._pulse = null; | ||
var prototype$6 = Dataflow.prototype; | ||
this._heap = new Heap(function(a, b) { return a.qrank - b.qrank; }); | ||
this._postrun = []; | ||
} | ||
/** | ||
* 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$6.stamp = function() { | ||
return this._clock; | ||
}; | ||
var prototype = Dataflow.prototype; | ||
/** | ||
* 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$6.loader = function(_) { | ||
if (arguments.length) { | ||
this._loader = _; | ||
return this; | ||
} else { | ||
return this._loader; | ||
} | ||
}; | ||
/** | ||
* 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; | ||
}; | ||
/** | ||
* Empty entry threshold for garbage cleaning. Map data structures will | ||
* perform cleaning once the number of empty entries exceeds this value. | ||
*/ | ||
prototype$6.cleanThreshold = 1e4; | ||
/** | ||
* 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; | ||
} | ||
}; | ||
// OPERATOR REGISTRATION | ||
prototype$6.add = add; | ||
prototype$6.connect = connect; | ||
prototype$6.rank = rank; | ||
prototype$6.rerank = rerank; | ||
/** | ||
* 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 UPDATES | ||
prototype$6.pulse = pulse; | ||
prototype$6.touch = touch; | ||
prototype$6.update = update; | ||
prototype$6.changeset = changeset; | ||
// OPERATOR REGISTRATION | ||
prototype.add = add; | ||
prototype.connect = connect; | ||
prototype.rank = rank; | ||
prototype.rerank = rerank; | ||
// DATA LOADING | ||
prototype$6.ingest = ingest$1; | ||
prototype$6.request = request; | ||
// OPERATOR UPDATES | ||
prototype.pulse = pulse; | ||
prototype.touch = touch; | ||
prototype.update = update; | ||
prototype.changeset = changeset; | ||
// EVENT HANDLING | ||
prototype$6.events = events; | ||
prototype$6.on = on; | ||
// DATA LOADING | ||
prototype.ingest = ingest$1; | ||
prototype.request = request; | ||
// PULSE PROPAGATION | ||
prototype$6.run = run; | ||
prototype$6.runAsync = runAsync; | ||
prototype$6.runAfter = runAfter; | ||
prototype$6._enqueue = enqueue; | ||
prototype$6._getPulse = getPulse; | ||
// EVENT HANDLING | ||
prototype.events = events; | ||
prototype.on = on; | ||
// LOGGING AND ERROR HANDLING | ||
// PULSE PROPAGATION | ||
prototype.run = run; | ||
prototype.runAsync = runAsync; | ||
prototype.runAfter = runAfter; | ||
prototype._enqueue = enqueue; | ||
prototype._getPulse = getPulse; | ||
function logMethod(method) { | ||
return function() { | ||
return this._log[method].apply(this, arguments); | ||
}; | ||
} | ||
// LOGGING AND ERROR HANDLING | ||
/** | ||
* 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$6.error = logMethod('error'); | ||
function logMethod(method) { | ||
return function() { | ||
return this._log[method].apply(this, arguments); | ||
}; | ||
} | ||
/** | ||
* 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$6.warn = logMethod('warn'); | ||
/** | ||
* 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 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$6.info = logMethod('info'); | ||
/** | ||
* 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 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$6.debug = logMethod('debug'); | ||
/** | ||
* 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'); | ||
/** | ||
* 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$6.logLevel = logMethod('level'); | ||
/** | ||
* 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'); | ||
/** | ||
* 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); | ||
} | ||
/** | ||
* 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'); | ||
var prototype$7 = vegaUtil.inherits(Transform, Operator); | ||
/** | ||
* 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); | ||
} | ||
/** | ||
* 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 prototype$7 = vegaUtil.inherits(Transform, Operator); | ||
var rv; | ||
if (this.skip()) { | ||
this.skip(false); | ||
} else { | ||
rv = this.evaluate(pulse); | ||
} | ||
rv = rv || pulse; | ||
/** | ||
* 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; | ||
if (rv !== pulse.StopPropagation) this.pulse = rv; | ||
this.stamp = pulse.stamp; | ||
var rv; | ||
if (this.skip()) { | ||
this.skip(false); | ||
} else { | ||
rv = this.evaluate(pulse); | ||
} | ||
rv = rv || pulse; | ||
return rv; | ||
}; | ||
if (rv !== pulse.StopPropagation) this.pulse = rv; | ||
this.stamp = pulse.stamp; | ||
/** | ||
* 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; | ||
}; | ||
return rv; | ||
}; | ||
/** | ||
* 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() {}; | ||
/** | ||
* 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; | ||
}; | ||
var transforms = {}; | ||
/** | ||
* 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() {}; | ||
function definition(type) { | ||
var t = transform(type); | ||
return t && t.Definition || null; | ||
} | ||
var transforms = {}; | ||
function transform(type) { | ||
type = type && type.toLowerCase(); | ||
return transforms.hasOwnProperty(type) ? transforms[type] : null; | ||
} | ||
function definition(type) { | ||
var t = transform(type); | ||
return t && t.Definition || null; | ||
} | ||
// Utilities | ||
function transform(type) { | ||
type = type && type.toLowerCase(); | ||
return transforms.hasOwnProperty(type) ? transforms[type] : null; | ||
} | ||
exports.UniqueList = UniqueList; | ||
exports.changeset = changeset; | ||
exports.isChangeSet = isChangeSet; | ||
exports.Dataflow = Dataflow; | ||
exports.EventStream = EventStream; | ||
exports.Parameters = Parameters; | ||
exports.Pulse = Pulse; | ||
exports.MultiPulse = MultiPulse; | ||
exports.Operator = Operator; | ||
exports.Transform = Transform; | ||
exports.derive = derive; | ||
exports.rederive = rederive; | ||
exports.ingest = ingest; | ||
exports.isTuple = isTuple; | ||
exports.replace = replace; | ||
exports.tupleid = tupleid; | ||
exports.definition = definition; | ||
exports.transform = transform; | ||
exports.transforms = transforms; | ||
// Utilities | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
exports.UniqueList = UniqueList; | ||
exports.changeset = changeset; | ||
exports.isChangeSet = isChangeSet; | ||
exports.Dataflow = Dataflow; | ||
exports.EventStream = EventStream; | ||
exports.Parameters = Parameters; | ||
exports.Pulse = Pulse; | ||
exports.MultiPulse = MultiPulse; | ||
exports.Operator = Operator; | ||
exports.Transform = Transform; | ||
exports.derive = derive; | ||
exports.rederive = rederive; | ||
exports.ingest = ingest; | ||
exports.isTuple = isTuple; | ||
exports.replace = replace; | ||
exports.tupleid = tupleid; | ||
exports.definition = definition; | ||
exports.transform = transform; | ||
exports.transforms = transforms; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
}))); |
@@ -1,1 +0,1 @@ | ||
!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("vega-util"),require("vega-loader")):"function"==typeof define&&define.amd?define(["exports","vega-util","vega-loader"],n):n(t.vega=t.vega||{},t.vega,t.vega)}(this,function(t,n,e){"use strict";function r(t){var e=t||n.identity,r=[],i={};return r.add=function(t){var n=e(t);return i[n]||(i[n]=1,r.push(t)),r},r.remove=function(t){var n,s=e(t);return i[s]&&(i[s]=0,(n=r.indexOf(t))>=0&&r.splice(n,1)),r},r}function i(t){return t[S]}function s(t,n){return t[S]=n,t}function u(t){var n=t===Object(t)?t:{data:t};return i(n)?n:s(n,L++)}function o(t,n){for(var e in t)n[e]=t[e];return n}function a(t){return t&&t.constructor===l}function l(){var t=[],e=[],r=[],s=[],o=[],a=!1;return{constructor:l,insert:function(e){for(var r=n.array(e),i=0,s=r.length;i<s;++i)t.push(r[i]);return this},remove:function(t){for(var r=n.isFunction(t)?s:e,i=n.array(t),u=0,o=i.length;u<o;++u)r.push(i[u]);return this},modify:function(t,e,i){var s={field:e,value:n.constant(i)};return n.isFunction(t)?(s.filter=t,o.push(s)):(s.tuple=t,r.push(s)),this},encode:function(t,e){return n.isFunction(t)?o.push({filter:t,field:e}):r.push({tuple:t,field:e}),this},reflow:function(){return a=!0,this},pulse:function(n,l){function f(t,e,r){r?t[e]=r(t):n.encode=e,a||(c[i(t)]=t)}var c,h,d,p,v,g,m;for(h=0,d=t.length;h<d;++h)n.add.push(u(t[h]));for(c={},h=0,d=e.length;h<d;++h)c[i(g=e[h])]=g;for(h=0,d=s.length;h<d;++h)v=s[h],l.forEach(function(t){v(t)&&(c[i(t)]=t)});for(m in c)n.rem.push(c[m]);for(c={},h=0,d=r.length;h<d;++h)f((p=r[h]).tuple,p.field,p.value),n.modifies(p.field);for(h=0,d=o.length;h<d;++h)p=o[h],v=p.filter,l.forEach(function(t){v(t)&&f(t,p.field,p.value)}),n.modifies(p.field);if(a)n.mod=e.length||s.length?l.filter(function(t){return c.hasOwnProperty(i(t))}):l.slice();else for(m in c)n.mod.push(c[m]);return n}}}function f(){Object.defineProperty(this,R,{writable:!0,value:{}})}function c(t,n,e,r){this.id=++T,this.value=t,this.stamp=-1,this.rank=-1,this.qrank=-1,this.flags=0,n&&(this._update=n),e&&this.parameters(e,r)}function h(t){return function(n){var e=this.flags;return 0===arguments.length?!!(e&t):(this.flags=n?e|t:e&~t,this)}}function d(t,n,e){this.id=++I,this.value=null,e&&(this.receive=e),t&&(this._filter=t),n&&(this._apply=n)}function p(t,n,e){return new d(t,n,e)}function v(t){var n,e,r=new Promise(function(t,r){n=t,e=r});return r.requests=0,r.done=function(){0==--r.requests&&t.runAfter(function(){t._pending=null;try{t.run(),n(t)}catch(t){e(t)}})},t._pending=r}function g(t,e,r,i,s,u){var o,l,f=n.extend({},u,j);n.isFunction(r)||(r=n.constant(r)),void 0===i?o=function(n){t.touch(r(n))}:n.isFunction(i)?(l=new c(null,i,s,!1),o=function(n){var e,i=r(n);l.evaluate(n),a(e=l.value)?t.pulse(i,e,u):t.update(i,e,f)}):o=function(n){t.update(r(n),i,f)},e.apply(o)}function m(t,e,r,i,s,u){var o,a;void 0===i?a=r:(o=n.isFunction(i)?i:n.constant(i),(a=new c(null,i=r?function(t,n){var e=o(t,n);return r.skip()?e:r.skip(!0).value=e}:o,s,!1)).modified(u&&u.force),a.rank=0,r&&(a.skip(!0),a.value=r.value,a.targets().add(r))),e.targets().add(a)}function _(t,n,e){this.dataflow=t,this.stamp=null==n?-1:n,this.add=[],this.rem=[],this.mod=[],this.fields=null,this.encode=e||null}function y(t,n){return t?function(e,r){return t(e,r)&&n(e,r)}:n}function k(t,e){var r=[];return n.visitArray(t,e,function(t){r.push(t)}),r}function F(t,n){var e={};return t.visit(n,function(t){e[i(t)]=1}),function(t){return e[i(t)]?null:t}}function w(t,n,e,r){var i,s,u,o,a,l=this,f=0;for(this.dataflow=t,this.stamp=n,this.fields=null,this.encode=r||null,this.pulses=e,u=0,o=e.length;u<o;++u)if((i=e[u]).stamp===n){if(i.fields){s=l.fields||(l.fields={});for(a in i.fields)s[a]=1}i.changed(l.ADD)&&(f|=l.ADD),i.changed(l.REM)&&(f|=l.REM),i.changed(l.MOD)&&(f|=l.MOD)}this.changes=f}function A(t,n){try{n(t)}catch(n){t.error(n)}}function D(t){this.cmp=t,this.nodes=[]}function O(t,n,e,r){var i,s,u;for(i=t[e];e>n&&r(i,s=t[u=e-1>>1])<0;)t[e]=s,e=u;return t[e]=i}function P(t,n,e){for(var r,i=n,s=t.length,u=t[n],o=2*n+1;o<s;)(r=o+1)<s&&e(t[o],t[r])>=0&&(o=r),t[n]=t[o],o=2*(n=o)+1;return t[n]=u,O(t,i,n,e)}function E(){this._log=n.logger(),this.logLevel(n.Error),this._clock=0,this._rank=0;try{this._loader=e.loader()}catch(t){}this._touched=r(n.id),this._pulses={},this._pulse=null,this._heap=new D(function(t,n){return t.qrank-n.qrank}),this._postrun=[]}function q(t){return function(){return this._log[t].apply(this,arguments)}}function b(t,n){c.call(this,t,null,n)}function M(t){return t=t&&t.toLowerCase(),Q.hasOwnProperty(t)?Q[t]:null}var S=Symbol("vega_id"),L=1,R="_:mod:_",x=f.prototype;x.set=function(t,e,r,i){var s=this,u=s[t],o=s[R];return null!=e&&e>=0?(u[e]!==r||i)&&(u[e]=r,o[e+":"+t]=-1,o[t]=-1):(u!==r||i)&&(s[t]=r,o[t]=n.isArray(r)?1+r.length:-1),s},x.modified=function(t,e){var r,i=this[R];if(!arguments.length){for(r in i)if(i[r])return!0;return!1}if(n.isArray(t)){for(r=0;r<t.length;++r)if(i[t[r]])return!0;return!1}return null!=e&&e>=0?e+1<i[t]||!!i[e+":"+t]:!!i[t]},x.clear=function(){return this[R]={},this};var T=0,z=new f,C=c.prototype;C.targets=function(){return this._targets||(this._targets=r(n.id))},C.set=function(t){return this.value!==t?(this.value=t,1):0},C.skip=h(1),C.modified=h(2),C.parameters=function(t,e){function r(t,n,r){r instanceof c?(r!==a&&(e&&r.targets().add(a),d.push(r)),h.push({op:r,name:t,index:n})):l.set(t,n,r)}e=!1!==e;var i,s,u,o,a=this,l=a._argval=a._argval||new f,h=a._argops=a._argops||[],d=[];for(i in t)if(s=t[i],"pulse"===i)n.array(s).forEach(function(t){t instanceof c?t!==a&&(t.targets().add(a),d.push(t)):n.error("Pulse parameters must be operator instances.")}),a.source=s;else if(n.isArray(s))for(l.set(i,-1,Array(u=s.length)),o=0;o<u;++o)r(i,o,s[o]);else r(i,-1,s);return this.marshall().clear(),d},C.marshall=function(t){var n,e,r,i,s,u=this._argval||z,o=this._argops;if(o&&(r=o.length))for(e=0;e<r;++e)s=(i=(n=o[e]).op).modified()&&i.stamp===t,u.set(n.name,n.index,i.value,s);return u},C.evaluate=function(t){if(this._update){var n=this.marshall(t.stamp),e=this._update(n,t);if(n.clear(),e!==this.value)this.value=e;else if(!this.modified())return t.StopPropagation}},C.run=function(t){if(t.stamp<=this.stamp)return t.StopPropagation;var n;return this.skip()?(this.skip(!1),n=0):n=this.evaluate(t),this.stamp=t.stamp,this.pulse=n,n||t};var I=0,U=d.prototype;U._filter=n.truthy,U._apply=n.identity,U.targets=function(){return this._targets||(this._targets=r(n.id))},U.consume=function(t){return arguments.length?(this._consume=!!t,this):!!this._consume},U.receive=function(t){if(this._filter(t)){for(var n=this.value=this._apply(t),e=this._targets,r=e?e.length:0,i=0;i<r;++i)e[i].receive(n);this._consume&&(t.preventDefault(),t.stopPropagation())}},U.filter=function(t){var n=p(t);return this.targets().add(n),n},U.apply=function(t){var n=p(null,t);return this.targets().add(n),n},U.merge=function(){var t=p();this.targets().add(t);for(var n=0,e=arguments.length;n<e;++n)arguments[n].targets().add(t);return t},U.throttle=function(t){var n=-1;return this.filter(function(){var e=Date.now();return e-n>t?(n=e,1):0})},U.debounce=function(t){var e=p();return this.targets().add(p(null,null,n.debounce(t,function(t){var n=t.dataflow;e.receive(t),n&&n.run&&n.run()}))),e},U.between=function(t,n){var e=!1;return t.targets().add(p(null,null,function(){e=!0})),n.targets().add(p(null,null,function(){e=!1})),this.filter(function(){return e})};var j={skip:!0},N={},G=_.prototype;G.StopPropagation=N,G.ADD=1,G.REM=2,G.MOD=4,G.ADD_REM=3,G.ADD_MOD=5,G.ALL=7,G.REFLOW=8,G.SOURCE=16,G.NO_SOURCE=32,G.NO_FIELDS=64,G.fork=function(t){return new _(this.dataflow).init(this,t)},G.clone=function(){var t=this.fork(7);return t.add=t.add.slice(),t.rem=t.rem.slice(),t.mod=t.mod.slice(),t.source&&(t.source=t.source.slice()),t.materialize(23)},G.addAll=function(){var t=this;return this.source&&this.source.length!==this.add.length?(t=new _(this.dataflow).init(this),t.add=t.source,t):t},G.init=function(t,n){var e=this;return e.stamp=t.stamp,e.encode=t.encode,!t.fields||64&n||(e.fields=t.fields),1&n?(e.addF=t.addF,e.add=t.add):(e.addF=null,e.add=[]),2&n?(e.remF=t.remF,e.rem=t.rem):(e.remF=null,e.rem=[]),4&n?(e.modF=t.modF,e.mod=t.mod):(e.modF=null,e.mod=[]),32&n?(e.srcF=null,e.source=null):(e.srcF=t.srcF,e.source=t.source),e},G.runAfter=function(t){this.dataflow.runAfter(t)},G.changed=function(t){var n=t||7;return 1&n&&this.add.length||2&n&&this.rem.length||4&n&&this.mod.length},G.reflow=function(t){if(t)return this.fork(7).reflow();var n=this.add.length,e=this.source&&this.source.length;return e&&e!==n&&(this.mod=this.source,n&&this.filter(4,F(this,1))),this},G.modifies=function(t){var e=n.array(t),r=this.fields||(this.fields={});return e.forEach(function(t){r[t]=!0}),this},G.modified=function(t){var e=this.fields;return!(!this.mod.length||!e)&&(arguments.length?n.isArray(t)?t.some(function(t){return e[t]}):e[t]:!!e)},G.filter=function(t,n){var e=this;return 1&t&&(e.addF=y(e.addF,n)),2&t&&(e.remF=y(e.remF,n)),4&t&&(e.modF=y(e.modF,n)),16&t&&(e.srcF=y(e.srcF,n)),e},G.materialize=function(t){var n=this;return 1&(t=t||7)&&n.addF&&(n.add=k(n.add,n.addF),n.addF=null),2&t&&n.remF&&(n.rem=k(n.rem,n.remF),n.remF=null),4&t&&n.modF&&(n.mod=k(n.mod,n.modF),n.modF=null),16&t&&n.srcF&&(n.source=n.source.filter(n.srcF),n.srcF=null),n},G.visit=function(t,e){var r,i,s=this,u=e;return 16&t?(n.visitArray(s.source,s.srcF,u),s):(1&t&&n.visitArray(s.add,s.addF,u),2&t&&n.visitArray(s.rem,s.remF,u),4&t&&n.visitArray(s.mod,s.modF,u),8&t&&(r=s.source)&&((i=s.add.length+s.mod.length)===r.length||(i?n.visitArray(r,F(s,5),u):n.visitArray(r,s.srcF,u))),s)};var W=n.inherits(w,_);W.fork=function(t){var n=new _(this.dataflow).init(this,t&this.NO_FIELDS);return void 0!==t&&(t&n.ADD&&this.visit(n.ADD,function(t){return n.add.push(t)}),t&n.REM&&this.visit(n.REM,function(t){return n.rem.push(t)}),t&n.MOD&&this.visit(n.MOD,function(t){return n.mod.push(t)})),n},W.changed=function(t){return this.changes&t},W.modified=function(t){var e=this,r=e.fields;return r&&e.changes&e.MOD?n.isArray(t)?t.some(function(t){return r[t]}):r[t]:0},W.filter=function(){n.error("MultiPulse does not support filtering.")},W.materialize=function(){n.error("MultiPulse does not support materialization.")},W.visit=function(t,n){var e=this,r=e.pulses,i=r.length,s=0;if(t&e.SOURCE)for(;s<i;++s)r[s].visit(t,n);else for(;s<i;++s)r[s].stamp===e.stamp&&r[s].visit(t,n);return e};var B={skip:!1,force:!1},H=D.prototype;H.size=function(){return this.nodes.length},H.clear=function(){return this.nodes=[],this},H.peek=function(){return this.nodes[0]},H.push=function(t){var n=this.nodes;return n.push(t),O(n,0,n.length-1,this.cmp)},H.pop=function(){var t,n=this.nodes,e=n.pop();return n.length?(t=n[0],n[0]=e,P(n,0,this.cmp)):t=e,t},H.replace=function(t){var n=this.nodes,e=n[0];return n[0]=t,P(n,0,this.cmp),e},H.pushpop=function(t){var n=this.nodes,e=n[0];return n.length&&this.cmp(e,t)<0&&(n[0]=t,t=e,P(n,0,this.cmp)),t};var J=E.prototype;J.stamp=function(){return this._clock},J.loader=function(t){return arguments.length?(this._loader=t,this):this._loader},J.cleanThreshold=1e4,J.add=function(t,e,r,i){var s,u=1;return t instanceof c?s=t:t&&t.prototype instanceof c?s=new t:n.isFunction(t)?s=new c(null,t):(u=0,s=new c(t,e)),this.rank(s),u&&(i=r,r=e),r&&this.connect(s,s.parameters(r,i)),this.touch(s),s},J.connect=function(t,n){var e,r,i=t.rank;for(e=0,r=n.length;e<r;++e)if(i<n[e].rank)return void this.rerank(t)},J.rank=function(t){t.rank=++this._rank},J.rerank=function(t){for(var e,r,i,s=[t];s.length;)if(this.rank(e=s.pop()),r=e._targets)for(i=r.length;--i>=0;)s.push(e=r[i]),e===t&&n.error("Cycle detected in dataflow graph.")},J.pulse=function(t,n,e){this.touch(t,e||B);var r=new _(this,this._clock+(this._pulse?0:1)),i=t.pulse&&t.pulse.source||[];return r.target=t,this._pulses[t.id]=n.pulse(r,i),this},J.touch=function(t,n){var e=n||B;return this._pulse?this._enqueue(t):this._touched.add(t),e.skip&&t.skip(!0),this},J.update=function(t,n,e){var r=e||B;return(t.set(n)||r.force)&&this.touch(t,r),this},J.changeset=l,J.ingest=function(t,n,r){return this.pulse(t,this.changeset().insert(e.read(n,r)))},J.request=function(t,n,e){var r=this,i=r._pending||v(r);i.requests+=1,r.loader().load(n,{context:"dataflow"}).then(function(n){r.ingest(t,n,e)},function(t){r.error("Loading failed",n,t)}).catch(function(t){r.error("Data ingestion failed",n,t)}).then(i.done,i.done)},J.events=function(t,e,r,i){for(var s,u=this,o=p(r,i),a=0,l=(s="string"==typeof t&&"undefined"!=typeof document?document.querySelectorAll(t):n.array(t)).length;a<l;++a)s[a].addEventListener(e,function(t){t.dataflow=u;try{o.receive(t)}catch(t){u.error(t)}finally{u.run()}});return o},J.on=function(t,n,e,r,i){return(t instanceof c?m:g)(this,t,n,e,r,i),this},J.run=function(t){var e,i,s,u,o=this,a=0,l=o.logLevel();if(o._pending)return o.info("Awaiting requests, delaying dataflow run."),0;if(o._pulse)return o.error("Dataflow invoked recursively. Use the runAfter method to queue invocation."),0;if(!o._touched.length)return o.info("Dataflow invoked, but nothing to do."),0;o._pulse=new _(o,++o._clock,t),l>=n.Info&&(s=Date.now(),o.debug("-- START PROPAGATION ("+o._clock+") -----")),o._touched.forEach(function(t){o._enqueue(t,!0)}),o._touched=r(n.id);try{for(;o._heap.size()>0;)(e=o._heap.pop()).rank===e.qrank?(i=e.run(o._getPulse(e,t)),l>=n.Debug&&o.debug(e.id,i===N?"STOP":i,e),i!==N&&(o._pulse=i,e._targets&&e._targets.forEach(function(t){o._enqueue(t)})),++a):o._enqueue(e,!0)}catch(t){u=t}if(o._pulses={},o._pulse=null,l>=n.Info&&(s=Date.now()-s,o.info("> Pulse "+o._clock+": "+a+" operators; "+s+"ms")),u&&(o._postrun=[],o.error(u)),o._onrun)try{o._onrun(o,a,u)}catch(t){o.error(t)}if(o._postrun.length){var f=o._postrun;o._postrun=[],f.sort(function(t,n){return n.priority-t.priority}).forEach(function(t){A(o,t.callback)})}return a},J.runAsync=function(){return this._pending||Promise.resolve(this.run())},J.runAfter=function(t,n,e){this._pulse||n?this._postrun.push({priority:e||0,callback:t}):A(this,t)},J._enqueue=function(t,n){var e=!this._pulses[t.id];e&&(this._pulses[t.id]=this._pulse),(e||n)&&(t.qrank=t.rank,this._heap.push(t))},J._getPulse=function(t,e){var r,i=t.source,s=this._clock;return i&&n.isArray(i)?(r=i.map(function(t){return t.pulse}),new w(this,s,r,e)):(r=this._pulses[t.id],i&&((i=i.pulse)&&i!==N?i.stamp===s&&r.target!==t?r=i:r.source=i.source:r.source=[]),r)},J.error=q("error"),J.warn=q("warn"),J.info=q("info"),J.debug=q("debug"),J.logLevel=q("level");var K=n.inherits(b,c);K.run=function(t){if(t.stamp<=this.stamp)return t.StopPropagation;var n;return this.skip()?this.skip(!1):n=this.evaluate(t),(n=n||t)!==t.StopPropagation&&(this.pulse=n),this.stamp=t.stamp,n},K.evaluate=function(t){var n=this.marshall(t.stamp),e=this.transform(n,t);return n.clear(),e},K.transform=function(){};var Q={};t.UniqueList=r,t.changeset=l,t.isChangeSet=a,t.Dataflow=E,t.EventStream=d,t.Parameters=f,t.Pulse=_,t.MultiPulse=w,t.Operator=c,t.Transform=b,t.derive=function(t){return o(t,u({}))},t.rederive=o,t.ingest=u,t.isTuple=function(t){return!(!t||!i(t))},t.replace=function(t,n){return s(n,i(t))},t.tupleid=i,t.definition=function(t){var n=M(t);return n&&n.Definition||null},t.transform=M,t.transforms=Q,Object.defineProperty(t,"__esModule",{value:!0})}); | ||
!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("vega-util"),require("vega-loader")):"function"==typeof define&&define.amd?define(["exports","vega-util","vega-loader"],n):n(t.vega={},t.vega,t.vega)}(this,function(t,g,r){"use strict";function l(t){var r=t||g.identity,i=[],s={};return i.add=function(t){var n=r(t);return s[n]||(s[n]=1,i.push(t)),i},i.remove=function(t){var n,e=r(t);return s[e]&&(s[e]=0)<=(n=i.indexOf(t))&&i.splice(n,1),i},i}var e=Symbol("vega_id"),i=1;function m(t){return t[e]}function s(t,n){return t[e]=n,t}function _(t){var n=t===Object(t)?t:{data:t};return m(n)?n:s(n,i++)}function n(t,n){for(var e in t)n[e]=t[e];return n}function h(t){return t&&t.constructor===u}function u(){var h=[],c=[],f=[],d=[],p=[],v=!1;return{constructor:u,insert:function(t){for(var n=g.array(t),e=0,r=n.length;e<r;++e)h.push(n[e]);return this},remove:function(t){for(var n=g.isFunction(t)?d:c,e=g.array(t),r=0,i=e.length;r<i;++r)n.push(e[r]);return this},modify:function(t,n,e){var r={field:n,value:g.constant(e)};return g.isFunction(t)?(r.filter=t,p.push(r)):(r.tuple=t,f.push(r)),this},encode:function(t,n){return g.isFunction(t)?p.push({filter:t,field:n}):f.push({tuple:t,field:n}),this},reflow:function(){return v=!0,this},pulse:function(r,t){var i,n,e,s,u,o,a;for(n=0,e=h.length;n<e;++n)r.add.push(_(h[n]));for(i={},n=0,e=c.length;n<e;++n)i[m(o=c[n])]=o;for(n=0,e=d.length;n<e;++n)u=d[n],t.forEach(function(t){u(t)&&(i[m(t)]=t)});for(a in i)r.rem.push(i[a]);function l(t,n,e){e?t[n]=e(t):r.encode=n,v||(i[m(t)]=t)}for(i={},n=0,e=f.length;n<e;++n)l((s=f[n]).tuple,s.field,s.value),r.modifies(s.field);for(n=0,e=p.length;n<e;++n)s=p[n],u=s.filter,t.forEach(function(t){u(t)&&l(t,s.field,s.value)}),r.modifies(s.field);if(v)r.mod=c.length||d.length?t.filter(function(t){return i.hasOwnProperty(m(t))}):t.slice();else for(a in i)r.mod.push(i[a]);return r}}}var o="_:mod:_";function c(){Object.defineProperty(this,o,{writable:!0,value:{}})}var a=c.prototype;a.set=function(t,n,e,r){var i=this[t],s=this[o];return null!=n&&0<=n?(i[n]!==e||r)&&(i[n]=e,s[n+":"+t]=-1,s[t]=-1):(i!==e||r)&&(this[t]=e,s[t]=g.isArray(e)?1+e.length:-1),this},a.modified=function(t,n){var e,r=this[o];if(!arguments.length){for(e in r)if(r[e])return!0;return!1}if(g.isArray(t)){for(e=0;e<t.length;++e)if(r[t[e]])return!0;return!1}return null!=n&&0<=n?n+1<r[t]||!!r[n+":"+t]:!!r[t]},a.clear=function(){return this[o]={},this};var f=0,d=new c;function p(t,n,e,r){this.id=++f,this.value=t,this.stamp=-1,this.rank=-1,this.qrank=-1,this.flags=0,n&&(this._update=n),e&&this.parameters(e,r)}var v=p.prototype;function y(e){return function(t){var n=this.flags;return 0===arguments.length?!!(n&e):(this.flags=t?n|e:n&~e,this)}}v.targets=function(){return this._targets||(this._targets=l(g.id))},v.set=function(t){return this.value!==t?(this.value=t,1):0},v.skip=y(1),v.modified=y(2),v.parameters=function(t,r){r=!1!==r;var n,e,i,s,u=this,o=u._argval=u._argval||new c,a=u._argops=u._argops||[],l=[];function h(t,n,e){e instanceof p?(e!==u&&(r&&e.targets().add(u),l.push(e)),a.push({op:e,name:t,index:n})):o.set(t,n,e)}for(n in t)if(e=t[n],"pulse"===n)g.array(e).forEach(function(t){t instanceof p?t!==u&&(t.targets().add(u),l.push(t)):g.error("Pulse parameters must be operator instances.")}),u.source=e;else if(g.isArray(e))for(o.set(n,-1,Array(i=e.length)),s=0;s<i;++s)h(n,s,e[s]);else h(n,-1,e);return this.marshall().clear(),l},v.marshall=function(t){var n,e,r,i,s,u=this._argval||d,o=this._argops;if(o&&(r=o.length))for(e=0;e<r;++e)s=(i=(n=o[e]).op).modified()&&i.stamp===t,u.set(n.name,n.index,i.value,s);return u},v.evaluate=function(t){if(this._update){var n=this.marshall(t.stamp),e=this._update(n,t);if(n.clear(),e!==this.value)this.value=e;else if(!this.modified())return t.StopPropagation}},v.run=function(t){return t.stamp<=this.stamp?t.StopPropagation:(this.skip()?(this.skip(!1),n=0):n=this.evaluate(t),this.stamp=t.stamp,(this.pulse=n)||t);var n};var k=0;function F(t,n,e){this.id=++k,this.value=null,e&&(this.receive=e),t&&(this._filter=t),n&&(this._apply=n)}function w(t,n,e){return new F(t,n,e)}var A=F.prototype;A._filter=g.truthy,A._apply=g.identity,A.targets=function(){return this._targets||(this._targets=l(g.id))},A.consume=function(t){return arguments.length?(this._consume=!!t,this):!!this._consume},A.receive=function(t){if(this._filter(t)){for(var n=this.value=this._apply(t),e=this._targets,r=e?e.length:0,i=0;i<r;++i)e[i].receive(n);this._consume&&(t.preventDefault(),t.stopPropagation())}},A.filter=function(t){var n=w(t);return this.targets().add(n),n},A.apply=function(t){var n=w(null,t);return this.targets().add(n),n},A.merge=function(){var t=w();this.targets().add(t);for(var n=0,e=arguments.length;n<e;++n)arguments[n].targets().add(t);return t},A.throttle=function(n){var e=-1;return this.filter(function(){var t=Date.now();return n<t-e?(e=t,1):0})},A.debounce=function(t){var e=w();return this.targets().add(w(null,null,g.debounce(t,function(t){var n=t.dataflow;e.receive(t),n&&n.run&&n.run()}))),e},A.between=function(t,n){var e=!1;return t.targets().add(w(null,null,function(){e=!0})),n.targets().add(w(null,null,function(){e=!1})),this.filter(function(){return e})};var D={skip:!0};function O(r,t,i,n,e,s){var u,o,a=g.extend({},s,D);g.isFunction(i)||(i=g.constant(i)),void 0===n?u=function(t){r.touch(i(t))}:g.isFunction(n)?(o=new p(null,n,e,!1),u=function(t){var n,e=i(t);o.evaluate(t),h(n=o.value)?r.pulse(e,n,s):r.update(e,n,a)}):u=function(t){r.update(i(t),n,a)},t.apply(u)}function P(t,n,r,e,i,s){var u,o;void 0===e?o=r:(u=g.isFunction(e)?e:g.constant(e),(o=new p(null,e=r?function(t,n){var e=u(t,n);return r.skip()?e:r.skip(!0).value=e}:u,i,!1)).modified(s&&s.force),o.rank=0,r&&(o.skip(!0),o.value=r.value,o.targets().add(r))),n.targets().add(o)}var E={};function q(t,n,e){this.dataflow=t,this.stamp=null==n?-1:n,this.add=[],this.rem=[],this.mod=[],this.fields=null,this.encode=e||null}var b=q.prototype;function M(e,r){return e?function(t,n){return e(t,n)&&r(t,n)}:r}function S(t,n){var e=[];return g.visitArray(t,n,function(t){e.push(t)}),e}function L(t,n){var e={};return t.visit(n,function(t){e[m(t)]=1}),function(t){return e[m(t)]?null:t}}function R(t,n,e,r){var i,s,u,o,a,l=this,h=0;for(this.dataflow=t,this.stamp=n,this.fields=null,this.encode=r||null,u=0,o=(this.pulses=e).length;u<o;++u)if((i=e[u]).stamp===n){if(i.fields)for(a in s=l.fields||(l.fields={}),i.fields)s[a]=1;i.changed(l.ADD)&&(h|=l.ADD),i.changed(l.REM)&&(h|=l.REM),i.changed(l.MOD)&&(h|=l.MOD)}this.changes=h}b.StopPropagation=E,b.ADD=1,b.REM=2,b.MOD=4,b.ADD_REM=3,b.ADD_MOD=5,b.ALL=7,b.REFLOW=8,b.SOURCE=16,b.NO_SOURCE=32,b.NO_FIELDS=64,b.fork=function(t){return new q(this.dataflow).init(this,t)},b.clone=function(){var t=this.fork(7);return t.add=t.add.slice(),t.rem=t.rem.slice(),t.mod=t.mod.slice(),t.source&&(t.source=t.source.slice()),t.materialize(23)},b.addAll=function(){var t=this;return this.source&&this.source.length!==this.add.length&&((t=new q(this.dataflow).init(this)).add=t.source),t},b.init=function(t,n){var e=this;return e.stamp=t.stamp,e.encode=t.encode,!t.fields||64&n||(e.fields=t.fields),1&n?(e.addF=t.addF,e.add=t.add):(e.addF=null,e.add=[]),2&n?(e.remF=t.remF,e.rem=t.rem):(e.remF=null,e.rem=[]),4&n?(e.modF=t.modF,e.mod=t.mod):(e.modF=null,e.mod=[]),32&n?(e.srcF=null,e.source=null):(e.srcF=t.srcF,e.source=t.source),e},b.runAfter=function(t){this.dataflow.runAfter(t)},b.changed=function(t){var n=t||7;return 1&n&&this.add.length||2&n&&this.rem.length||4&n&&this.mod.length},b.reflow=function(t){if(t)return this.fork(7).reflow();var n=this.add.length,e=this.source&&this.source.length;return e&&e!==n&&(this.mod=this.source,n&&this.filter(4,L(this,1))),this},b.modifies=function(t){var n=g.array(t),e=this.fields||(this.fields={});return n.forEach(function(t){e[t]=!0}),this},b.modified=function(t){var n=this.fields;return!(!this.mod.length||!n)&&(arguments.length?g.isArray(t)?t.some(function(t){return n[t]}):n[t]:!!n)},b.filter=function(t,n){var e=this;return 1&t&&(e.addF=M(e.addF,n)),2&t&&(e.remF=M(e.remF,n)),4&t&&(e.modF=M(e.modF,n)),16&t&&(e.srcF=M(e.srcF,n)),e},b.materialize=function(t){var n=this;return 1&(t=t||7)&&n.addF&&(n.add=S(n.add,n.addF),n.addF=null),2&t&&n.remF&&(n.rem=S(n.rem,n.remF),n.remF=null),4&t&&n.modF&&(n.mod=S(n.mod,n.modF),n.modF=null),16&t&&n.srcF&&(n.source=n.source.filter(n.srcF),n.srcF=null),n},b.visit=function(t,n){var e,r,i=this,s=n;return 16&t?g.visitArray(i.source,i.srcF,s):(1&t&&g.visitArray(i.add,i.addF,s),2&t&&g.visitArray(i.rem,i.remF,s),4&t&&g.visitArray(i.mod,i.modF,s),8&t&&(e=i.source)&&((r=i.add.length+i.mod.length)===e.length||(r?g.visitArray(e,L(i,5),s):g.visitArray(e,i.srcF,s)))),i};var x=g.inherits(R,q);function T(n,t){try{t(n)}catch(t){n.error(t)}}x.fork=function(t){var n=new q(this.dataflow).init(this,t&this.NO_FIELDS);return void 0!==t&&(t&n.ADD&&this.visit(n.ADD,function(t){return n.add.push(t)}),t&n.REM&&this.visit(n.REM,function(t){return n.rem.push(t)}),t&n.MOD&&this.visit(n.MOD,function(t){return n.mod.push(t)})),n},x.changed=function(t){return this.changes&t},x.modified=function(t){var n=this.fields;return n&&this.changes&this.MOD?g.isArray(t)?t.some(function(t){return n[t]}):n[t]:0},x.filter=function(){g.error("MultiPulse does not support filtering.")},x.materialize=function(){g.error("MultiPulse does not support materialization.")};var z={skip:!(x.visit=function(t,n){var e=this.pulses,r=e.length,i=0;if(t&this.SOURCE)for(;i<r;++i)e[i].visit(t,n);else for(;i<r;++i)e[i].stamp===this.stamp&&e[i].visit(t,n);return this}),force:!1};function C(t){this.cmp=t,this.nodes=[]}var I=C.prototype;function U(t,n,e,r){var i,s,u;for(i=t[e];n<e&&r(i,s=t[u=e-1>>1])<0;)t[e]=s,e=u;return t[e]=i}function j(t,n,e){for(var r,i=n,s=t.length,u=t[n],o=2*n+1;o<s;)(r=o+1)<s&&0<=e(t[o],t[r])&&(o=r),t[n]=t[o],o=2*(n=o)+1;return t[n]=u,U(t,i,n,e)}function N(){this._log=g.logger(),this.logLevel(g.Error),this._clock=0,this._rank=0;try{this._loader=r.loader()}catch(t){}this._touched=l(g.id),this._pulses={},this._pulse=null,this._heap=new C(function(t,n){return t.qrank-n.qrank}),this._postrun=[]}I.size=function(){return this.nodes.length},I.clear=function(){return this.nodes=[],this},I.peek=function(){return this.nodes[0]},I.push=function(t){var n=this.nodes;return n.push(t),U(n,0,n.length-1,this.cmp)},I.pop=function(){var t,n=this.nodes,e=n.pop();return n.length?(t=n[0],n[0]=e,j(n,0,this.cmp)):t=e,t},I.replace=function(t){var n=this.nodes,e=n[0];return n[0]=t,j(n,0,this.cmp),e},I.pushpop=function(t){var n=this.nodes,e=n[0];return n.length&&this.cmp(e,t)<0&&(n[0]=t,t=e,j(n,0,this.cmp)),t};var G=N.prototype;function W(t){return function(){return this._log[t].apply(this,arguments)}}function B(t,n){p.call(this,t,null,n)}G.stamp=function(){return this._clock},G.loader=function(t){return arguments.length?(this._loader=t,this):this._loader},G.cleanThreshold=1e4,G.add=function(t,n,e,r){var i,s=1;return t instanceof p?i=t:t&&t.prototype instanceof p?i=new t:g.isFunction(t)?i=new p(null,t):(s=0,i=new p(t,n)),this.rank(i),s&&(r=e,e=n),e&&this.connect(i,i.parameters(e,r)),this.touch(i),i},G.connect=function(t,n){var e,r,i=t.rank;for(e=0,r=n.length;e<r;++e)if(i<n[e].rank)return void this.rerank(t)},G.rank=function(t){t.rank=++this._rank},G.rerank=function(t){for(var n,e,r,i=[t];i.length;)if(this.rank(n=i.pop()),e=n._targets)for(r=e.length;0<=--r;)i.push(n=e[r]),n===t&&g.error("Cycle detected in dataflow graph.")},G.pulse=function(t,n,e){this.touch(t,e||z);var r=new q(this,this._clock+(this._pulse?0:1)),i=t.pulse&&t.pulse.source||[];return r.target=t,this._pulses[t.id]=n.pulse(r,i),this},G.touch=function(t,n){var e=n||z;return this._pulse?this._enqueue(t):this._touched.add(t),e.skip&&t.skip(!0),this},G.update=function(t,n,e){var r=e||z;return(t.set(n)||r.force)&&this.touch(t,r),this},G.changeset=u,G.ingest=function(t,n,e){return this.pulse(t,this.changeset().insert(r.read(n,e)))},G.request=function(n,e,r){var t,i,s,u,o=this,a=o._pending||(t=o,(u=new Promise(function(t,n){i=t,s=n})).requests=0,u.done=function(){0==--u.requests&&t.runAfter(function(){t._pending=null;try{t.run(),i(t)}catch(t){s(t)}})},t._pending=u);a.requests+=1,o.loader().load(e,{context:"dataflow"}).then(function(t){o.ingest(n,t,r)},function(t){o.error("Loading failed",e,t)}).catch(function(t){o.error("Data ingestion failed",e,t)}).then(a.done,a.done)},G.events=function(t,n,e,r){for(var i,s=this,u=w(e,r),o=function(t){t.dataflow=s;try{u.receive(t)}catch(t){s.error(t)}finally{s.run()}},a=0,l=(i="string"==typeof t&&"undefined"!=typeof document?document.querySelectorAll(t):g.array(t)).length;a<l;++a)i[a].addEventListener(n,o);return u},G.on=function(t,n,e,r,i){return(t instanceof p?P:O)(this,t,n,e,r,i),this},G.run=function(t){var n,e,r,i,s=this,u=0,o=s.logLevel();if(s._pending)return s.info("Awaiting requests, delaying dataflow run."),0;if(s._pulse)return s.error("Dataflow invoked recursively. Use the runAfter method to queue invocation."),0;if(!s._touched.length)return s.info("Dataflow invoked, but nothing to do."),0;s._pulse=new q(s,++s._clock,t),o>=g.Info&&(r=Date.now(),s.debug("-- START PROPAGATION ("+s._clock+") -----")),s._touched.forEach(function(t){s._enqueue(t,!0)}),s._touched=l(g.id);try{for(;0<s._heap.size();)(n=s._heap.pop()).rank===n.qrank?(e=n.run(s._getPulse(n,t)),o>=g.Debug&&s.debug(n.id,e===E?"STOP":e,n),e!==E&&(s._pulse=e,n._targets&&n._targets.forEach(function(t){s._enqueue(t)})),++u):s._enqueue(n,!0)}catch(t){i=t}if(s._pulses={},s._pulse=null,o>=g.Info&&(r=Date.now()-r,s.info("> Pulse "+s._clock+": "+u+" operators; "+r+"ms")),i&&(s._postrun=[],s.error(i)),s._onrun)try{s._onrun(s,u,i)}catch(t){s.error(t)}if(s._postrun.length){var a=s._postrun;s._postrun=[],a.sort(function(t,n){return n.priority-t.priority}).forEach(function(t){T(s,t.callback)})}return u},G.runAsync=function(){return this._pending||Promise.resolve(this.run())},G.runAfter=function(t,n,e){this._pulse||n?this._postrun.push({priority:e||0,callback:t}):T(this,t)},G._enqueue=function(t,n){var e=!this._pulses[t.id];e&&(this._pulses[t.id]=this._pulse),(e||n)&&(t.qrank=t.rank,this._heap.push(t))},G._getPulse=function(t,n){var e,r=t.source,i=this._clock;return r&&g.isArray(r)?new R(this,i,e=r.map(function(t){return t.pulse}),n):(e=this._pulses[t.id],r&&((r=r.pulse)&&r!==E?r.stamp===i&&e.target!==t?e=r:e.source=r.source:e.source=[]),e)},G.error=W("error"),G.warn=W("warn"),G.info=W("info"),G.debug=W("debug"),G.logLevel=W("level");var H=g.inherits(B,p);H.run=function(t){return t.stamp<=this.stamp?t.StopPropagation:(this.skip()?this.skip(!1):n=this.evaluate(t),(n=n||t)!==t.StopPropagation&&(this.pulse=n),this.stamp=t.stamp,n);var n},H.evaluate=function(t){var n=this.marshall(t.stamp),e=this.transform(n,t);return n.clear(),e},H.transform=function(){};var J={};function K(t){return t=t&&t.toLowerCase(),J.hasOwnProperty(t)?J[t]:null}t.UniqueList=l,t.changeset=u,t.isChangeSet=h,t.Dataflow=N,t.EventStream=F,t.Parameters=c,t.Pulse=q,t.MultiPulse=R,t.Operator=p,t.Transform=B,t.derive=function(t){return n(t,_({}))},t.rederive=n,t.ingest=_,t.isTuple=function(t){return!(!t||!m(t))},t.replace=function(t,n){return s(n,m(t))},t.tupleid=m,t.definition=function(t){var n=K(t);return n&&n.Definition||null},t.transform=K,t.transforms=J,Object.defineProperty(t,"__esModule",{value:!0})}); |
{ | ||
"name": "vega-dataflow", | ||
"version": "3.1.0", | ||
"version": "4.0.0", | ||
"description": "Reactive dataflow processing.", | ||
@@ -32,8 +32,8 @@ "keywords": [ | ||
"dependencies": { | ||
"vega-loader": "2", | ||
"vega-util": "1" | ||
"vega-loader": "^3.0.0", | ||
"vega-util": "^1.7.0" | ||
}, | ||
"devDependencies": { | ||
"eslint": "4", | ||
"rollup": "0.43", | ||
"rollup": "0.58.2", | ||
"tape": "4", | ||
@@ -40,0 +40,0 @@ "uglify-js": "3" |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
141859
3537
+ Addednode-fetch@2.7.0(transitive)
+ Addedtr46@0.0.3(transitive)
+ Addedvega-loader@3.1.0(transitive)
+ Addedwebidl-conversions@3.0.1(transitive)
+ Addedwhatwg-url@5.0.0(transitive)
- Removedd3-collection@1.0.7(transitive)
- Removedd3-dispatch@1.0.6(transitive)
- Removedd3-request@1.0.6(transitive)
- Removedvega-loader@2.1.0(transitive)
- Removedxmlhttprequest@1.8.0(transitive)
Updatedvega-loader@^3.0.0
Updatedvega-util@^1.7.0