You've already forked wakapi-readme-stats
Bar graph added.
This commit is contained in:
139
node_modules/vega-parser/src/DataScope.js
generated
vendored
Normal file
139
node_modules/vega-parser/src/DataScope.js
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
import {Aggregate, Collect} from './transforms';
|
||||
import {aggrField, entry, keyFieldRef, ref, sortKey} from './util';
|
||||
import {isString} from 'vega-util';
|
||||
|
||||
export default function DataScope(scope, input, output, values, aggr) {
|
||||
this.scope = scope; // parent scope object
|
||||
this.input = input; // first operator in pipeline (tuple input)
|
||||
this.output = output; // last operator in pipeline (tuple output)
|
||||
this.values = values; // operator for accessing tuples (but not tuple flow)
|
||||
|
||||
// last aggregate in transform pipeline
|
||||
this.aggregate = aggr;
|
||||
|
||||
// lookup table of field indices
|
||||
this.index = {};
|
||||
}
|
||||
|
||||
DataScope.fromEntries = function(scope, entries) {
|
||||
var n = entries.length,
|
||||
i = 1,
|
||||
input = entries[0],
|
||||
values = entries[n-1],
|
||||
output = entries[n-2],
|
||||
aggr = null;
|
||||
|
||||
if (input && input.type === 'load') {
|
||||
input = entries[1];
|
||||
}
|
||||
|
||||
// add operator entries to this scope, wire up pulse chain
|
||||
scope.add(entries[0]);
|
||||
for (; i<n; ++i) {
|
||||
entries[i].params.pulse = ref(entries[i-1]);
|
||||
scope.add(entries[i]);
|
||||
if (entries[i].type === 'aggregate') aggr = entries[i];
|
||||
}
|
||||
|
||||
return new DataScope(scope, input, output, values, aggr);
|
||||
};
|
||||
|
||||
var prototype = DataScope.prototype;
|
||||
|
||||
prototype.countsRef = function(scope, field, sort) {
|
||||
var ds = this,
|
||||
cache = ds.counts || (ds.counts = {}),
|
||||
k = fieldKey(field), v, a, p;
|
||||
|
||||
if (k != null) {
|
||||
scope = ds.scope;
|
||||
v = cache[k];
|
||||
}
|
||||
|
||||
if (!v) {
|
||||
p = {
|
||||
groupby: scope.fieldRef(field, 'key'),
|
||||
pulse: ref(ds.output)
|
||||
};
|
||||
if (sort && sort.field) addSortField(scope, p, sort);
|
||||
a = scope.add(Aggregate(p));
|
||||
v = scope.add(Collect({pulse: ref(a)}));
|
||||
v = {agg: a, ref: ref(v)};
|
||||
if (k != null) cache[k] = v;
|
||||
} else if (sort && sort.field) {
|
||||
addSortField(scope, v.agg.params, sort);
|
||||
}
|
||||
|
||||
return v.ref;
|
||||
};
|
||||
|
||||
function fieldKey(field) {
|
||||
return isString(field) ? field : null;
|
||||
}
|
||||
|
||||
function addSortField(scope, p, sort) {
|
||||
var as = aggrField(sort.op, sort.field), s;
|
||||
|
||||
if (p.ops) {
|
||||
for (var i=0, n=p.as.length; i<n; ++i) {
|
||||
if (p.as[i] === as) return;
|
||||
}
|
||||
} else {
|
||||
p.ops = ['count'];
|
||||
p.fields = [null];
|
||||
p.as = ['count'];
|
||||
}
|
||||
if (sort.op) {
|
||||
p.ops.push((s=sort.op.signal) ? scope.signalRef(s) : sort.op);
|
||||
p.fields.push(scope.fieldRef(sort.field));
|
||||
p.as.push(as);
|
||||
}
|
||||
}
|
||||
|
||||
function cache(scope, ds, name, optype, field, counts, index) {
|
||||
var cache = ds[name] || (ds[name] = {}),
|
||||
sort = sortKey(counts),
|
||||
k = fieldKey(field), v, op;
|
||||
|
||||
if (k != null) {
|
||||
scope = ds.scope;
|
||||
k = k + (sort ? '|' + sort : '');
|
||||
v = cache[k];
|
||||
}
|
||||
|
||||
if (!v) {
|
||||
var params = counts
|
||||
? {field: keyFieldRef, pulse: ds.countsRef(scope, field, counts)}
|
||||
: {field: scope.fieldRef(field), pulse: ref(ds.output)};
|
||||
if (sort) params.sort = scope.sortRef(counts);
|
||||
op = scope.add(entry(optype, undefined, params));
|
||||
if (index) ds.index[field] = op;
|
||||
v = ref(op);
|
||||
if (k != null) cache[k] = v;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
prototype.tuplesRef = function() {
|
||||
return ref(this.values);
|
||||
};
|
||||
|
||||
prototype.extentRef = function(scope, field) {
|
||||
return cache(scope, this, 'extent', 'extent', field, false);
|
||||
};
|
||||
|
||||
prototype.domainRef = function(scope, field) {
|
||||
return cache(scope, this, 'domain', 'values', field, false);
|
||||
};
|
||||
|
||||
prototype.valuesRef = function(scope, field, sort) {
|
||||
return cache(scope, this, 'vals', 'values', field, sort || true);
|
||||
};
|
||||
|
||||
prototype.lookupRef = function(scope, field) {
|
||||
return cache(scope, this, 'lookup', 'tupleindex', field, false);
|
||||
};
|
||||
|
||||
prototype.indataRef = function(scope, field) {
|
||||
return cache(scope, this, 'indata', 'tupleindex', field, true, true);
|
||||
};
|
||||
453
node_modules/vega-parser/src/Scope.js
generated
vendored
Normal file
453
node_modules/vega-parser/src/Scope.js
generated
vendored
Normal file
@@ -0,0 +1,453 @@
|
||||
import DataScope from './DataScope';
|
||||
|
||||
import {
|
||||
Compare, Expression, Field, Key, Projection, Proxy, Scale, Sieve
|
||||
} from './transforms';
|
||||
|
||||
import {
|
||||
Ascending, Entry, aggrField, compareRef, fieldRef, isExpr,
|
||||
isSignal, keyRef, operator, ref
|
||||
} from './util';
|
||||
|
||||
import parseScope from './parsers/scope';
|
||||
import {parseExpression} from 'vega-functions';
|
||||
|
||||
import {
|
||||
array, error, extend, hasOwnProperty,
|
||||
isArray, isObject, isString, peek, stringValue
|
||||
} from 'vega-util';
|
||||
|
||||
export default function Scope(config, options) {
|
||||
this.config = config || {};
|
||||
this.options = options || {};
|
||||
|
||||
this.bindings = [];
|
||||
this.field = {};
|
||||
this.signals = {};
|
||||
this.lambdas = {};
|
||||
this.scales = {};
|
||||
this.events = {};
|
||||
this.data = {};
|
||||
|
||||
this.streams = [];
|
||||
this.updates = [];
|
||||
this.operators = [];
|
||||
this.eventConfig = null;
|
||||
this.locale = null;
|
||||
|
||||
this._id = 0;
|
||||
this._subid = 0;
|
||||
this._nextsub = [0];
|
||||
|
||||
this._parent = [];
|
||||
this._encode = [];
|
||||
this._lookup = [];
|
||||
this._markpath = [];
|
||||
}
|
||||
|
||||
function Subscope(scope) {
|
||||
this.config = scope.config;
|
||||
this.options = scope.options;
|
||||
this.legends = scope.legends;
|
||||
|
||||
this.field = Object.create(scope.field);
|
||||
this.signals = Object.create(scope.signals);
|
||||
this.lambdas = Object.create(scope.lambdas);
|
||||
this.scales = Object.create(scope.scales);
|
||||
this.events = Object.create(scope.events);
|
||||
this.data = Object.create(scope.data);
|
||||
|
||||
this.streams = [];
|
||||
this.updates = [];
|
||||
this.operators = [];
|
||||
|
||||
this._id = 0;
|
||||
this._subid = ++scope._nextsub[0];
|
||||
this._nextsub = scope._nextsub;
|
||||
|
||||
this._parent = scope._parent.slice();
|
||||
this._encode = scope._encode.slice();
|
||||
this._lookup = scope._lookup.slice();
|
||||
this._markpath = scope._markpath;
|
||||
}
|
||||
|
||||
var prototype = Scope.prototype = Subscope.prototype;
|
||||
|
||||
// ----
|
||||
|
||||
prototype.parse = function(spec) {
|
||||
return parseScope(spec, this);
|
||||
};
|
||||
|
||||
prototype.fork = function() {
|
||||
return new Subscope(this);
|
||||
};
|
||||
|
||||
prototype.isSubscope = function() {
|
||||
return this._subid > 0;
|
||||
};
|
||||
|
||||
prototype.toRuntime = function() {
|
||||
this.finish();
|
||||
return {
|
||||
description: this.description,
|
||||
operators: this.operators,
|
||||
streams: this.streams,
|
||||
updates: this.updates,
|
||||
bindings: this.bindings,
|
||||
eventConfig: this.eventConfig,
|
||||
locale: this.locale
|
||||
};
|
||||
};
|
||||
|
||||
prototype.id = function() {
|
||||
return (this._subid ? this._subid + ':' : 0) + this._id++;
|
||||
};
|
||||
|
||||
prototype.add = function(op) {
|
||||
this.operators.push(op);
|
||||
op.id = this.id();
|
||||
// if pre-registration references exist, resolve them now
|
||||
if (op.refs) {
|
||||
op.refs.forEach(function(ref) { ref.$ref = op.id; });
|
||||
op.refs = null;
|
||||
}
|
||||
return op;
|
||||
};
|
||||
|
||||
prototype.proxy = function(op) {
|
||||
var vref = op instanceof Entry ? ref(op) : op;
|
||||
return this.add(Proxy({value: vref}));
|
||||
};
|
||||
|
||||
prototype.addStream = function(stream) {
|
||||
this.streams.push(stream);
|
||||
stream.id = this.id();
|
||||
return stream;
|
||||
};
|
||||
|
||||
prototype.addUpdate = function(update) {
|
||||
this.updates.push(update);
|
||||
return update;
|
||||
};
|
||||
|
||||
// Apply metadata
|
||||
prototype.finish = function() {
|
||||
var name, ds;
|
||||
|
||||
// annotate root
|
||||
if (this.root) this.root.root = true;
|
||||
|
||||
// annotate signals
|
||||
for (name in this.signals) {
|
||||
this.signals[name].signal = name;
|
||||
}
|
||||
|
||||
// annotate scales
|
||||
for (name in this.scales) {
|
||||
this.scales[name].scale = name;
|
||||
}
|
||||
|
||||
// annotate data sets
|
||||
function annotate(op, name, type) {
|
||||
var data, list;
|
||||
if (op) {
|
||||
data = op.data || (op.data = {});
|
||||
list = data[name] || (data[name] = []);
|
||||
list.push(type);
|
||||
}
|
||||
}
|
||||
for (name in this.data) {
|
||||
ds = this.data[name];
|
||||
annotate(ds.input, name, 'input');
|
||||
annotate(ds.output, name, 'output');
|
||||
annotate(ds.values, name, 'values');
|
||||
for (var field in ds.index) {
|
||||
annotate(ds.index[field], name, 'index:' + field);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// ----
|
||||
|
||||
prototype.pushState = function(encode, parent, lookup) {
|
||||
this._encode.push(ref(this.add(Sieve({pulse: encode}))));
|
||||
this._parent.push(parent);
|
||||
this._lookup.push(lookup ? ref(this.proxy(lookup)) : null);
|
||||
this._markpath.push(-1);
|
||||
};
|
||||
|
||||
prototype.popState = function() {
|
||||
this._encode.pop();
|
||||
this._parent.pop();
|
||||
this._lookup.pop();
|
||||
this._markpath.pop();
|
||||
};
|
||||
|
||||
prototype.parent = function() {
|
||||
return peek(this._parent);
|
||||
};
|
||||
|
||||
prototype.encode = function() {
|
||||
return peek(this._encode);
|
||||
};
|
||||
|
||||
prototype.lookup = function() {
|
||||
return peek(this._lookup);
|
||||
};
|
||||
|
||||
prototype.markpath = function() {
|
||||
var p = this._markpath;
|
||||
return ++p[p.length-1];
|
||||
};
|
||||
|
||||
// ----
|
||||
|
||||
prototype.fieldRef = function(field, name) {
|
||||
if (isString(field)) return fieldRef(field, name);
|
||||
if (!field.signal) {
|
||||
error('Unsupported field reference: ' + stringValue(field));
|
||||
}
|
||||
|
||||
var s = field.signal,
|
||||
f = this.field[s],
|
||||
params;
|
||||
|
||||
if (!f) {
|
||||
params = {name: this.signalRef(s)};
|
||||
if (name) params.as = name;
|
||||
this.field[s] = f = ref(this.add(Field(params)));
|
||||
}
|
||||
return f;
|
||||
};
|
||||
|
||||
prototype.compareRef = function(cmp) {
|
||||
function check(_) {
|
||||
if (isSignal(_)) {
|
||||
signal = true;
|
||||
return scope.signalRef(_.signal);
|
||||
} else if (isExpr(_)) {
|
||||
signal = true;
|
||||
return scope.exprRef(_.expr);
|
||||
} else {
|
||||
return _;
|
||||
}
|
||||
}
|
||||
|
||||
var scope = this,
|
||||
signal = false,
|
||||
fields = array(cmp.field).map(check),
|
||||
orders = array(cmp.order).map(check);
|
||||
|
||||
return signal
|
||||
? ref(this.add(Compare({fields: fields, orders: orders})))
|
||||
: compareRef(fields, orders);
|
||||
};
|
||||
|
||||
prototype.keyRef = function(fields, flat) {
|
||||
function check(_) {
|
||||
if (isSignal(_)) {
|
||||
signal = true;
|
||||
return ref(sig[_.signal]);
|
||||
} else {
|
||||
return _;
|
||||
}
|
||||
}
|
||||
|
||||
var sig = this.signals,
|
||||
signal = false;
|
||||
fields = array(fields).map(check);
|
||||
|
||||
return signal
|
||||
? ref(this.add(Key({fields: fields, flat: flat})))
|
||||
: keyRef(fields, flat);
|
||||
};
|
||||
|
||||
prototype.sortRef = function(sort) {
|
||||
if (!sort) return sort;
|
||||
|
||||
// including id ensures stable sorting
|
||||
var a = aggrField(sort.op, sort.field),
|
||||
o = sort.order || Ascending;
|
||||
|
||||
return o.signal
|
||||
? ref(this.add(Compare({
|
||||
fields: a,
|
||||
orders: this.signalRef(o.signal)
|
||||
})))
|
||||
: compareRef(a, o);
|
||||
};
|
||||
|
||||
// ----
|
||||
|
||||
prototype.event = function(source, type) {
|
||||
var key = source + ':' + type;
|
||||
if (!this.events[key]) {
|
||||
var id = this.id();
|
||||
this.streams.push({
|
||||
id: id,
|
||||
source: source,
|
||||
type: type
|
||||
});
|
||||
this.events[key] = id;
|
||||
}
|
||||
return this.events[key];
|
||||
};
|
||||
|
||||
// ----
|
||||
|
||||
prototype.hasOwnSignal = function(name) {
|
||||
return hasOwnProperty(this.signals, name);
|
||||
};
|
||||
|
||||
prototype.addSignal = function(name, value) {
|
||||
if (this.hasOwnSignal(name)) {
|
||||
error('Duplicate signal name: ' + stringValue(name));
|
||||
}
|
||||
var op = value instanceof Entry ? value : this.add(operator(value));
|
||||
return this.signals[name] = op;
|
||||
};
|
||||
|
||||
prototype.getSignal = function(name) {
|
||||
if (!this.signals[name]) {
|
||||
error('Unrecognized signal name: ' + stringValue(name));
|
||||
}
|
||||
return this.signals[name];
|
||||
};
|
||||
|
||||
prototype.signalRef = function(s) {
|
||||
if (this.signals[s]) {
|
||||
return ref(this.signals[s]);
|
||||
} else if (!hasOwnProperty(this.lambdas, s)) {
|
||||
this.lambdas[s] = this.add(operator(null));
|
||||
}
|
||||
return ref(this.lambdas[s]);
|
||||
};
|
||||
|
||||
prototype.parseLambdas = function() {
|
||||
var code = Object.keys(this.lambdas);
|
||||
for (var i=0, n=code.length; i<n; ++i) {
|
||||
var s = code[i],
|
||||
e = parseExpression(s, this),
|
||||
op = this.lambdas[s];
|
||||
op.params = e.$params;
|
||||
op.update = e.$expr;
|
||||
}
|
||||
};
|
||||
|
||||
prototype.property = function(spec) {
|
||||
return spec && spec.signal ? this.signalRef(spec.signal) : spec;
|
||||
};
|
||||
|
||||
prototype.objectProperty = function(spec) {
|
||||
return (!spec || !isObject(spec)) ? spec
|
||||
: this.signalRef(spec.signal || propertyLambda(spec));
|
||||
};
|
||||
|
||||
function propertyLambda(spec) {
|
||||
return (isArray(spec) ? arrayLambda : objectLambda)(spec);
|
||||
}
|
||||
|
||||
function arrayLambda(array) {
|
||||
var code = '[',
|
||||
i = 0,
|
||||
n = array.length,
|
||||
value;
|
||||
|
||||
for (; i<n; ++i) {
|
||||
value = array[i];
|
||||
code += (i > 0 ? ',' : '')
|
||||
+ (isObject(value)
|
||||
? (value.signal || propertyLambda(value))
|
||||
: stringValue(value));
|
||||
}
|
||||
return code + ']';
|
||||
}
|
||||
|
||||
function objectLambda(obj) {
|
||||
var code = '{',
|
||||
i = 0,
|
||||
key, value;
|
||||
|
||||
for (key in obj) {
|
||||
value = obj[key];
|
||||
code += (++i > 1 ? ',' : '')
|
||||
+ stringValue(key) + ':'
|
||||
+ (isObject(value)
|
||||
? (value.signal || propertyLambda(value))
|
||||
: stringValue(value));
|
||||
}
|
||||
return code + '}';
|
||||
}
|
||||
|
||||
prototype.exprRef = function(code, name) {
|
||||
var params = {expr: parseExpression(code, this)};
|
||||
if (name) params.expr.$name = name;
|
||||
return ref(this.add(Expression(params)));
|
||||
};
|
||||
|
||||
prototype.addBinding = function(name, bind) {
|
||||
if (!this.bindings) {
|
||||
error('Nested signals do not support binding: ' + stringValue(name));
|
||||
}
|
||||
this.bindings.push(extend({signal: name}, bind));
|
||||
};
|
||||
|
||||
// ----
|
||||
|
||||
prototype.addScaleProj = function(name, transform) {
|
||||
if (hasOwnProperty(this.scales, name)) {
|
||||
error('Duplicate scale or projection name: ' + stringValue(name));
|
||||
}
|
||||
this.scales[name] = this.add(transform);
|
||||
};
|
||||
|
||||
prototype.addScale = function(name, params) {
|
||||
this.addScaleProj(name, Scale(params));
|
||||
};
|
||||
|
||||
prototype.addProjection = function(name, params) {
|
||||
this.addScaleProj(name, Projection(params));
|
||||
};
|
||||
|
||||
prototype.getScale = function(name) {
|
||||
if (!this.scales[name]) {
|
||||
error('Unrecognized scale name: ' + stringValue(name));
|
||||
}
|
||||
return this.scales[name];
|
||||
};
|
||||
|
||||
prototype.projectionRef =
|
||||
prototype.scaleRef = function(name) {
|
||||
return ref(this.getScale(name));
|
||||
};
|
||||
|
||||
prototype.projectionType =
|
||||
prototype.scaleType = function(name) {
|
||||
return this.getScale(name).params.type;
|
||||
};
|
||||
|
||||
// ----
|
||||
|
||||
prototype.addData = function(name, dataScope) {
|
||||
if (hasOwnProperty(this.data, name)) {
|
||||
error('Duplicate data set name: ' + stringValue(name));
|
||||
}
|
||||
return (this.data[name] = dataScope);
|
||||
};
|
||||
|
||||
prototype.getData = function(name) {
|
||||
if (!this.data[name]) {
|
||||
error('Undefined data set name: ' + stringValue(name));
|
||||
}
|
||||
return this.data[name];
|
||||
};
|
||||
|
||||
prototype.addDataPipeline = function(name, entries) {
|
||||
if (hasOwnProperty(this.data, name)) {
|
||||
error('Duplicate data set name: ' + stringValue(name));
|
||||
}
|
||||
return this.addData(name, DataScope.fromEntries(this, entries));
|
||||
};
|
||||
241
node_modules/vega-parser/src/config.js
generated
vendored
Normal file
241
node_modules/vega-parser/src/config.js
generated
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
/**
|
||||
* Standard configuration defaults for Vega specification parsing.
|
||||
* Users can provide their own (sub-)set of these default values
|
||||
* by passing in a config object to the top-level parse method.
|
||||
*/
|
||||
export default function() {
|
||||
const defaultFont = 'sans-serif',
|
||||
defaultSymbolSize = 30,
|
||||
defaultStrokeWidth = 2,
|
||||
defaultColor = '#4c78a8',
|
||||
black = '#000',
|
||||
gray = '#888',
|
||||
lightGray = '#ddd';
|
||||
|
||||
return {
|
||||
// default visualization description
|
||||
description: 'Vega visualization',
|
||||
|
||||
// default padding around visualization
|
||||
padding: 0,
|
||||
|
||||
// default for automatic sizing; options: 'none', 'pad', 'fit'
|
||||
// or provide an object (e.g., {'type': 'pad', 'resize': true})
|
||||
autosize: 'pad',
|
||||
|
||||
// default view background color
|
||||
// covers the entire view component
|
||||
background: null,
|
||||
|
||||
// default event handling configuration
|
||||
// preventDefault for view-sourced event types except 'wheel'
|
||||
events: {
|
||||
defaults: {allow: ['wheel']}
|
||||
},
|
||||
|
||||
// defaults for top-level group marks
|
||||
// accepts mark properties (fill, stroke, etc)
|
||||
// covers the data rectangle within group width/height
|
||||
group: null,
|
||||
|
||||
// defaults for basic mark types
|
||||
// each subset accepts mark properties (fill, stroke, etc)
|
||||
mark: null,
|
||||
arc: {
|
||||
fill: defaultColor
|
||||
},
|
||||
area: {
|
||||
fill: defaultColor
|
||||
},
|
||||
image: null,
|
||||
line: {
|
||||
stroke: defaultColor,
|
||||
strokeWidth: defaultStrokeWidth
|
||||
},
|
||||
path: {
|
||||
stroke: defaultColor
|
||||
},
|
||||
rect: {
|
||||
fill: defaultColor
|
||||
},
|
||||
rule: {
|
||||
stroke: black
|
||||
},
|
||||
shape: {
|
||||
stroke: defaultColor
|
||||
},
|
||||
symbol: {
|
||||
fill: defaultColor,
|
||||
size: 64
|
||||
},
|
||||
text: {
|
||||
fill: black,
|
||||
font: defaultFont,
|
||||
fontSize: 11
|
||||
},
|
||||
trail: {
|
||||
fill: defaultColor,
|
||||
size: defaultStrokeWidth
|
||||
},
|
||||
|
||||
// style definitions
|
||||
style: {
|
||||
// axis & legend labels
|
||||
'guide-label': {
|
||||
fill: black,
|
||||
font: defaultFont,
|
||||
fontSize: 10
|
||||
},
|
||||
// axis & legend titles
|
||||
'guide-title': {
|
||||
fill: black,
|
||||
font: defaultFont,
|
||||
fontSize: 11,
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
// headers, including chart title
|
||||
'group-title': {
|
||||
fill: black,
|
||||
font: defaultFont,
|
||||
fontSize: 13,
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
// chart subtitle
|
||||
'group-subtitle': {
|
||||
fill: black,
|
||||
font: defaultFont,
|
||||
fontSize: 12
|
||||
},
|
||||
// defaults for styled point marks in Vega-Lite
|
||||
point: {
|
||||
size: defaultSymbolSize,
|
||||
strokeWidth: defaultStrokeWidth,
|
||||
shape: 'circle'
|
||||
},
|
||||
circle: {
|
||||
size: defaultSymbolSize,
|
||||
strokeWidth: defaultStrokeWidth
|
||||
},
|
||||
square: {
|
||||
size: defaultSymbolSize,
|
||||
strokeWidth: defaultStrokeWidth,
|
||||
shape: 'square'
|
||||
},
|
||||
// defaults for styled group marks in Vega-Lite
|
||||
cell: {
|
||||
fill: 'transparent',
|
||||
stroke: lightGray
|
||||
}
|
||||
},
|
||||
|
||||
// defaults for title
|
||||
title: {
|
||||
orient: 'top',
|
||||
anchor: 'middle',
|
||||
offset: 4,
|
||||
subtitlePadding: 3
|
||||
},
|
||||
|
||||
// defaults for axes
|
||||
axis: {
|
||||
minExtent: 0,
|
||||
maxExtent: 200,
|
||||
bandPosition: 0.5,
|
||||
domain: true,
|
||||
domainWidth: 1,
|
||||
domainColor: gray,
|
||||
grid: false,
|
||||
gridWidth: 1,
|
||||
gridColor: lightGray,
|
||||
labels: true,
|
||||
labelAngle: 0,
|
||||
labelLimit: 180,
|
||||
labelOffset: 0,
|
||||
labelPadding: 2,
|
||||
ticks: true,
|
||||
tickColor: gray,
|
||||
tickOffset: 0,
|
||||
tickRound: true,
|
||||
tickSize: 5,
|
||||
tickWidth: 1,
|
||||
titlePadding: 4
|
||||
},
|
||||
|
||||
// correction for centering bias
|
||||
axisBand: {
|
||||
tickOffset: -0.5
|
||||
},
|
||||
|
||||
// defaults for cartographic projection
|
||||
projection: {
|
||||
type: 'mercator'
|
||||
},
|
||||
|
||||
// defaults for legends
|
||||
legend: {
|
||||
orient: 'right',
|
||||
padding: 0,
|
||||
gridAlign: 'each',
|
||||
columnPadding: 10,
|
||||
rowPadding: 2,
|
||||
symbolDirection: 'vertical',
|
||||
gradientDirection: 'vertical',
|
||||
gradientLength: 200,
|
||||
gradientThickness: 16,
|
||||
gradientStrokeColor: lightGray,
|
||||
gradientStrokeWidth: 0,
|
||||
gradientLabelOffset: 2,
|
||||
labelAlign: 'left',
|
||||
labelBaseline: 'middle',
|
||||
labelLimit: 160,
|
||||
labelOffset: 4,
|
||||
labelOverlap: true,
|
||||
symbolLimit: 30,
|
||||
symbolType: 'circle',
|
||||
symbolSize: 100,
|
||||
symbolOffset: 0,
|
||||
symbolStrokeWidth: 1.5,
|
||||
symbolBaseFillColor: 'transparent',
|
||||
symbolBaseStrokeColor: gray,
|
||||
titleLimit: 180,
|
||||
titleOrient: 'top',
|
||||
titlePadding: 5,
|
||||
layout: {
|
||||
offset: 18,
|
||||
direction: 'horizontal',
|
||||
left: { direction: 'vertical' },
|
||||
right: { direction: 'vertical' }
|
||||
}
|
||||
},
|
||||
|
||||
// defaults for scale ranges
|
||||
range: {
|
||||
category: {
|
||||
scheme: 'tableau10'
|
||||
},
|
||||
ordinal: {
|
||||
scheme: 'blues'
|
||||
},
|
||||
heatmap: {
|
||||
scheme: 'yellowgreenblue'
|
||||
},
|
||||
ramp: {
|
||||
scheme: 'blues'
|
||||
},
|
||||
diverging: {
|
||||
scheme: 'blueorange',
|
||||
extent: [1, 0]
|
||||
},
|
||||
symbol: [
|
||||
'circle',
|
||||
'square',
|
||||
'triangle-up',
|
||||
'cross',
|
||||
'diamond',
|
||||
'triangle-right',
|
||||
'triangle-down',
|
||||
'triangle-left'
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
13
node_modules/vega-parser/src/parse.js
generated
vendored
Normal file
13
node_modules/vega-parser/src/parse.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import parseView from './parsers/view';
|
||||
import Scope from './Scope';
|
||||
import defaults from './config';
|
||||
import {error, isObject, mergeConfig} from 'vega-util';
|
||||
|
||||
export default function(spec, config, options) {
|
||||
if (!isObject(spec)) {
|
||||
error('Input Vega specification must be an object.');
|
||||
}
|
||||
|
||||
config = mergeConfig(defaults(), config, spec.config);
|
||||
return parseView(spec, new Scope(config, options)).toRuntime();
|
||||
}
|
||||
5
node_modules/vega-parser/src/parsers/autosize.js
generated
vendored
Normal file
5
node_modules/vega-parser/src/parsers/autosize.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import {isObject} from 'vega-util';
|
||||
|
||||
export default function(spec) {
|
||||
return isObject(spec) ? spec : {type: spec || 'pad'};
|
||||
}
|
||||
121
node_modules/vega-parser/src/parsers/axis.js
generated
vendored
Normal file
121
node_modules/vega-parser/src/parsers/axis.js
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
import {addEncoders, extendEncode} from './encode/util';
|
||||
import axisConfig from './guides/axis-config';
|
||||
import axisDomain from './guides/axis-domain';
|
||||
import axisGrid from './guides/axis-grid';
|
||||
import axisTicks from './guides/axis-ticks';
|
||||
import axisLabels from './guides/axis-labels';
|
||||
import axisTitle from './guides/axis-title';
|
||||
import {Skip} from './guides/constants';
|
||||
import guideGroup from './guides/guide-group';
|
||||
import {lookup, tickBand} from './guides/guide-util';
|
||||
import {AxisRole} from './marks/roles';
|
||||
import parseMark from './mark';
|
||||
import {AxisTicks, Collect} from '../transforms';
|
||||
import {ref, value} from '../util';
|
||||
|
||||
export default function(spec, scope) {
|
||||
var config = axisConfig(spec, scope),
|
||||
encode = spec.encode || {},
|
||||
axisEncode = encode.axis || {},
|
||||
name = axisEncode.name || undefined,
|
||||
interactive = axisEncode.interactive,
|
||||
style = axisEncode.style,
|
||||
_ = lookup(spec, config),
|
||||
band = tickBand(_),
|
||||
datum, dataRef, ticksRef, size, children;
|
||||
|
||||
// single-element data source for axis group
|
||||
datum = {
|
||||
scale: spec.scale,
|
||||
ticks: !!_('ticks'),
|
||||
labels: !!_('labels'),
|
||||
grid: !!_('grid'),
|
||||
domain: !!_('domain'),
|
||||
title: spec.title != null
|
||||
};
|
||||
dataRef = ref(scope.add(Collect({}, [datum])));
|
||||
|
||||
// encoding properties for axis group item
|
||||
axisEncode = extendEncode(
|
||||
buildAxisEncode(_, spec), axisEncode, Skip
|
||||
);
|
||||
|
||||
// data source for axis ticks
|
||||
ticksRef = ref(scope.add(AxisTicks({
|
||||
scale: scope.scaleRef(spec.scale),
|
||||
extra: scope.property(band.extra),
|
||||
count: scope.objectProperty(spec.tickCount),
|
||||
values: scope.objectProperty(spec.values),
|
||||
minstep: scope.property(spec.tickMinStep),
|
||||
formatType: scope.property(spec.formatType),
|
||||
formatSpecifier: scope.property(spec.format)
|
||||
})));
|
||||
|
||||
// generate axis marks
|
||||
children = [];
|
||||
|
||||
// include axis gridlines if requested
|
||||
if (datum.grid) {
|
||||
children.push(axisGrid(spec, config, encode.grid, ticksRef, band));
|
||||
}
|
||||
|
||||
// include axis ticks if requested
|
||||
if (datum.ticks) {
|
||||
size = _('tickSize');
|
||||
children.push(axisTicks(spec, config, encode.ticks, ticksRef, size, band));
|
||||
}
|
||||
|
||||
// include axis labels if requested
|
||||
if (datum.labels) {
|
||||
size = datum.ticks ? size : 0;
|
||||
children.push(axisLabels(spec, config, encode.labels, ticksRef, size, band));
|
||||
}
|
||||
|
||||
// include axis domain path if requested
|
||||
if (datum.domain) {
|
||||
children.push(axisDomain(spec, config, encode.domain, dataRef));
|
||||
}
|
||||
|
||||
// include axis title if defined
|
||||
if (datum.title) {
|
||||
children.push(axisTitle(spec, config, encode.title, dataRef));
|
||||
}
|
||||
|
||||
// parse axis specification
|
||||
return parseMark(
|
||||
guideGroup({
|
||||
role: AxisRole,
|
||||
from: dataRef,
|
||||
encode: axisEncode,
|
||||
marks: children,
|
||||
aria: _('aria'),
|
||||
description: _('description'),
|
||||
zindex: _('zindex'),
|
||||
name,
|
||||
interactive,
|
||||
style
|
||||
}),
|
||||
scope
|
||||
);
|
||||
}
|
||||
|
||||
function buildAxisEncode(_, spec) {
|
||||
var encode = {enter: {}, update: {}};
|
||||
|
||||
addEncoders(encode, {
|
||||
orient: _('orient'),
|
||||
offset: _('offset') || 0,
|
||||
position: value(spec.position, 0),
|
||||
titlePadding: _('titlePadding'),
|
||||
minExtent: _('minExtent'),
|
||||
maxExtent: _('maxExtent'),
|
||||
range: {signal: `abs(span(range("${spec.scale}")))`},
|
||||
translate: _('translate'),
|
||||
|
||||
// accessibility support
|
||||
format: spec.format,
|
||||
formatType: spec.formatType
|
||||
});
|
||||
|
||||
return encode;
|
||||
}
|
||||
116
node_modules/vega-parser/src/parsers/data.js
generated
vendored
Normal file
116
node_modules/vega-parser/src/parsers/data.js
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
import parseTransform from './transform';
|
||||
import parseTrigger from './trigger';
|
||||
import {Collect, Load, Relay, Sieve} from '../transforms';
|
||||
import {hasSignal, ref} from '../util';
|
||||
import {array} from 'vega-util';
|
||||
|
||||
export default function parseData(data, scope) {
|
||||
var transforms = [];
|
||||
|
||||
if (data.transform) {
|
||||
data.transform.forEach(function(tx) {
|
||||
transforms.push(parseTransform(tx, scope));
|
||||
});
|
||||
}
|
||||
|
||||
if (data.on) {
|
||||
data.on.forEach(function(on) {
|
||||
parseTrigger(on, scope, data.name);
|
||||
});
|
||||
}
|
||||
|
||||
scope.addDataPipeline(data.name, analyze(data, scope, transforms));
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze a data pipeline, add needed operators.
|
||||
*/
|
||||
function analyze(data, scope, ops) {
|
||||
var output = [],
|
||||
source = null,
|
||||
modify = false,
|
||||
generate = false,
|
||||
upstream, i, n, t, m;
|
||||
|
||||
if (data.values) {
|
||||
// hard-wired input data set
|
||||
if (hasSignal(data.values) || hasSignal(data.format)) {
|
||||
// if either values or format has signal, use dynamic loader
|
||||
output.push(load(scope, data));
|
||||
output.push(source = collect());
|
||||
} else {
|
||||
// otherwise, ingest upon dataflow init
|
||||
output.push(source = collect({
|
||||
$ingest: data.values,
|
||||
$format: data.format
|
||||
}));
|
||||
}
|
||||
} else if (data.url) {
|
||||
// load data from external source
|
||||
if (hasSignal(data.url) || hasSignal(data.format)) {
|
||||
// if either url or format has signal, use dynamic loader
|
||||
output.push(load(scope, data));
|
||||
output.push(source = collect());
|
||||
} else {
|
||||
// otherwise, request load upon dataflow init
|
||||
output.push(source = collect({
|
||||
$request: data.url,
|
||||
$format: data.format
|
||||
}));
|
||||
}
|
||||
} else if (data.source) {
|
||||
// derives from one or more other data sets
|
||||
source = upstream = array(data.source).map(function(d) {
|
||||
return ref(scope.getData(d).output);
|
||||
});
|
||||
output.push(null); // populate later
|
||||
}
|
||||
|
||||
// scan data transforms, add collectors as needed
|
||||
for (i=0, n=ops.length; i<n; ++i) {
|
||||
t = ops[i];
|
||||
m = t.metadata;
|
||||
|
||||
if (!source && !m.source) {
|
||||
output.push(source = collect());
|
||||
}
|
||||
output.push(t);
|
||||
|
||||
if (m.generates) generate = true;
|
||||
if (m.modifies && !generate) modify = true;
|
||||
|
||||
if (m.source) source = t;
|
||||
else if (m.changes) source = null;
|
||||
}
|
||||
|
||||
if (upstream) {
|
||||
n = upstream.length - 1;
|
||||
output[0] = Relay({
|
||||
derive: modify,
|
||||
pulse: n ? upstream : upstream[0]
|
||||
});
|
||||
if (modify || n) {
|
||||
// collect derived and multi-pulse tuples
|
||||
output.splice(1, 0, collect());
|
||||
}
|
||||
}
|
||||
|
||||
if (!source) output.push(collect());
|
||||
output.push(Sieve({}));
|
||||
return output;
|
||||
}
|
||||
|
||||
function collect(values) {
|
||||
var s = Collect({}, values);
|
||||
s.metadata = {source: true};
|
||||
return s;
|
||||
}
|
||||
|
||||
function load(scope, data) {
|
||||
return Load({
|
||||
url: data.url ? scope.property(data.url) : undefined,
|
||||
async: data.async ? scope.property(data.async) : undefined,
|
||||
values: data.values ? scope.property(data.values) : undefined,
|
||||
format: scope.objectProperty(data.format)
|
||||
});
|
||||
}
|
||||
47
node_modules/vega-parser/src/parsers/encode.js
generated
vendored
Normal file
47
node_modules/vega-parser/src/parsers/encode.js
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
import applyDefaults from './encode/defaults';
|
||||
import entry from './encode/entry';
|
||||
import rule from './encode/rule';
|
||||
|
||||
import {parseExpression} from 'vega-functions';
|
||||
import {extend, isArray} from 'vega-util';
|
||||
|
||||
export default function(encode, type, role, style, scope, params) {
|
||||
const enc = {};
|
||||
params = params || {};
|
||||
params.encoders = {$encode: enc};
|
||||
|
||||
encode = applyDefaults(encode, type, role, style, scope.config);
|
||||
for (const key in encode) {
|
||||
enc[key] = parseBlock(encode[key], type, params, scope);
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
function parseBlock(block, marktype, params, scope) {
|
||||
const channels = {},
|
||||
fields = {};
|
||||
|
||||
for (const name in block) {
|
||||
if (block[name] != null) { // skip any null entries
|
||||
channels[name] = parse(expr(block[name]), scope, params, fields);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
$expr: {marktype, channels},
|
||||
$fields: Object.keys(fields),
|
||||
$output: Object.keys(block)
|
||||
};
|
||||
}
|
||||
|
||||
function expr(enc) {
|
||||
return isArray(enc) ? rule(enc) : entry(enc);
|
||||
}
|
||||
|
||||
function parse(code, scope, params, fields) {
|
||||
const expr = parseExpression(code, scope);
|
||||
expr.$fields.forEach(name => fields[name] = 1);
|
||||
extend(params, expr.$params);
|
||||
return expr.$expr;
|
||||
}
|
||||
64
node_modules/vega-parser/src/parsers/encode/defaults.js
generated
vendored
Normal file
64
node_modules/vega-parser/src/parsers/encode/defaults.js
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
import {has} from './util';
|
||||
import {FrameRole, MarkRole} from '../marks/roles';
|
||||
import {array, extend} from 'vega-util';
|
||||
|
||||
export default function(encode, type, role, style, config) {
|
||||
const defaults = {}, enter = {};
|
||||
let update, key, skip, props;
|
||||
|
||||
// if text mark, apply global lineBreak settings (#2370)
|
||||
key = 'lineBreak';
|
||||
if (type === 'text' && config[key] != null && !has(key, encode)) {
|
||||
applyDefault(defaults, key, config[key]);
|
||||
}
|
||||
|
||||
// ignore legend and axis roles
|
||||
if (role == 'legend' || String(role).startsWith('axis')) {
|
||||
role = null;
|
||||
}
|
||||
|
||||
// resolve mark config
|
||||
props = role === FrameRole ? config.group
|
||||
: (role === MarkRole) ? extend({}, config.mark, config[type])
|
||||
: null;
|
||||
|
||||
for (key in props) {
|
||||
// do not apply defaults if relevant fields are defined
|
||||
skip = has(key, encode)
|
||||
|| (key === 'fill' || key === 'stroke')
|
||||
&& (has('fill', encode) || has('stroke', encode));
|
||||
|
||||
if (!skip) applyDefault(defaults, key, props[key]);
|
||||
}
|
||||
|
||||
// resolve styles, apply with increasing precedence
|
||||
array(style).forEach(name => {
|
||||
const props = config.style && config.style[name];
|
||||
for (const key in props) {
|
||||
if (!has(key, encode)) {
|
||||
applyDefault(defaults, key, props[key]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
encode = extend({}, encode); // defensive copy
|
||||
for (key in defaults) {
|
||||
props = defaults[key];
|
||||
if (props.signal) {
|
||||
(update = update || {})[key] = props;
|
||||
} else {
|
||||
enter[key] = props;
|
||||
}
|
||||
}
|
||||
|
||||
encode.enter = extend(enter, encode.enter);
|
||||
if (update) encode.update = extend(update, encode.update);
|
||||
|
||||
return encode;
|
||||
}
|
||||
|
||||
function applyDefault(defaults, key, value) {
|
||||
defaults[key] = value && value.signal
|
||||
? {signal: value.signal}
|
||||
: {value: value};
|
||||
}
|
||||
137
node_modules/vega-parser/src/parsers/encode/entry.js
generated
vendored
Normal file
137
node_modules/vega-parser/src/parsers/encode/entry.js
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
import {error, isObject, isString, peek, splitAccessPath, stringValue} from 'vega-util';
|
||||
|
||||
const scaleRef = scale => isString(scale) ? stringValue(scale)
|
||||
: scale.signal ? `(${scale.signal})`
|
||||
: field(scale);
|
||||
|
||||
export default function entry(enc) {
|
||||
if (enc.gradient != null) {
|
||||
return gradient(enc);
|
||||
}
|
||||
|
||||
let value = enc.signal ? `(${enc.signal})`
|
||||
: enc.color ? color(enc.color)
|
||||
: enc.field != null ? field(enc.field)
|
||||
: enc.value !== undefined ? stringValue(enc.value)
|
||||
: undefined;
|
||||
|
||||
if (enc.scale != null) {
|
||||
value = scale(enc, value);
|
||||
}
|
||||
|
||||
if (value === undefined) {
|
||||
value = null;
|
||||
}
|
||||
|
||||
if (enc.exponent != null) {
|
||||
value = `pow(${value},${property(enc.exponent)})`;
|
||||
}
|
||||
|
||||
if (enc.mult != null) {
|
||||
value += `*${property(enc.mult)}`;
|
||||
}
|
||||
|
||||
if (enc.offset != null) {
|
||||
value += `+${property(enc.offset)}`;
|
||||
}
|
||||
|
||||
if (enc.round) {
|
||||
value = `round(${value})`;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
const _color = (type, x, y, z) =>
|
||||
`(${type}(${[x, y, z].map(entry).join(',')})+'')`;
|
||||
|
||||
function color(enc) {
|
||||
return (enc.c) ? _color('hcl', enc.h, enc.c, enc.l)
|
||||
: (enc.h || enc.s) ? _color('hsl', enc.h, enc.s, enc.l)
|
||||
: (enc.l || enc.a) ? _color('lab', enc.l, enc.a, enc.b)
|
||||
: (enc.r || enc.g || enc.b) ? _color('rgb', enc.r, enc.g, enc.b)
|
||||
: null;
|
||||
}
|
||||
|
||||
function gradient(enc) {
|
||||
// map undefined to null; expression lang does not allow undefined
|
||||
const args = [enc.start, enc.stop, enc.count]
|
||||
.map(_ => _ == null ? null : stringValue(_));
|
||||
|
||||
// trim null inputs from the end
|
||||
while (args.length && peek(args) == null) args.pop();
|
||||
|
||||
args.unshift(scaleRef(enc.gradient));
|
||||
return `gradient(${args.join(',')})`;
|
||||
}
|
||||
|
||||
function property(property) {
|
||||
return isObject(property) ? '(' + entry(property) + ')' : property;
|
||||
}
|
||||
|
||||
function field(ref) {
|
||||
return resolveField(isObject(ref) ? ref : {datum: ref});
|
||||
}
|
||||
|
||||
function resolveField(ref) {
|
||||
let object, level, field;
|
||||
|
||||
if (ref.signal) {
|
||||
object = 'datum';
|
||||
field = ref.signal;
|
||||
} else if (ref.group || ref.parent) {
|
||||
level = Math.max(1, ref.level || 1);
|
||||
object = 'item';
|
||||
|
||||
while (level-- > 0) {
|
||||
object += '.mark.group';
|
||||
}
|
||||
|
||||
if (ref.parent) {
|
||||
field = ref.parent;
|
||||
object += '.datum';
|
||||
} else {
|
||||
field = ref.group;
|
||||
}
|
||||
} else if (ref.datum) {
|
||||
object = 'datum';
|
||||
field = ref.datum;
|
||||
} else {
|
||||
error('Invalid field reference: ' + stringValue(ref));
|
||||
}
|
||||
|
||||
if (!ref.signal) {
|
||||
field = isString(field)
|
||||
? splitAccessPath(field).map(stringValue).join('][')
|
||||
: resolveField(field);
|
||||
}
|
||||
|
||||
return object + '[' + field + ']';
|
||||
}
|
||||
|
||||
function scale(enc, value) {
|
||||
const scale = scaleRef(enc.scale);
|
||||
|
||||
if (enc.range != null) {
|
||||
// pull value from scale range
|
||||
value = `lerp(_range(${scale}), ${+enc.range})`;
|
||||
} else {
|
||||
// run value through scale and/or pull scale bandwidth
|
||||
if (value !== undefined) value = `_scale(${scale}, ${value})`;
|
||||
|
||||
if (enc.band) {
|
||||
value = (value ? value + '+' : '')
|
||||
+ `_bandwidth(${scale})`
|
||||
+ (+enc.band === 1 ? '' : '*' + property(enc.band));
|
||||
|
||||
if (enc.extra) {
|
||||
// include logic to handle extraneous elements
|
||||
value = `(datum.extra ? _scale(${scale}, datum.extra.value) : ${value})`;
|
||||
}
|
||||
}
|
||||
|
||||
if (value == null) value = '0';
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
18
node_modules/vega-parser/src/parsers/encode/rule.js
generated
vendored
Normal file
18
node_modules/vega-parser/src/parsers/encode/rule.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import entry from './entry';
|
||||
import {peek} from 'vega-util';
|
||||
|
||||
export default function(enc) {
|
||||
let code = '';
|
||||
|
||||
enc.forEach(rule => {
|
||||
const value = entry(rule);
|
||||
code += rule.test ? `(${rule.test})?${value}:` : value;
|
||||
});
|
||||
|
||||
// if no else clause, terminate with null (#1366)
|
||||
if (peek(code) === ':') {
|
||||
code += 'null';
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
43
node_modules/vega-parser/src/parsers/encode/util.js
generated
vendored
Normal file
43
node_modules/vega-parser/src/parsers/encode/util.js
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
import {extend, hasOwnProperty, isArray, isObject} from 'vega-util';
|
||||
|
||||
export const encoder = _ => isObject(_) && !isArray(_)
|
||||
? extend({}, _)
|
||||
: {value: _};
|
||||
|
||||
export function addEncode(object, name, value, set) {
|
||||
if (value != null) {
|
||||
// Always assign signal to update, even if the signal is from the enter block
|
||||
if (isObject(value) && !isArray(value)) {
|
||||
object.update[name] = value;
|
||||
} else {
|
||||
object[set || 'enter'][name] = {value: value};
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function addEncoders(object, enter, update) {
|
||||
for (const name in enter) {
|
||||
addEncode(object, name, enter[name]);
|
||||
}
|
||||
for (const name in update) {
|
||||
addEncode(object, name, update[name], 'update');
|
||||
}
|
||||
}
|
||||
|
||||
export function extendEncode(encode, extra, skip) {
|
||||
for (const name in extra) {
|
||||
if (skip && hasOwnProperty(skip, name)) continue;
|
||||
encode[name] = extend(encode[name] || {}, extra[name]);
|
||||
}
|
||||
return encode;
|
||||
}
|
||||
|
||||
export function has(key, encode) {
|
||||
return encode && (
|
||||
(encode.enter && encode.enter[key]) ||
|
||||
(encode.update && encode.update[key])
|
||||
);
|
||||
}
|
||||
97
node_modules/vega-parser/src/parsers/guides/axis-config.js
generated
vendored
Normal file
97
node_modules/vega-parser/src/parsers/guides/axis-config.js
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
import {ifOrient, ifX} from './axis-util';
|
||||
import {Bottom, GuideLabelStyle, GuideTitleStyle, Top} from './constants';
|
||||
import {isSignal} from '../../util';
|
||||
import {extend, hasOwnProperty} from 'vega-util';
|
||||
|
||||
function fallback(prop, config, axisConfig, style) {
|
||||
let styleProp;
|
||||
|
||||
if (config && hasOwnProperty(config, prop)) {
|
||||
return config[prop];
|
||||
}
|
||||
else if (hasOwnProperty(axisConfig, prop)) {
|
||||
return axisConfig[prop];
|
||||
}
|
||||
else if (prop.startsWith('title')) {
|
||||
switch (prop) {
|
||||
case 'titleColor':
|
||||
styleProp = 'fill';
|
||||
break;
|
||||
case 'titleFont':
|
||||
case 'titleFontSize':
|
||||
case 'titleFontWeight':
|
||||
styleProp = prop[5].toLowerCase() + prop.slice(6);
|
||||
}
|
||||
return style[GuideTitleStyle][styleProp];
|
||||
}
|
||||
else if (prop.startsWith('label')) {
|
||||
switch (prop) {
|
||||
case 'labelColor':
|
||||
styleProp = 'fill';
|
||||
break;
|
||||
case 'labelFont':
|
||||
case 'labelFontSize':
|
||||
styleProp = prop[5].toLowerCase() + prop.slice(6);
|
||||
}
|
||||
return style[GuideLabelStyle][styleProp];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function keys(objects) {
|
||||
const map = {};
|
||||
for (const obj of objects) {
|
||||
if (!obj) continue;
|
||||
for (const key in obj) map[key] = 1;
|
||||
}
|
||||
return Object.keys(map);
|
||||
}
|
||||
|
||||
export default function(spec, scope) {
|
||||
var config = scope.config,
|
||||
style = config.style,
|
||||
axis = config.axis,
|
||||
band = scope.scaleType(spec.scale) === 'band' && config.axisBand,
|
||||
orient = spec.orient,
|
||||
xy, or, key;
|
||||
|
||||
if (isSignal(orient)) {
|
||||
const xyKeys = keys([
|
||||
config.axisX, config.axisY
|
||||
]),
|
||||
orientKeys = keys([
|
||||
config.axisTop, config.axisBottom,
|
||||
config.axisLeft, config.axisRight
|
||||
]);
|
||||
|
||||
xy = {};
|
||||
for (key of xyKeys) {
|
||||
xy[key] = ifX(
|
||||
orient,
|
||||
fallback(key, config.axisX, axis, style),
|
||||
fallback(key, config.axisY, axis, style)
|
||||
);
|
||||
}
|
||||
|
||||
or = {};
|
||||
for (key of orientKeys) {
|
||||
or[key] = ifOrient(
|
||||
orient.signal,
|
||||
fallback(key, config.axisTop, axis, style),
|
||||
fallback(key, config.axisBottom, axis, style),
|
||||
fallback(key, config.axisLeft, axis, style),
|
||||
fallback(key, config.axisRight, axis, style)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
xy = (orient === Top || orient === Bottom) ? config.axisX : config.axisY;
|
||||
or = config['axis' + orient[0].toUpperCase() + orient.slice(1)];
|
||||
}
|
||||
|
||||
var result = (xy || or || band)
|
||||
? extend({}, axis, xy, or, band)
|
||||
: axis;
|
||||
|
||||
return result;
|
||||
}
|
||||
48
node_modules/vega-parser/src/parsers/guides/axis-domain.js
generated
vendored
Normal file
48
node_modules/vega-parser/src/parsers/guides/axis-domain.js
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
import {ifX, ifY} from './axis-util';
|
||||
import {one, zero} from './constants';
|
||||
import guideMark from './guide-mark';
|
||||
import {lookup} from './guide-util';
|
||||
import {addEncoders} from '../encode/util';
|
||||
import {RuleMark} from '../marks/marktypes';
|
||||
import {AxisDomainRole} from '../marks/roles';
|
||||
|
||||
export default function(spec, config, userEncode, dataRef) {
|
||||
var _ = lookup(spec, config),
|
||||
orient = spec.orient,
|
||||
encode, enter, update;
|
||||
|
||||
encode = {
|
||||
enter: enter = {opacity: zero},
|
||||
update: update = {opacity: one},
|
||||
exit: {opacity: zero}
|
||||
};
|
||||
|
||||
addEncoders(encode, {
|
||||
stroke: _('domainColor'),
|
||||
strokeCap: _('domainCap'),
|
||||
strokeDash: _('domainDash'),
|
||||
strokeDashOffset: _('domainDashOffset'),
|
||||
strokeWidth: _('domainWidth'),
|
||||
strokeOpacity: _('domainOpacity')
|
||||
});
|
||||
|
||||
const pos0 = position(spec, 0);
|
||||
const pos1 = position(spec, 1);
|
||||
|
||||
enter.x = update.x = ifX(orient, pos0, zero);
|
||||
enter.x2 = update.x2 = ifX(orient, pos1);
|
||||
|
||||
enter.y = update.y = ifY(orient, pos0, zero);
|
||||
enter.y2 = update.y2 = ifY(orient, pos1);
|
||||
|
||||
return guideMark({
|
||||
type: RuleMark,
|
||||
role: AxisDomainRole,
|
||||
from: dataRef,
|
||||
encode
|
||||
}, userEncode);
|
||||
}
|
||||
|
||||
function position(spec, pos) {
|
||||
return {scale: spec.scale, range: pos};
|
||||
}
|
||||
93
node_modules/vega-parser/src/parsers/guides/axis-grid.js
generated
vendored
Normal file
93
node_modules/vega-parser/src/parsers/guides/axis-grid.js
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
import {getSign, ifX, ifY} from './axis-util';
|
||||
import {Value, one, zero} from './constants';
|
||||
import guideMark from './guide-mark';
|
||||
import {lookup} from './guide-util';
|
||||
import {addEncoders} from '../encode/util';
|
||||
import {RuleMark} from '../marks/marktypes';
|
||||
import {AxisGridRole} from '../marks/roles';
|
||||
import {isSignal} from '../../util';
|
||||
import {extend, isObject} from 'vega-util';
|
||||
|
||||
export default function(spec, config, userEncode, dataRef, band) {
|
||||
var _ = lookup(spec, config),
|
||||
orient = spec.orient,
|
||||
vscale = spec.gridScale,
|
||||
sign = getSign(orient, 1, -1),
|
||||
offset = offsetValue(spec.offset, sign),
|
||||
encode, enter, exit, update,
|
||||
tickPos, gridStart, gridEnd, sz;
|
||||
|
||||
encode = {
|
||||
enter: enter = {opacity: zero},
|
||||
update: update = {opacity: one},
|
||||
exit: exit = {opacity: zero}
|
||||
};
|
||||
|
||||
addEncoders(encode, {
|
||||
stroke: _('gridColor'),
|
||||
strokeCap: _('gridCap'),
|
||||
strokeDash: _('gridDash'),
|
||||
strokeDashOffset: _('gridDashOffset'),
|
||||
strokeOpacity: _('gridOpacity'),
|
||||
strokeWidth: _('gridWidth')
|
||||
});
|
||||
|
||||
tickPos = {
|
||||
scale: spec.scale,
|
||||
field: Value,
|
||||
band: band.band,
|
||||
extra: band.extra,
|
||||
offset: band.offset,
|
||||
round: _('tickRound')
|
||||
};
|
||||
|
||||
sz = ifX(orient, {signal: 'height'}, {signal: 'width'});
|
||||
|
||||
gridStart = vscale
|
||||
? {scale: vscale, range: 0, mult: sign, offset: offset}
|
||||
: {value: 0, offset: offset};
|
||||
|
||||
gridEnd = vscale
|
||||
? {scale: vscale, range: 1, mult: sign, offset: offset}
|
||||
: extend(sz, {mult: sign, offset: offset});
|
||||
|
||||
enter.x = update.x = ifX(orient, tickPos, gridStart);
|
||||
enter.y = update.y = ifY(orient, tickPos, gridStart);
|
||||
enter.x2 = update.x2 = ifY(orient, gridEnd);
|
||||
enter.y2 = update.y2 = ifX(orient, gridEnd);
|
||||
exit.x = ifX(orient, tickPos);
|
||||
exit.y = ifY(orient, tickPos);
|
||||
|
||||
return guideMark({
|
||||
type: RuleMark,
|
||||
role: AxisGridRole,
|
||||
key: Value,
|
||||
from: dataRef,
|
||||
encode
|
||||
}, userEncode);
|
||||
}
|
||||
|
||||
function offsetValue(offset, sign) {
|
||||
if (sign === 1) {
|
||||
// no further adjustment needed, just return offset
|
||||
} else if (!isObject(offset)) {
|
||||
offset = isSignal(sign)
|
||||
? {signal: `(${sign.signal}) * (${offset || 0})`}
|
||||
: sign * (offset || 0);
|
||||
} else {
|
||||
let entry = offset = extend({}, offset);
|
||||
while (entry.mult != null) {
|
||||
if (!isObject(entry.mult)) {
|
||||
entry.mult = isSignal(sign) // no offset if sign === 1
|
||||
? {signal: `(${entry.mult}) * (${sign.signal})`}
|
||||
: entry.mult * sign;
|
||||
return offset;
|
||||
} else {
|
||||
entry = entry.mult = extend({}, entry.mult);
|
||||
}
|
||||
}
|
||||
entry.mult = sign;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
130
node_modules/vega-parser/src/parsers/guides/axis-labels.js
generated
vendored
Normal file
130
node_modules/vega-parser/src/parsers/guides/axis-labels.js
generated
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
import {getSign, ifRight, ifTop, ifX, ifY, patch} from './axis-util';
|
||||
import {GuideLabelStyle, Label, Value, one, zero} from './constants';
|
||||
import guideMark from './guide-mark';
|
||||
import {extendOffset, lookup} from './guide-util';
|
||||
import {addEncoders, encoder} from '../encode/util';
|
||||
import {TextMark} from '../marks/marktypes';
|
||||
import {AxisLabelRole} from '../marks/roles';
|
||||
import {deref} from '../../util';
|
||||
|
||||
function flushExpr(scale, threshold, a, b, c) {
|
||||
return {
|
||||
signal: 'flush(range("' + scale + '"), '
|
||||
+ 'scale("' + scale + '", datum.value), '
|
||||
+ threshold + ',' + a + ',' + b + ',' + c + ')'
|
||||
};
|
||||
}
|
||||
|
||||
export default function(spec, config, userEncode, dataRef, size, band) {
|
||||
var _ = lookup(spec, config),
|
||||
orient = spec.orient,
|
||||
scale = spec.scale,
|
||||
sign = getSign(orient, -1, 1),
|
||||
flush = deref(_('labelFlush')),
|
||||
flushOffset = deref(_('labelFlushOffset')),
|
||||
flushOn = flush === 0 || !!flush,
|
||||
labelAlign = _('labelAlign'),
|
||||
labelBaseline = _('labelBaseline'),
|
||||
encode, enter, update, tickSize, tickPos,
|
||||
align, baseline, bound, overlap, offsetExpr;
|
||||
|
||||
tickSize = encoder(size);
|
||||
tickSize.mult = sign;
|
||||
tickSize.offset = encoder(_('labelPadding') || 0);
|
||||
tickSize.offset.mult = sign;
|
||||
|
||||
tickPos = {
|
||||
scale: scale,
|
||||
field: Value,
|
||||
band: 0.5,
|
||||
offset: extendOffset(band.offset, _('labelOffset'))
|
||||
};
|
||||
|
||||
align = ifX(orient,
|
||||
flushOn
|
||||
? flushExpr(scale, flush, '"left"', '"right"', '"center"')
|
||||
: {value: 'center'},
|
||||
ifRight(orient, 'left', 'right')
|
||||
);
|
||||
|
||||
baseline = ifX(orient,
|
||||
ifTop(orient, 'bottom', 'top'),
|
||||
flushOn
|
||||
? flushExpr(scale, flush, '"top"', '"bottom"', '"middle"')
|
||||
: {value: 'middle'}
|
||||
);
|
||||
|
||||
offsetExpr = flushExpr(scale, flush, `-(${flushOffset})`, flushOffset, 0);
|
||||
flushOn = flushOn && flushOffset;
|
||||
|
||||
enter = {
|
||||
opacity: zero,
|
||||
x: ifX(orient, tickPos, tickSize),
|
||||
y: ifY(orient, tickPos, tickSize)
|
||||
};
|
||||
|
||||
encode = {
|
||||
enter: enter,
|
||||
update: update = {
|
||||
opacity: one,
|
||||
text: {field: Label},
|
||||
x: enter.x,
|
||||
y: enter.y,
|
||||
align,
|
||||
baseline
|
||||
},
|
||||
exit: {
|
||||
opacity: zero,
|
||||
x: enter.x,
|
||||
y: enter.y
|
||||
}
|
||||
};
|
||||
|
||||
addEncoders(encode, {
|
||||
dx: !labelAlign && flushOn ? ifX(orient, offsetExpr) : null,
|
||||
dy: !labelBaseline && flushOn ? ifY(orient, offsetExpr) : null
|
||||
});
|
||||
|
||||
addEncoders(encode, {
|
||||
angle: _('labelAngle'),
|
||||
fill: _('labelColor'),
|
||||
fillOpacity: _('labelOpacity'),
|
||||
font: _('labelFont'),
|
||||
fontSize: _('labelFontSize'),
|
||||
fontWeight: _('labelFontWeight'),
|
||||
fontStyle: _('labelFontStyle'),
|
||||
limit: _('labelLimit'),
|
||||
lineHeight: _('labelLineHeight')
|
||||
}, {
|
||||
align: labelAlign,
|
||||
baseline: labelBaseline
|
||||
});
|
||||
|
||||
bound = _('labelBound');
|
||||
overlap = _('labelOverlap');
|
||||
|
||||
// if overlap method or bound defined, request label overlap removal
|
||||
overlap = overlap || bound ? {
|
||||
separation: _('labelSeparation'),
|
||||
method: overlap,
|
||||
order: 'datum.index',
|
||||
bound: bound ? {scale, orient, tolerance: bound} : null
|
||||
} : undefined;
|
||||
|
||||
if (update.align !== align) {
|
||||
update.align = patch(update.align, align);
|
||||
}
|
||||
if (update.baseline !== baseline) {
|
||||
update.baseline = patch(update.baseline, baseline);
|
||||
}
|
||||
|
||||
return guideMark({
|
||||
type: TextMark,
|
||||
role: AxisLabelRole,
|
||||
style: GuideLabelStyle,
|
||||
key: Value,
|
||||
from: dataRef,
|
||||
encode,
|
||||
overlap
|
||||
}, userEncode);
|
||||
}
|
||||
57
node_modules/vega-parser/src/parsers/guides/axis-ticks.js
generated
vendored
Normal file
57
node_modules/vega-parser/src/parsers/guides/axis-ticks.js
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
import {getSign, ifX, ifY} from './axis-util';
|
||||
import {Value, one, zero} from './constants';
|
||||
import guideMark from './guide-mark';
|
||||
import {lookup} from './guide-util';
|
||||
import {addEncoders, encoder} from '../encode/util';
|
||||
import {RuleMark} from '../marks/marktypes';
|
||||
import {AxisTickRole} from '../marks/roles';
|
||||
|
||||
export default function(spec, config, userEncode, dataRef, size, band) {
|
||||
var _ = lookup(spec, config),
|
||||
orient = spec.orient,
|
||||
sign = getSign(orient, -1, 1),
|
||||
encode, enter, exit, update, tickSize, tickPos;
|
||||
|
||||
encode = {
|
||||
enter: enter = {opacity: zero},
|
||||
update: update = {opacity: one},
|
||||
exit: exit = {opacity: zero}
|
||||
};
|
||||
|
||||
addEncoders(encode, {
|
||||
stroke: _('tickColor'),
|
||||
strokeCap: _('tickCap'),
|
||||
strokeDash: _('tickDash'),
|
||||
strokeDashOffset: _('tickDashOffset'),
|
||||
strokeOpacity: _('tickOpacity'),
|
||||
strokeWidth: _('tickWidth')
|
||||
});
|
||||
|
||||
tickSize = encoder(size);
|
||||
tickSize.mult = sign;
|
||||
|
||||
tickPos = {
|
||||
scale: spec.scale,
|
||||
field: Value,
|
||||
band: band.band,
|
||||
extra: band.extra,
|
||||
offset: band.offset,
|
||||
round: _('tickRound')
|
||||
};
|
||||
|
||||
update.y = enter.y = ifX(orient, zero, tickPos);
|
||||
update.y2 = enter.y2 = ifX(orient, tickSize);
|
||||
exit.x = ifX(orient, tickPos);
|
||||
|
||||
update.x = enter.x = ifY(orient, zero, tickPos);
|
||||
update.x2 = enter.x2 = ifY(orient, tickSize);
|
||||
exit.y = ifY(orient, tickPos);
|
||||
|
||||
return guideMark({
|
||||
type: RuleMark,
|
||||
role: AxisTickRole,
|
||||
key: Value,
|
||||
from: dataRef,
|
||||
encode
|
||||
}, userEncode);
|
||||
}
|
||||
82
node_modules/vega-parser/src/parsers/guides/axis-title.js
generated
vendored
Normal file
82
node_modules/vega-parser/src/parsers/guides/axis-title.js
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
import {getSign, ifTop, ifX, ifY, mult, patch} from './axis-util';
|
||||
import {Bottom, GuideTitleStyle, Top, one, zero} from './constants';
|
||||
import guideMark from './guide-mark';
|
||||
import {alignExpr, anchorExpr, lookup} from './guide-util';
|
||||
import {addEncoders, encoder, has} from '../encode/util';
|
||||
import {TextMark} from '../marks/marktypes';
|
||||
import {AxisTitleRole} from '../marks/roles';
|
||||
import {extend} from 'vega-util';
|
||||
|
||||
export default function(spec, config, userEncode, dataRef) {
|
||||
var _ = lookup(spec, config),
|
||||
orient = spec.orient,
|
||||
sign = getSign(orient, -1, 1),
|
||||
encode, enter, update, titlePos;
|
||||
|
||||
encode = {
|
||||
enter: enter = {
|
||||
opacity: zero,
|
||||
anchor: encoder(_('titleAnchor', null)),
|
||||
align: {signal: alignExpr}
|
||||
},
|
||||
update: update = extend({}, enter, {
|
||||
opacity: one,
|
||||
text: encoder(spec.title)
|
||||
}),
|
||||
exit: {
|
||||
opacity: zero
|
||||
}
|
||||
};
|
||||
|
||||
titlePos = {
|
||||
signal: `lerp(range("${spec.scale}"), ${anchorExpr(0, 1, 0.5)})`
|
||||
};
|
||||
|
||||
update.x = ifX(orient, titlePos);
|
||||
update.y = ifY(orient, titlePos);
|
||||
enter.angle = ifX(orient, zero, mult(sign, 90));
|
||||
enter.baseline = ifX(orient, ifTop(orient, Bottom, Top), {value: Bottom});
|
||||
update.angle = enter.angle;
|
||||
update.baseline = enter.baseline;
|
||||
|
||||
addEncoders(encode, {
|
||||
fill: _('titleColor'),
|
||||
fillOpacity: _('titleOpacity'),
|
||||
font: _('titleFont'),
|
||||
fontSize: _('titleFontSize'),
|
||||
fontStyle: _('titleFontStyle'),
|
||||
fontWeight: _('titleFontWeight'),
|
||||
limit: _('titleLimit'),
|
||||
lineHeight: _('titleLineHeight')
|
||||
}, { // require update
|
||||
align: _('titleAlign'),
|
||||
angle: _('titleAngle'),
|
||||
baseline: _('titleBaseline')
|
||||
});
|
||||
|
||||
autoLayout(_, orient, encode, userEncode);
|
||||
encode.update.align = patch(encode.update.align, enter.align);
|
||||
encode.update.angle = patch(encode.update.angle, enter.angle);
|
||||
encode.update.baseline = patch(encode.update.baseline, enter.baseline);
|
||||
|
||||
return guideMark({
|
||||
type: TextMark,
|
||||
role: AxisTitleRole,
|
||||
style: GuideTitleStyle,
|
||||
from: dataRef,
|
||||
encode
|
||||
}, userEncode);
|
||||
}
|
||||
|
||||
function autoLayout(_, orient, encode, userEncode) {
|
||||
const auto = (value, dim) => value != null
|
||||
? (encode.update[dim] = patch(encoder(value), encode.update[dim]), false)
|
||||
: !has(dim, userEncode) ? true : false;
|
||||
|
||||
const autoY = auto(_('titleX'), 'x'),
|
||||
autoX = auto(_('titleY'), 'y');
|
||||
|
||||
encode.enter.auto = autoX === autoY
|
||||
? encoder(autoX)
|
||||
: ifX(orient, encoder(autoX), encoder(autoY));
|
||||
}
|
||||
96
node_modules/vega-parser/src/parsers/guides/axis-util.js
generated
vendored
Normal file
96
node_modules/vega-parser/src/parsers/guides/axis-util.js
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
import {extend, stringValue} from 'vega-util';
|
||||
import {Bottom, Left, Right, Top} from './constants';
|
||||
import {encoder} from '../encode/util';
|
||||
import {isSignal} from '../../util';
|
||||
|
||||
const isX = orient => orient === Bottom || orient === Top;
|
||||
|
||||
// get sign coefficient based on axis orient
|
||||
export const getSign = (orient, a, b) => isSignal(orient)
|
||||
? ifLeftTopExpr(orient.signal, a, b)
|
||||
: orient === Left || orient === Top ? a : b;
|
||||
|
||||
// condition on axis x-direction
|
||||
export const ifX = (orient, a, b) => isSignal(orient)
|
||||
? ifXEnc(orient.signal, a, b)
|
||||
: isX(orient) ? a : b;
|
||||
|
||||
// condition on axis y-direction
|
||||
export const ifY = (orient, a, b) => isSignal(orient)
|
||||
? ifYEnc(orient.signal, a, b)
|
||||
: isX(orient) ? b : a;
|
||||
|
||||
export const ifTop = (orient, a, b) => isSignal(orient)
|
||||
? ifTopExpr(orient.signal, a, b)
|
||||
: orient === Top ? {value: a} : {value: b};
|
||||
|
||||
export const ifRight = (orient, a, b) => isSignal(orient)
|
||||
? ifRightExpr(orient.signal, a, b)
|
||||
: orient === Right ? {value: a} : {value: b};
|
||||
|
||||
const ifXEnc = ($orient, a, b) => ifEnc(
|
||||
`${$orient} === '${Top}' || ${$orient} === '${Bottom}'`, a, b
|
||||
);
|
||||
|
||||
const ifYEnc = ($orient, a, b) => ifEnc(
|
||||
`${$orient} !== '${Top}' && ${$orient} !== '${Bottom}'`, a, b
|
||||
);
|
||||
|
||||
const ifLeftTopExpr = ($orient, a, b) => ifExpr(
|
||||
`${$orient} === '${Left}' || ${$orient} === '${Top}'`, a, b
|
||||
);
|
||||
|
||||
const ifTopExpr = ($orient, a, b) => ifExpr(
|
||||
`${$orient} === '${Top}'`, a, b
|
||||
);
|
||||
|
||||
const ifRightExpr = ($orient, a, b) => ifExpr(
|
||||
`${$orient} === '${Right}'`, a, b
|
||||
);
|
||||
|
||||
const ifEnc = (test, a, b) => {
|
||||
// ensure inputs are encoder objects (or null)
|
||||
a = a != null ? encoder(a) : a;
|
||||
b = b != null ? encoder(b) : b;
|
||||
|
||||
if (isSimple(a) && isSimple(b)) {
|
||||
// if possible generate simple signal expression
|
||||
a = a ? (a.signal || stringValue(a.value)) : null;
|
||||
b = b ? (b.signal || stringValue(b.value)) : null;
|
||||
return {signal: `${test} ? (${a}) : (${b})`};
|
||||
} else {
|
||||
// otherwise generate rule set
|
||||
return [extend({test}, a)].concat(b || []);
|
||||
}
|
||||
};
|
||||
|
||||
const isSimple = enc => (
|
||||
enc == null || Object.keys(enc).length === 1
|
||||
);
|
||||
|
||||
const ifExpr = (test, a, b) => ({
|
||||
signal: `${test} ? (${toExpr(a)}) : (${toExpr(b)})`
|
||||
});
|
||||
|
||||
export const ifOrient = ($orient, t, b, l, r) => ({
|
||||
signal: (l != null ? `${$orient} === '${Left}' ? (${toExpr(l)}) : ` : '')
|
||||
+ (b != null ? `${$orient} === '${Bottom}' ? (${toExpr(b)}) : ` : '')
|
||||
+ (r != null ? `${$orient} === '${Right}' ? (${toExpr(r)}) : ` : '')
|
||||
+ (t != null ? `${$orient} === '${Top}' ? (${toExpr(t)}) : ` : '')
|
||||
+ '(null)'
|
||||
});
|
||||
|
||||
const toExpr = v => isSignal(v)
|
||||
? v.signal
|
||||
: v == null ? null : stringValue(v);
|
||||
|
||||
export const mult = (sign, value) => value === 0 ? 0 : isSignal(sign)
|
||||
? {signal: `(${sign.signal}) * ${value}`}
|
||||
: {value: sign * value};
|
||||
|
||||
export const patch = (value, base) => {
|
||||
const s = value.signal;
|
||||
return s && s.endsWith('(null)')
|
||||
? {signal: s.slice(0, -6) + base.signal}
|
||||
: value;
|
||||
};
|
||||
56
node_modules/vega-parser/src/parsers/guides/constants.js
generated
vendored
Normal file
56
node_modules/vega-parser/src/parsers/guides/constants.js
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
export const Top = 'top';
|
||||
export const Left = 'left';
|
||||
export const Right = 'right';
|
||||
export const Bottom = 'bottom';
|
||||
export const Center = 'center';
|
||||
|
||||
export const Vertical = 'vertical';
|
||||
|
||||
export const Start = 'start';
|
||||
export const Middle = 'middle';
|
||||
export const End = 'end';
|
||||
|
||||
export const Index = 'index';
|
||||
export const Label = 'label';
|
||||
export const Offset = 'offset';
|
||||
export const Perc = 'perc';
|
||||
export const Perc2 = 'perc2';
|
||||
export const Value = 'value';
|
||||
|
||||
export const GuideLabelStyle = 'guide-label';
|
||||
export const GuideTitleStyle = 'guide-title';
|
||||
export const GroupTitleStyle = 'group-title';
|
||||
export const GroupSubtitleStyle = 'group-subtitle';
|
||||
|
||||
export const Symbols = 'symbol';
|
||||
export const Gradient = 'gradient';
|
||||
export const Discrete = 'discrete';
|
||||
|
||||
export const Size = 'size';
|
||||
export const Shape = 'shape';
|
||||
export const Fill = 'fill';
|
||||
export const Stroke = 'stroke';
|
||||
export const StrokeWidth = 'strokeWidth';
|
||||
export const StrokeDash = 'strokeDash';
|
||||
export const Opacity = 'opacity';
|
||||
|
||||
// Encoding channels supported by legends
|
||||
// In priority order of 'canonical' scale
|
||||
export const LegendScales = [
|
||||
Size,
|
||||
Shape,
|
||||
Fill,
|
||||
Stroke,
|
||||
StrokeWidth,
|
||||
StrokeDash,
|
||||
Opacity
|
||||
];
|
||||
|
||||
export const Skip = {
|
||||
name: 1,
|
||||
style: 1,
|
||||
interactive: 1
|
||||
};
|
||||
|
||||
export const zero = {value: 0};
|
||||
export const one = {value: 1};
|
||||
7
node_modules/vega-parser/src/parsers/guides/guide-group.js
generated
vendored
Normal file
7
node_modules/vega-parser/src/parsers/guides/guide-group.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import {GroupMark} from '../marks/marktypes';
|
||||
|
||||
export default function(mark) {
|
||||
mark.type = GroupMark;
|
||||
mark.interactive = mark.interactive || false;
|
||||
return mark;
|
||||
}
|
||||
14
node_modules/vega-parser/src/parsers/guides/guide-mark.js
generated
vendored
Normal file
14
node_modules/vega-parser/src/parsers/guides/guide-mark.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import {Skip} from './constants';
|
||||
import {extendEncode} from '../encode/util';
|
||||
|
||||
export default function(mark, extras) {
|
||||
if (extras) {
|
||||
mark.name = extras.name;
|
||||
mark.style = extras.style || mark.style;
|
||||
mark.interactive = !!extras.interactive;
|
||||
mark.encode = extendEncode(mark.encode, extras, Skip);
|
||||
} else {
|
||||
mark.interactive = false;
|
||||
}
|
||||
return mark;
|
||||
}
|
||||
88
node_modules/vega-parser/src/parsers/guides/guide-util.js
generated
vendored
Normal file
88
node_modules/vega-parser/src/parsers/guides/guide-util.js
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
import {Center, End, Left, Right, Start, Vertical} from './constants';
|
||||
import {value} from '../../util';
|
||||
import {isObject, stringValue} from 'vega-util';
|
||||
|
||||
export function lookup(spec, config) {
|
||||
const _ = (name, dflt) => value(spec[name], value(config[name], dflt));
|
||||
|
||||
_.isVertical = s => Vertical === value(
|
||||
spec.direction,
|
||||
config.direction || (s ? config.symbolDirection : config.gradientDirection)
|
||||
);
|
||||
|
||||
_.gradientLength = () => value(
|
||||
spec.gradientLength,
|
||||
config.gradientLength || config.gradientWidth
|
||||
);
|
||||
|
||||
_.gradientThickness = () => value(
|
||||
spec.gradientThickness,
|
||||
config.gradientThickness || config.gradientHeight
|
||||
);
|
||||
|
||||
_.entryColumns = () => value(
|
||||
spec.columns,
|
||||
value(config.columns, +_.isVertical(true))
|
||||
);
|
||||
|
||||
return _;
|
||||
}
|
||||
|
||||
export function getEncoding(name, encode) {
|
||||
var v = encode && (
|
||||
(encode.update && encode.update[name]) ||
|
||||
(encode.enter && encode.enter[name])
|
||||
);
|
||||
return v && v.signal ? v : v ? v.value : null;
|
||||
}
|
||||
|
||||
export function getStyle(name, scope, style) {
|
||||
var s = scope.config.style[style];
|
||||
return s && s[name];
|
||||
}
|
||||
|
||||
export function anchorExpr(s, e, m) {
|
||||
return `item.anchor === '${Start}' ? ${s} : item.anchor === '${End}' ? ${e} : ${m}`;
|
||||
}
|
||||
|
||||
export const alignExpr = anchorExpr(
|
||||
stringValue(Left),
|
||||
stringValue(Right),
|
||||
stringValue(Center)
|
||||
);
|
||||
|
||||
export function tickBand(_) {
|
||||
let v = _('tickBand'),
|
||||
offset = _('tickOffset'),
|
||||
band, extra;
|
||||
|
||||
if (!v) {
|
||||
// if no tick band entry, fall back on other properties
|
||||
band = _('bandPosition');
|
||||
extra = _('tickExtra');
|
||||
} else if (v.signal) {
|
||||
// if signal, augment code to interpret values
|
||||
band = {signal: `(${v.signal}) === 'extent' ? 1 : 0.5`};
|
||||
extra = {signal: `(${v.signal}) === 'extent'`};
|
||||
if (!isObject(offset)) {
|
||||
offset = {signal: `(${v.signal}) === 'extent' ? 0 : ${offset}`};
|
||||
}
|
||||
} else if (v === 'extent') {
|
||||
// if constant, simply set values
|
||||
band = 1;
|
||||
extra = true;
|
||||
offset = 0;
|
||||
} else {
|
||||
band = 0.5;
|
||||
extra = false;
|
||||
}
|
||||
|
||||
return {extra, band, offset};
|
||||
}
|
||||
|
||||
export function extendOffset(value, offset) {
|
||||
return !offset ? value
|
||||
: !value ? offset
|
||||
: !isObject(value) ? { value, offset }
|
||||
: Object.assign({}, value, { offset: extendOffset(value.offset, offset) });
|
||||
}
|
||||
49
node_modules/vega-parser/src/parsers/guides/legend-gradient-discrete.js
generated
vendored
Normal file
49
node_modules/vega-parser/src/parsers/guides/legend-gradient-discrete.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
import {Perc, Perc2, Value, one, zero} from './constants';
|
||||
import guideMark from './guide-mark';
|
||||
import {lookup} from './guide-util';
|
||||
import {addEncoders, encoder} from '../encode/util';
|
||||
import {RectMark} from '../marks/marktypes';
|
||||
import {LegendBandRole} from '../marks/roles';
|
||||
import {extend} from 'vega-util';
|
||||
|
||||
export default function(spec, scale, config, userEncode, dataRef) {
|
||||
var _ = lookup(spec, config),
|
||||
vertical = _.isVertical(),
|
||||
thickness = _.gradientThickness(),
|
||||
length = _.gradientLength(),
|
||||
encode, enter, u, v, uu, vv, adjust = '';
|
||||
|
||||
vertical
|
||||
? (u = 'y', uu = 'y2', v = 'x', vv = 'width', adjust = '1-')
|
||||
: (u = 'x', uu = 'x2', v = 'y', vv = 'height');
|
||||
|
||||
enter = {
|
||||
opacity: zero,
|
||||
fill: {scale: scale, field: Value}
|
||||
};
|
||||
enter[u] = {signal: adjust + 'datum.' + Perc, mult: length};
|
||||
enter[v] = zero;
|
||||
enter[uu] = {signal: adjust + 'datum.' + Perc2, mult: length};
|
||||
enter[vv] = encoder(thickness);
|
||||
|
||||
encode = {
|
||||
enter: enter,
|
||||
update: extend({}, enter, {opacity: one}),
|
||||
exit: {opacity: zero}
|
||||
};
|
||||
|
||||
addEncoders(encode, {
|
||||
stroke: _('gradientStrokeColor'),
|
||||
strokeWidth: _('gradientStrokeWidth')
|
||||
}, { // update
|
||||
opacity: _('gradientOpacity')
|
||||
});
|
||||
|
||||
return guideMark({
|
||||
type: RectMark,
|
||||
role: LegendBandRole,
|
||||
key: Value,
|
||||
from: dataRef,
|
||||
encode
|
||||
}, userEncode);
|
||||
}
|
||||
77
node_modules/vega-parser/src/parsers/guides/legend-gradient-labels.js
generated
vendored
Normal file
77
node_modules/vega-parser/src/parsers/guides/legend-gradient-labels.js
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
import {
|
||||
Bottom, Center, GuideLabelStyle, Index, Label, Left, Middle,
|
||||
Perc, Right, Top, Value, one, zero
|
||||
} from './constants';
|
||||
import guideMark from './guide-mark';
|
||||
import {lookup} from './guide-util';
|
||||
import {addEncoders, encoder} from '../encode/util';
|
||||
import {TextMark} from '../marks/marktypes';
|
||||
import {LegendLabelRole} from '../marks/roles';
|
||||
import {value} from '../../util';
|
||||
|
||||
const alignExpr = `datum.${Perc}<=0?"${Left}":datum.${Perc}>=1?"${Right}":"${Center}"`,
|
||||
baselineExpr = `datum.${Perc}<=0?"${Bottom}":datum.${Perc}>=1?"${Top}":"${Middle}"`;
|
||||
|
||||
export default function(spec, config, userEncode, dataRef) {
|
||||
var _ = lookup(spec, config),
|
||||
vertical = _.isVertical(),
|
||||
thickness = encoder(_.gradientThickness()),
|
||||
length = _.gradientLength(),
|
||||
overlap = _('labelOverlap'),
|
||||
encode, enter, update, u, v, adjust = '';
|
||||
|
||||
encode = {
|
||||
enter: enter = {
|
||||
opacity: zero
|
||||
},
|
||||
update: update = {
|
||||
opacity: one,
|
||||
text: {field: Label}
|
||||
},
|
||||
exit: {
|
||||
opacity: zero
|
||||
}
|
||||
};
|
||||
|
||||
addEncoders(encode, {
|
||||
fill: _('labelColor'),
|
||||
fillOpacity: _('labelOpacity'),
|
||||
font: _('labelFont'),
|
||||
fontSize: _('labelFontSize'),
|
||||
fontStyle: _('labelFontStyle'),
|
||||
fontWeight: _('labelFontWeight'),
|
||||
limit: value(spec.labelLimit, config.gradientLabelLimit)
|
||||
});
|
||||
|
||||
if (vertical) {
|
||||
enter.align = {value: 'left'};
|
||||
enter.baseline = update.baseline = {signal: baselineExpr};
|
||||
u = 'y'; v = 'x'; adjust = '1-';
|
||||
} else {
|
||||
enter.align = update.align = {signal: alignExpr};
|
||||
enter.baseline = {value: 'top'};
|
||||
u = 'x'; v = 'y';
|
||||
}
|
||||
|
||||
enter[u] = update[u] = {signal: adjust + 'datum.' + Perc, mult: length};
|
||||
|
||||
enter[v] = update[v] = thickness;
|
||||
thickness.offset = value(spec.labelOffset, config.gradientLabelOffset) || 0;
|
||||
|
||||
overlap = overlap ? {
|
||||
separation: _('labelSeparation'),
|
||||
method: overlap,
|
||||
order: 'datum.' + Index
|
||||
} : undefined;
|
||||
|
||||
// type, role, style, key, dataRef, encode, extras
|
||||
return guideMark({
|
||||
type: TextMark,
|
||||
role: LegendLabelRole,
|
||||
style: GuideLabelStyle,
|
||||
key: Value,
|
||||
from: dataRef,
|
||||
encode,
|
||||
overlap
|
||||
}, userEncode);
|
||||
}
|
||||
57
node_modules/vega-parser/src/parsers/guides/legend-gradient.js
generated
vendored
Normal file
57
node_modules/vega-parser/src/parsers/guides/legend-gradient.js
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
import {one, zero} from './constants';
|
||||
import guideMark from './guide-mark';
|
||||
import {lookup} from './guide-util';
|
||||
import {addEncoders, encoder} from '../encode/util';
|
||||
import {RectMark} from '../marks/marktypes';
|
||||
import {LegendGradientRole} from '../marks/roles';
|
||||
import {extend} from 'vega-util';
|
||||
|
||||
export default function(spec, scale, config, userEncode) {
|
||||
var _ = lookup(spec, config),
|
||||
vertical = _.isVertical(),
|
||||
thickness = _.gradientThickness(),
|
||||
length = _.gradientLength(),
|
||||
encode, enter, start, stop, width, height;
|
||||
|
||||
if (vertical) {
|
||||
start = [0, 1];
|
||||
stop = [0, 0];
|
||||
width = thickness;
|
||||
height = length;
|
||||
} else {
|
||||
start = [0, 0];
|
||||
stop = [1, 0];
|
||||
width = length;
|
||||
height = thickness;
|
||||
}
|
||||
|
||||
encode = {
|
||||
enter: enter = {
|
||||
opacity: zero,
|
||||
x: zero,
|
||||
y: zero,
|
||||
width: encoder(width),
|
||||
height: encoder(height)
|
||||
},
|
||||
update: extend({}, enter, {
|
||||
opacity: one,
|
||||
fill: {gradient: scale, start: start, stop: stop}
|
||||
}),
|
||||
exit: {
|
||||
opacity: zero
|
||||
}
|
||||
};
|
||||
|
||||
addEncoders(encode, {
|
||||
stroke: _('gradientStrokeColor'),
|
||||
strokeWidth: _('gradientStrokeWidth')
|
||||
}, { // update
|
||||
opacity: _('gradientOpacity')
|
||||
});
|
||||
|
||||
return guideMark({
|
||||
type: RectMark,
|
||||
role: LegendGradientRole,
|
||||
encode
|
||||
}, userEncode);
|
||||
}
|
||||
183
node_modules/vega-parser/src/parsers/guides/legend-symbol-groups.js
generated
vendored
Normal file
183
node_modules/vega-parser/src/parsers/guides/legend-symbol-groups.js
generated
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
import {
|
||||
GuideLabelStyle, Index, Label, LegendScales, Offset, Size, Skip,
|
||||
Value, one, zero
|
||||
} from './constants';
|
||||
import guideGroup from './guide-group';
|
||||
import guideMark from './guide-mark';
|
||||
import {lookup} from './guide-util';
|
||||
import {addEncoders, encoder, extendEncode} from '../encode/util';
|
||||
import {SymbolMark, TextMark} from '../marks/marktypes';
|
||||
import {LegendLabelRole, LegendSymbolRole, ScopeRole} from '../marks/roles';
|
||||
|
||||
// userEncode is top-level, includes entries, symbols, labels
|
||||
export default function(spec, config, userEncode, dataRef, columns) {
|
||||
var _ = lookup(spec, config),
|
||||
entries = userEncode.entries,
|
||||
interactive = !!(entries && entries.interactive),
|
||||
name = entries ? entries.name : undefined,
|
||||
height = _('clipHeight'),
|
||||
symbolOffset = _('symbolOffset'),
|
||||
valueRef = {data: 'value'},
|
||||
encode = {},
|
||||
xSignal = `(${columns}) ? datum.${Offset} : datum.${Size}`,
|
||||
yEncode = height ? encoder(height) : {field: Size},
|
||||
index = `datum.${Index}`,
|
||||
ncols = `max(1, ${columns})`,
|
||||
enter, update, labelOffset, symbols, labels, nrows, sort;
|
||||
|
||||
yEncode.mult = 0.5;
|
||||
|
||||
// -- LEGEND SYMBOLS --
|
||||
encode = {
|
||||
enter: enter = {
|
||||
opacity: zero,
|
||||
x: {signal: xSignal, mult: 0.5, offset: symbolOffset},
|
||||
y: yEncode
|
||||
},
|
||||
update: update = {
|
||||
opacity: one,
|
||||
x: enter.x,
|
||||
y: enter.y
|
||||
},
|
||||
exit: {
|
||||
opacity: zero
|
||||
}
|
||||
};
|
||||
|
||||
var baseFill = null,
|
||||
baseStroke = null;
|
||||
if (!spec.fill) {
|
||||
baseFill = config.symbolBaseFillColor;
|
||||
baseStroke = config.symbolBaseStrokeColor;
|
||||
}
|
||||
|
||||
addEncoders(encode, {
|
||||
fill: _('symbolFillColor', baseFill),
|
||||
shape: _('symbolType'),
|
||||
size: _('symbolSize'),
|
||||
stroke: _('symbolStrokeColor', baseStroke),
|
||||
strokeDash: _('symbolDash'),
|
||||
strokeDashOffset: _('symbolDashOffset'),
|
||||
strokeWidth: _('symbolStrokeWidth')
|
||||
}, { // update
|
||||
opacity: _('symbolOpacity')
|
||||
});
|
||||
|
||||
LegendScales.forEach(function(scale) {
|
||||
if (spec[scale]) {
|
||||
update[scale] = enter[scale] = {scale: spec[scale], field: Value};
|
||||
}
|
||||
});
|
||||
|
||||
symbols = guideMark({
|
||||
type: SymbolMark,
|
||||
role: LegendSymbolRole,
|
||||
key: Value,
|
||||
from: valueRef,
|
||||
clip: height ? true : undefined,
|
||||
encode
|
||||
}, userEncode.symbols);
|
||||
|
||||
// -- LEGEND LABELS --
|
||||
labelOffset = encoder(symbolOffset);
|
||||
labelOffset.offset = _('labelOffset');
|
||||
|
||||
encode = {
|
||||
enter: enter = {
|
||||
opacity: zero,
|
||||
x: {signal: xSignal, offset: labelOffset},
|
||||
y: yEncode
|
||||
},
|
||||
update: update = {
|
||||
opacity: one,
|
||||
text: {field: Label},
|
||||
x: enter.x,
|
||||
y: enter.y
|
||||
},
|
||||
exit: {
|
||||
opacity: zero
|
||||
}
|
||||
};
|
||||
|
||||
addEncoders(encode, {
|
||||
align: _('labelAlign'),
|
||||
baseline: _('labelBaseline'),
|
||||
fill: _('labelColor'),
|
||||
fillOpacity: _('labelOpacity'),
|
||||
font: _('labelFont'),
|
||||
fontSize: _('labelFontSize'),
|
||||
fontStyle: _('labelFontStyle'),
|
||||
fontWeight: _('labelFontWeight'),
|
||||
limit: _('labelLimit')
|
||||
});
|
||||
|
||||
labels = guideMark({
|
||||
type: TextMark,
|
||||
role: LegendLabelRole,
|
||||
style: GuideLabelStyle,
|
||||
key: Value,
|
||||
from: valueRef,
|
||||
encode
|
||||
}, userEncode.labels);
|
||||
|
||||
// -- LEGEND ENTRY GROUPS --
|
||||
encode = {
|
||||
enter: {
|
||||
noBound: {value: !height}, // ignore width/height in bounds calc
|
||||
width: zero,
|
||||
height: height ? encoder(height) : zero,
|
||||
opacity: zero
|
||||
},
|
||||
exit: {opacity: zero},
|
||||
update: update = {
|
||||
opacity: one,
|
||||
row: {signal: null},
|
||||
column: {signal: null}
|
||||
}
|
||||
};
|
||||
|
||||
// annotate and sort groups to ensure correct ordering
|
||||
if (_.isVertical(true)) {
|
||||
nrows = `ceil(item.mark.items.length / ${ncols})`;
|
||||
update.row.signal = `${index}%${nrows}`;
|
||||
update.column.signal = `floor(${index} / ${nrows})`;
|
||||
sort = {field: ['row', index]};
|
||||
} else {
|
||||
update.row.signal = `floor(${index} / ${ncols})`;
|
||||
update.column.signal = `${index} % ${ncols}`;
|
||||
sort = {field: index};
|
||||
}
|
||||
// handle zero column case (implies infinite columns)
|
||||
update.column.signal = `(${columns})?${update.column.signal}:${index}`;
|
||||
|
||||
// facet legend entries into sub-groups
|
||||
dataRef = {facet: {data: dataRef, name: 'value', groupby: Index}};
|
||||
|
||||
return guideGroup({
|
||||
role: ScopeRole,
|
||||
from: dataRef,
|
||||
encode: extendEncode(encode, entries, Skip),
|
||||
marks: [symbols, labels],
|
||||
name,
|
||||
interactive,
|
||||
sort
|
||||
});
|
||||
}
|
||||
|
||||
export function legendSymbolLayout(spec, config) {
|
||||
const _ = lookup(spec, config);
|
||||
|
||||
// layout parameters for legend entries
|
||||
return {
|
||||
align: _('gridAlign'),
|
||||
columns: _.entryColumns(),
|
||||
center: {
|
||||
row: true,
|
||||
column: false
|
||||
},
|
||||
padding: {
|
||||
row: _('rowPadding'),
|
||||
column: _('columnPadding')
|
||||
}
|
||||
};
|
||||
}
|
||||
61
node_modules/vega-parser/src/parsers/guides/legend-title.js
generated
vendored
Normal file
61
node_modules/vega-parser/src/parsers/guides/legend-title.js
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
import {GuideTitleStyle, one, zero} from './constants';
|
||||
import guideMark from './guide-mark';
|
||||
import {alignExpr, anchorExpr, lookup} from './guide-util';
|
||||
import {addEncoders} from '../encode/util';
|
||||
import {TextMark} from '../marks/marktypes';
|
||||
import {LegendTitleRole} from '../marks/roles';
|
||||
|
||||
// expression logic for align, anchor, angle, and baseline calculation
|
||||
const isL = 'item.orient === "left"',
|
||||
isR = 'item.orient === "right"',
|
||||
isLR = `(${isL} || ${isR})`,
|
||||
isVG = `datum.vgrad && ${isLR}`,
|
||||
baseline = anchorExpr('"top"', '"bottom"', '"middle"'),
|
||||
alignFlip = anchorExpr('"right"', '"left"', '"center"'),
|
||||
exprAlign = `datum.vgrad && ${isR} ? (${alignFlip}) : (${isLR} && !(datum.vgrad && ${isL})) ? "left" : ${alignExpr}`,
|
||||
exprAnchor = `item._anchor || (${isLR} ? "middle" : "start")`,
|
||||
exprAngle = `${isVG} ? (${isL} ? -90 : 90) : 0`,
|
||||
exprBaseline = `${isLR} ? (datum.vgrad ? (${isR} ? "bottom" : "top") : ${baseline}) : "top"`;
|
||||
|
||||
export default function(spec, config, userEncode, dataRef) {
|
||||
var _ = lookup(spec, config), encode;
|
||||
|
||||
encode = {
|
||||
enter: {opacity: zero},
|
||||
update: {
|
||||
opacity: one,
|
||||
x: {field: {group: 'padding'}},
|
||||
y: {field: {group: 'padding'}}
|
||||
},
|
||||
exit: {opacity: zero}
|
||||
};
|
||||
|
||||
addEncoders(encode, {
|
||||
orient: _('titleOrient'),
|
||||
_anchor: _('titleAnchor'),
|
||||
anchor: {signal: exprAnchor},
|
||||
angle: {signal: exprAngle},
|
||||
align: {signal: exprAlign},
|
||||
baseline: {signal: exprBaseline},
|
||||
text: spec.title,
|
||||
fill: _('titleColor'),
|
||||
fillOpacity: _('titleOpacity'),
|
||||
font: _('titleFont'),
|
||||
fontSize: _('titleFontSize'),
|
||||
fontStyle: _('titleFontStyle'),
|
||||
fontWeight: _('titleFontWeight'),
|
||||
limit: _('titleLimit'),
|
||||
lineHeight: _('titleLineHeight')
|
||||
}, { // require update
|
||||
align: _('titleAlign'),
|
||||
baseline: _('titleBaseline')
|
||||
});
|
||||
|
||||
return guideMark({
|
||||
type: TextMark,
|
||||
role: LegendTitleRole,
|
||||
style: GuideTitleStyle,
|
||||
from: dataRef,
|
||||
encode
|
||||
}, userEncode);
|
||||
}
|
||||
202
node_modules/vega-parser/src/parsers/legend.js
generated
vendored
Normal file
202
node_modules/vega-parser/src/parsers/legend.js
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
import {addEncoders, extendEncode} from './encode/util';
|
||||
import {
|
||||
Discrete, Gradient,
|
||||
GuideLabelStyle, LegendScales, Skip, Symbols
|
||||
} from './guides/constants';
|
||||
import guideGroup from './guides/guide-group';
|
||||
import {getEncoding, getStyle, lookup} from './guides/guide-util';
|
||||
import legendGradient from './guides/legend-gradient';
|
||||
import legendGradientDiscrete from './guides/legend-gradient-discrete';
|
||||
import legendGradientLabels from './guides/legend-gradient-labels';
|
||||
import legendSymbolGroups, {legendSymbolLayout} from './guides/legend-symbol-groups';
|
||||
import legendTitle from './guides/legend-title';
|
||||
import parseMark from './mark';
|
||||
import {LegendEntryRole, LegendRole} from './marks/roles';
|
||||
|
||||
import {deref, ref} from '../util';
|
||||
import {Collect, LegendEntries} from '../transforms';
|
||||
|
||||
import {parseExpression} from 'vega-functions';
|
||||
import {isContinuous, isDiscretizing} from 'vega-scale';
|
||||
import {error} from 'vega-util';
|
||||
|
||||
export default function(spec, scope) {
|
||||
var config = scope.config.legend,
|
||||
encode = spec.encode || {},
|
||||
legendEncode = encode.legend || {},
|
||||
name = legendEncode.name || undefined,
|
||||
interactive = legendEncode.interactive,
|
||||
style = legendEncode.style,
|
||||
_ = lookup(spec, config),
|
||||
scales = {}, scale = 0,
|
||||
entryEncode, entryLayout, params, children,
|
||||
type, datum, dataRef, entryRef;
|
||||
|
||||
// resolve scales and 'canonical' scale name
|
||||
LegendScales.forEach(s => spec[s]
|
||||
? (scales[s] = spec[s], scale = scale || spec[s]) : 0
|
||||
);
|
||||
if (!scale) error('Missing valid scale for legend.');
|
||||
|
||||
// resolve legend type (symbol, gradient, or discrete gradient)
|
||||
type = legendType(spec, scope.scaleType(scale));
|
||||
|
||||
// single-element data source for legend group
|
||||
datum = {
|
||||
title: spec.title != null,
|
||||
scales: scales,
|
||||
type: type,
|
||||
vgrad: type !== 'symbol' && _.isVertical()
|
||||
};
|
||||
dataRef = ref(scope.add(Collect(null, [datum])));
|
||||
|
||||
// encoding properties for legend group
|
||||
legendEncode = extendEncode(
|
||||
buildLegendEncode(_, spec, config), legendEncode, Skip
|
||||
);
|
||||
|
||||
// encoding properties for legend entry sub-group
|
||||
entryEncode = {enter: {x: {value: 0}, y: {value: 0}}};
|
||||
|
||||
// data source for legend values
|
||||
entryRef = ref(scope.add(LegendEntries(params = {
|
||||
type: type,
|
||||
scale: scope.scaleRef(scale),
|
||||
count: scope.objectProperty(_('tickCount')),
|
||||
limit: scope.property(_('symbolLimit')),
|
||||
values: scope.objectProperty(spec.values),
|
||||
minstep: scope.property(spec.tickMinStep),
|
||||
formatType: scope.property(spec.formatType),
|
||||
formatSpecifier: scope.property(spec.format)
|
||||
})));
|
||||
|
||||
// continuous gradient legend
|
||||
if (type === Gradient) {
|
||||
children = [
|
||||
legendGradient(spec, scale, config, encode.gradient),
|
||||
legendGradientLabels(spec, config, encode.labels, entryRef)
|
||||
];
|
||||
// adjust default tick count based on the gradient length
|
||||
params.count = params.count || scope.signalRef(
|
||||
`max(2,2*floor((${deref(_.gradientLength())})/100))`
|
||||
);
|
||||
}
|
||||
|
||||
// discrete gradient legend
|
||||
else if (type === Discrete) {
|
||||
children = [
|
||||
legendGradientDiscrete(spec, scale, config, encode.gradient, entryRef),
|
||||
legendGradientLabels(spec, config, encode.labels, entryRef)
|
||||
];
|
||||
}
|
||||
|
||||
// symbol legend
|
||||
else {
|
||||
// determine legend symbol group layout
|
||||
entryLayout = legendSymbolLayout(spec, config);
|
||||
children = [
|
||||
legendSymbolGroups(spec, config, encode, entryRef, deref(entryLayout.columns))
|
||||
];
|
||||
// pass symbol size information to legend entry generator
|
||||
params.size = sizeExpression(spec, scope, children[0].marks);
|
||||
}
|
||||
|
||||
// generate legend marks
|
||||
children = [
|
||||
guideGroup({
|
||||
role: LegendEntryRole,
|
||||
from: dataRef,
|
||||
encode: entryEncode,
|
||||
marks: children,
|
||||
layout: entryLayout,
|
||||
interactive
|
||||
})
|
||||
];
|
||||
|
||||
// include legend title if defined
|
||||
if (datum.title) {
|
||||
children.push(legendTitle(spec, config, encode.title, dataRef));
|
||||
}
|
||||
|
||||
// parse legend specification
|
||||
return parseMark(
|
||||
guideGroup({
|
||||
role: LegendRole,
|
||||
from: dataRef,
|
||||
encode: legendEncode,
|
||||
marks: children,
|
||||
aria: _('aria'),
|
||||
description: _('description'),
|
||||
zindex: _('zindex'),
|
||||
name,
|
||||
interactive,
|
||||
style
|
||||
}),
|
||||
scope
|
||||
);
|
||||
}
|
||||
|
||||
function legendType(spec, scaleType) {
|
||||
var type = spec.type || Symbols;
|
||||
|
||||
if (!spec.type && scaleCount(spec) === 1 && (spec.fill || spec.stroke)) {
|
||||
type = isContinuous(scaleType) ? Gradient
|
||||
: isDiscretizing(scaleType) ? Discrete
|
||||
: Symbols;
|
||||
}
|
||||
|
||||
return type !== Gradient ? type
|
||||
: isDiscretizing(scaleType) ? Discrete
|
||||
: Gradient;
|
||||
}
|
||||
|
||||
function scaleCount(spec) {
|
||||
return LegendScales.reduce(function(count, type) {
|
||||
return count + (spec[type] ? 1 : 0);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function buildLegendEncode(_, spec, config) {
|
||||
var encode = {enter: {}, update: {}};
|
||||
|
||||
addEncoders(encode, {
|
||||
orient: _('orient'),
|
||||
offset: _('offset'),
|
||||
padding: _('padding'),
|
||||
titlePadding: _('titlePadding'),
|
||||
cornerRadius: _('cornerRadius'),
|
||||
fill: _('fillColor'),
|
||||
stroke: _('strokeColor'),
|
||||
strokeWidth: config.strokeWidth,
|
||||
strokeDash: config.strokeDash,
|
||||
x: _('legendX'),
|
||||
y: _('legendY'),
|
||||
|
||||
// accessibility support
|
||||
format: spec.format,
|
||||
formatType: spec.formatType
|
||||
});
|
||||
|
||||
return encode;
|
||||
}
|
||||
|
||||
function sizeExpression(spec, scope, marks) {
|
||||
var size = deref(getChannel('size', spec, marks)),
|
||||
strokeWidth = deref(getChannel('strokeWidth', spec, marks)),
|
||||
fontSize = deref(getFontSize(marks[1].encode, scope, GuideLabelStyle));
|
||||
|
||||
return parseExpression(
|
||||
`max(ceil(sqrt(${size})+${strokeWidth}),${fontSize})`,
|
||||
scope
|
||||
);
|
||||
}
|
||||
|
||||
function getChannel(name, spec, marks) {
|
||||
return spec[name]
|
||||
? `scale("${spec[name]}",datum)`
|
||||
: getEncoding(name, marks[0].encode);
|
||||
}
|
||||
|
||||
function getFontSize(encode, scope, style) {
|
||||
return getEncoding('fontSize', encode) || getStyle('fontSize', scope, style);
|
||||
}
|
||||
163
node_modules/vega-parser/src/parsers/mark.js
generated
vendored
Normal file
163
node_modules/vega-parser/src/parsers/mark.js
generated
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
import parseEncode from './encode';
|
||||
import clip from './marks/clip';
|
||||
import definition from './marks/definition';
|
||||
import interactive from './marks/interactive';
|
||||
import parseData from './marks/data';
|
||||
import parseFacet from './marks/facet';
|
||||
import parseSubflow from './marks/subflow';
|
||||
import getRole from './marks/role';
|
||||
import {GroupMark} from './marks/marktypes';
|
||||
import {FrameRole, MarkRole, ScopeRole} from './marks/roles';
|
||||
import parseTransform from './transform';
|
||||
import parseTrigger from './trigger';
|
||||
import DataScope from '../DataScope';
|
||||
import {fieldRef, isSignal, ref} from '../util';
|
||||
import {error} from 'vega-util';
|
||||
import {Bound, Collect, DataJoin, Encode, Mark, Overlap, Render, Sieve, SortItems, ViewLayout} from '../transforms';
|
||||
|
||||
export default function(spec, scope) {
|
||||
var role = getRole(spec),
|
||||
group = spec.type === GroupMark,
|
||||
facet = spec.from && spec.from.facet,
|
||||
layout = spec.layout || role === ScopeRole || role === FrameRole,
|
||||
nested = role === MarkRole || layout || facet,
|
||||
overlap = spec.overlap,
|
||||
ops, op, input, store, enc, bound, render, sieve, name,
|
||||
joinRef, markRef, encodeRef, layoutRef, boundRef;
|
||||
|
||||
// resolve input data
|
||||
input = parseData(spec.from, group, scope);
|
||||
|
||||
// data join to map tuples to visual items
|
||||
op = scope.add(DataJoin({
|
||||
key: input.key || (spec.key ? fieldRef(spec.key) : undefined),
|
||||
pulse: input.pulse,
|
||||
clean: !group
|
||||
}));
|
||||
joinRef = ref(op);
|
||||
|
||||
// collect visual items
|
||||
op = store = scope.add(Collect({pulse: joinRef}));
|
||||
|
||||
// connect visual items to scenegraph
|
||||
op = scope.add(Mark({
|
||||
markdef: definition(spec),
|
||||
interactive: interactive(spec.interactive, scope),
|
||||
clip: clip(spec.clip, scope),
|
||||
context: {$context: true},
|
||||
groups: scope.lookup(),
|
||||
parent: scope.signals.parent ? scope.signalRef('parent') : null,
|
||||
index: scope.markpath(),
|
||||
pulse: ref(op)
|
||||
}));
|
||||
markRef = ref(op);
|
||||
|
||||
// add visual encoders
|
||||
op = enc = scope.add(Encode(parseEncode(
|
||||
spec.encode, spec.type, role, spec.style, scope,
|
||||
{mod: false, pulse: markRef}
|
||||
)));
|
||||
|
||||
// monitor parent marks to propagate changes
|
||||
op.params.parent = scope.encode();
|
||||
|
||||
// add post-encoding transforms, if defined
|
||||
if (spec.transform) {
|
||||
spec.transform.forEach(function(_) {
|
||||
const tx = parseTransform(_, scope),
|
||||
md = tx.metadata;
|
||||
if (md.generates || md.changes) {
|
||||
error('Mark transforms should not generate new data.');
|
||||
}
|
||||
if (!md.nomod) enc.params.mod = true; // update encode mod handling
|
||||
tx.params.pulse = ref(op);
|
||||
scope.add(op = tx);
|
||||
});
|
||||
}
|
||||
|
||||
// if item sort specified, perform post-encoding
|
||||
if (spec.sort) {
|
||||
op = scope.add(SortItems({
|
||||
sort: scope.compareRef(spec.sort),
|
||||
pulse: ref(op)
|
||||
}));
|
||||
}
|
||||
|
||||
encodeRef = ref(op);
|
||||
|
||||
// add view layout operator if needed
|
||||
if (facet || layout) {
|
||||
layout = scope.add(ViewLayout({
|
||||
layout: scope.objectProperty(spec.layout),
|
||||
legends: scope.legends,
|
||||
mark: markRef,
|
||||
pulse: encodeRef
|
||||
}));
|
||||
layoutRef = ref(layout);
|
||||
}
|
||||
|
||||
// compute bounding boxes
|
||||
bound = scope.add(Bound({mark: markRef, pulse: layoutRef || encodeRef}));
|
||||
boundRef = ref(bound);
|
||||
|
||||
// if group mark, recurse to parse nested content
|
||||
if (group) {
|
||||
// juggle layout & bounds to ensure they run *after* any faceting transforms
|
||||
if (nested) { ops = scope.operators; ops.pop(); if (layout) ops.pop(); }
|
||||
|
||||
scope.pushState(encodeRef, layoutRef || boundRef, joinRef);
|
||||
facet ? parseFacet(spec, scope, input) // explicit facet
|
||||
: nested ? parseSubflow(spec, scope, input) // standard mark group
|
||||
: scope.parse(spec); // guide group, we can avoid nested scopes
|
||||
scope.popState();
|
||||
|
||||
if (nested) { if (layout) ops.push(layout); ops.push(bound); }
|
||||
}
|
||||
|
||||
// if requested, add overlap removal transform
|
||||
if (overlap) {
|
||||
boundRef = parseOverlap(overlap, boundRef, scope);
|
||||
}
|
||||
|
||||
// render / sieve items
|
||||
render = scope.add(Render({pulse: boundRef}));
|
||||
sieve = scope.add(Sieve({pulse: ref(render)}, undefined, scope.parent()));
|
||||
|
||||
// if mark is named, make accessible as reactive geometry
|
||||
// add trigger updates if defined
|
||||
if (spec.name != null) {
|
||||
name = spec.name;
|
||||
scope.addData(name, new DataScope(scope, store, render, sieve));
|
||||
if (spec.on) spec.on.forEach(function(on) {
|
||||
if (on.insert || on.remove || on.toggle) {
|
||||
error('Marks only support modify triggers.');
|
||||
}
|
||||
parseTrigger(on, scope, name);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function parseOverlap(overlap, source, scope) {
|
||||
var method = overlap.method,
|
||||
bound = overlap.bound,
|
||||
sep = overlap.separation, tol;
|
||||
|
||||
var params = {
|
||||
separation: isSignal(sep) ? scope.signalRef(sep.signal) : sep,
|
||||
method: isSignal(method) ? scope.signalRef(method.signal) : method,
|
||||
pulse: source
|
||||
};
|
||||
|
||||
if (overlap.order) {
|
||||
params.sort = scope.compareRef({field: overlap.order});
|
||||
}
|
||||
|
||||
if (bound) {
|
||||
tol = bound.tolerance;
|
||||
params.boundTolerance = isSignal(tol) ? scope.signalRef(tol.signal) : +tol;
|
||||
params.boundScale = scope.scaleRef(bound.scale);
|
||||
params.boundOrient = bound.orient;
|
||||
}
|
||||
|
||||
return ref(scope.add(Overlap(params)));
|
||||
}
|
||||
25
node_modules/vega-parser/src/parsers/marks/clip.js
generated
vendored
Normal file
25
node_modules/vega-parser/src/parsers/marks/clip.js
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
import {isObject, stringValue} from 'vega-util';
|
||||
|
||||
export default function(clip, scope) {
|
||||
var expr;
|
||||
|
||||
if (isObject(clip)) {
|
||||
if (clip.signal) {
|
||||
expr = clip.signal;
|
||||
} else if (clip.path) {
|
||||
expr = 'pathShape(' + param(clip.path) + ')';
|
||||
} else if (clip.sphere) {
|
||||
expr = 'geoShape(' + param(clip.sphere) + ', {type: "Sphere"})';
|
||||
}
|
||||
}
|
||||
|
||||
return expr
|
||||
? scope.signalRef(expr)
|
||||
: !!clip;
|
||||
}
|
||||
|
||||
function param(value) {
|
||||
return isObject(value) && value.signal
|
||||
? value.signal
|
||||
: stringValue(value);
|
||||
}
|
||||
55
node_modules/vega-parser/src/parsers/marks/data.js
generated
vendored
Normal file
55
node_modules/vega-parser/src/parsers/marks/data.js
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
import parseTransform from '../transform';
|
||||
import {Collect} from '../../transforms';
|
||||
import {ref} from '../../util';
|
||||
import {array, error, extend} from 'vega-util';
|
||||
|
||||
export default function(from, group, scope) {
|
||||
var facet, key, op, dataRef, parent;
|
||||
|
||||
// if no source data, generate singleton datum
|
||||
if (!from) {
|
||||
dataRef = ref(scope.add(Collect(null, [{}])));
|
||||
}
|
||||
|
||||
// if faceted, process facet specification
|
||||
else if (facet = from.facet) {
|
||||
if (!group) error('Only group marks can be faceted.');
|
||||
|
||||
// use pre-faceted source data, if available
|
||||
if (facet.field != null) {
|
||||
dataRef = parent = getDataRef(facet, scope);
|
||||
} else {
|
||||
// generate facet aggregates if no direct data specification
|
||||
if (!from.data) {
|
||||
op = parseTransform(extend({
|
||||
type: 'aggregate',
|
||||
groupby: array(facet.groupby)
|
||||
}, facet.aggregate), scope);
|
||||
op.params.key = scope.keyRef(facet.groupby);
|
||||
op.params.pulse = getDataRef(facet, scope);
|
||||
dataRef = parent = ref(scope.add(op));
|
||||
} else {
|
||||
parent = ref(scope.getData(from.data).aggregate);
|
||||
}
|
||||
|
||||
key = scope.keyRef(facet.groupby, true);
|
||||
}
|
||||
}
|
||||
|
||||
// if not yet defined, get source data reference
|
||||
if (!dataRef) {
|
||||
dataRef = getDataRef(from, scope);
|
||||
}
|
||||
|
||||
return {
|
||||
key: key,
|
||||
pulse: dataRef,
|
||||
parent: parent
|
||||
};
|
||||
}
|
||||
|
||||
export function getDataRef(from, scope) {
|
||||
return from.$ref ? from
|
||||
: from.data && from.data.$ref ? from.data
|
||||
: ref(scope.getData(from.data).output);
|
||||
}
|
||||
12
node_modules/vega-parser/src/parsers/marks/definition.js
generated
vendored
Normal file
12
node_modules/vega-parser/src/parsers/marks/definition.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import role from './role';
|
||||
|
||||
export default function(spec) {
|
||||
return {
|
||||
marktype: spec.type,
|
||||
name: spec.name || undefined,
|
||||
role: spec.role || role(spec),
|
||||
zindex: +spec.zindex || undefined,
|
||||
aria: spec.aria,
|
||||
description: spec.description
|
||||
};
|
||||
}
|
||||
46
node_modules/vega-parser/src/parsers/marks/facet.js
generated
vendored
Normal file
46
node_modules/vega-parser/src/parsers/marks/facet.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
import {getDataRef} from './data';
|
||||
import DataScope from '../../DataScope';
|
||||
import {Collect, Facet, PreFacet, Sieve} from '../../transforms';
|
||||
import {ref} from '../../util';
|
||||
import {error, stringValue} from 'vega-util';
|
||||
|
||||
export default function(spec, scope, group) {
|
||||
var facet = spec.from.facet,
|
||||
name = facet.name,
|
||||
data = getDataRef(facet, scope),
|
||||
subscope, source, values, op;
|
||||
|
||||
if (!facet.name) {
|
||||
error('Facet must have a name: ' + stringValue(facet));
|
||||
}
|
||||
if (!facet.data) {
|
||||
error('Facet must reference a data set: ' + stringValue(facet));
|
||||
}
|
||||
|
||||
if (facet.field) {
|
||||
op = scope.add(PreFacet({
|
||||
field: scope.fieldRef(facet.field),
|
||||
pulse: data
|
||||
}));
|
||||
} else if (facet.groupby) {
|
||||
op = scope.add(Facet({
|
||||
key: scope.keyRef(facet.groupby),
|
||||
group: ref(scope.proxy(group.parent)),
|
||||
pulse: data
|
||||
}));
|
||||
} else {
|
||||
error('Facet must specify groupby or field: ' + stringValue(facet));
|
||||
}
|
||||
|
||||
// initialize facet subscope
|
||||
subscope = scope.fork();
|
||||
source = subscope.add(Collect());
|
||||
values = subscope.add(Sieve({pulse: ref(source)}));
|
||||
subscope.addData(name, new DataScope(subscope, source, source, values));
|
||||
subscope.addSignal('parent', null);
|
||||
|
||||
// parse faceted subflow
|
||||
op.params.subflow = {
|
||||
$subflow: subscope.parse(spec).toRuntime()
|
||||
};
|
||||
}
|
||||
5
node_modules/vega-parser/src/parsers/marks/interactive.js
generated
vendored
Normal file
5
node_modules/vega-parser/src/parsers/marks/interactive.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
export default function(spec, scope) {
|
||||
return spec && spec.signal ? scope.signalRef(spec.signal)
|
||||
: spec === false ? false
|
||||
: true;
|
||||
}
|
||||
5
node_modules/vega-parser/src/parsers/marks/marktypes.js
generated
vendored
Normal file
5
node_modules/vega-parser/src/parsers/marks/marktypes.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
export var GroupMark = 'group';
|
||||
export var RectMark = 'rect';
|
||||
export var RuleMark = 'rule';
|
||||
export var SymbolMark = 'symbol';
|
||||
export var TextMark = 'text';
|
||||
9
node_modules/vega-parser/src/parsers/marks/role.js
generated
vendored
Normal file
9
node_modules/vega-parser/src/parsers/marks/role.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import {GroupMark} from './marktypes';
|
||||
import {MarkRole, ScopeRole} from './roles';
|
||||
|
||||
export default function(spec) {
|
||||
var role = spec.role || '';
|
||||
return (!role.indexOf('axis') || !role.indexOf('legend') || !role.indexOf('title'))
|
||||
? role
|
||||
: spec.type === GroupMark ? ScopeRole : (role || MarkRole);
|
||||
}
|
||||
22
node_modules/vega-parser/src/parsers/marks/roles.js
generated
vendored
Normal file
22
node_modules/vega-parser/src/parsers/marks/roles.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
export var MarkRole = 'mark';
|
||||
export var FrameRole = 'frame';
|
||||
export var ScopeRole = 'scope';
|
||||
|
||||
export var AxisRole = 'axis';
|
||||
export var AxisDomainRole = 'axis-domain';
|
||||
export var AxisGridRole = 'axis-grid';
|
||||
export var AxisLabelRole = 'axis-label';
|
||||
export var AxisTickRole = 'axis-tick';
|
||||
export var AxisTitleRole = 'axis-title';
|
||||
|
||||
export var LegendRole = 'legend';
|
||||
export var LegendBandRole = 'legend-band';
|
||||
export var LegendEntryRole = 'legend-entry';
|
||||
export var LegendGradientRole = 'legend-gradient';
|
||||
export var LegendLabelRole = 'legend-label';
|
||||
export var LegendSymbolRole = 'legend-symbol';
|
||||
export var LegendTitleRole = 'legend-title';
|
||||
|
||||
export var TitleRole = 'title';
|
||||
export var TitleTextRole = 'title-text';
|
||||
export var TitleSubtitleRole = 'title-subtitle';
|
||||
14
node_modules/vega-parser/src/parsers/marks/subflow.js
generated
vendored
Normal file
14
node_modules/vega-parser/src/parsers/marks/subflow.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import {PreFacet, Sieve} from '../../transforms';
|
||||
|
||||
export default function(spec, scope, input) {
|
||||
var op = scope.add(PreFacet({pulse: input.pulse})),
|
||||
subscope = scope.fork();
|
||||
|
||||
subscope.add(Sieve());
|
||||
subscope.addSignal('parent', null);
|
||||
|
||||
// parse group mark subflow
|
||||
op.params.subflow = {
|
||||
$subflow: subscope.parse(spec).toRuntime()
|
||||
};
|
||||
}
|
||||
16
node_modules/vega-parser/src/parsers/padding.js
generated
vendored
Normal file
16
node_modules/vega-parser/src/parsers/padding.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import {isObject} from 'vega-util';
|
||||
|
||||
const number = _ => +_ || 0;
|
||||
|
||||
const paddingObject = _ => ({top: _, bottom: _, left: _, right: _});
|
||||
|
||||
export default function(spec) {
|
||||
return !isObject(spec) ? paddingObject(number(spec))
|
||||
: spec.signal ? spec
|
||||
: {
|
||||
top: number(spec.top),
|
||||
bottom: number(spec.bottom),
|
||||
left: number(spec.left),
|
||||
right: number(spec.right)
|
||||
};
|
||||
}
|
||||
28
node_modules/vega-parser/src/parsers/projection.js
generated
vendored
Normal file
28
node_modules/vega-parser/src/parsers/projection.js
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
import {error, isArray, isObject, stringValue} from 'vega-util';
|
||||
|
||||
export default function(proj, scope) {
|
||||
var config = scope.config.projection || {},
|
||||
params = {};
|
||||
|
||||
for (var name in proj) {
|
||||
if (name === 'name') continue;
|
||||
params[name] = parseParameter(proj[name], name, scope);
|
||||
}
|
||||
|
||||
// apply projection defaults from config
|
||||
for (name in config) {
|
||||
if (params[name] == null) {
|
||||
params[name] = parseParameter(config[name], name, scope);
|
||||
}
|
||||
}
|
||||
|
||||
scope.addProjection(proj.name, params);
|
||||
}
|
||||
|
||||
function parseParameter(_, name, scope) {
|
||||
return isArray(_) ? _.map(function(_) { return parseParameter(_, name, scope); })
|
||||
: !isObject(_) ? _
|
||||
: _.signal ? scope.signalRef(_.signal)
|
||||
: name === 'fit' ? _
|
||||
: error('Unsupported parameter object: ' + stringValue(_));
|
||||
}
|
||||
274
node_modules/vega-parser/src/parsers/scale.js
generated
vendored
Normal file
274
node_modules/vega-parser/src/parsers/scale.js
generated
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
import {
|
||||
Aggregate, Collect, MultiExtent, MultiValues, Sieve, Values
|
||||
} from '../transforms';
|
||||
import {aggrField, keyFieldRef, ref} from '../util';
|
||||
|
||||
import {isDiscrete, isQuantile, isValidScaleType} from 'vega-scale';
|
||||
import {
|
||||
error, extend, hasOwnProperty, isArray, isObject, isString, stringValue
|
||||
} from 'vega-util';
|
||||
|
||||
var FIELD_REF_ID = 0;
|
||||
|
||||
var MULTIDOMAIN_SORT_OPS = {min: 'min', max: 'max', count: 'sum'};
|
||||
|
||||
export function initScale(spec, scope) {
|
||||
var type = spec.type || 'linear';
|
||||
|
||||
if (!isValidScaleType(type)) {
|
||||
error('Unrecognized scale type: ' + stringValue(type));
|
||||
}
|
||||
|
||||
scope.addScale(spec.name, {
|
||||
type: type,
|
||||
domain: undefined
|
||||
});
|
||||
}
|
||||
|
||||
export function parseScale(spec, scope) {
|
||||
var params = scope.getScale(spec.name).params,
|
||||
key;
|
||||
|
||||
params.domain = parseScaleDomain(spec.domain, spec, scope);
|
||||
|
||||
if (spec.range != null) {
|
||||
params.range = parseScaleRange(spec, scope, params);
|
||||
}
|
||||
|
||||
if (spec.interpolate != null) {
|
||||
parseScaleInterpolate(spec.interpolate, params);
|
||||
}
|
||||
|
||||
if (spec.nice != null) {
|
||||
params.nice = parseScaleNice(spec.nice);
|
||||
}
|
||||
|
||||
if (spec.bins != null) {
|
||||
params.bins = parseScaleBins(spec.bins, scope);
|
||||
}
|
||||
|
||||
for (key in spec) {
|
||||
if (hasOwnProperty(params, key) || key === 'name') continue;
|
||||
params[key] = parseLiteral(spec[key], scope);
|
||||
}
|
||||
}
|
||||
|
||||
function parseLiteral(v, scope) {
|
||||
return !isObject(v) ? v
|
||||
: v.signal ? scope.signalRef(v.signal)
|
||||
: error('Unsupported object: ' + stringValue(v));
|
||||
}
|
||||
|
||||
function parseArray(v, scope) {
|
||||
return v.signal
|
||||
? scope.signalRef(v.signal)
|
||||
: v.map(v => parseLiteral(v, scope));
|
||||
}
|
||||
|
||||
function dataLookupError(name) {
|
||||
error('Can not find data set: ' + stringValue(name));
|
||||
}
|
||||
|
||||
// -- SCALE DOMAIN ----
|
||||
|
||||
function parseScaleDomain(domain, spec, scope) {
|
||||
if (!domain) {
|
||||
if (spec.domainMin != null || spec.domainMax != null) {
|
||||
error('No scale domain defined for domainMin/domainMax to override.');
|
||||
}
|
||||
return; // default domain
|
||||
}
|
||||
|
||||
return domain.signal ? scope.signalRef(domain.signal)
|
||||
: (isArray(domain) ? explicitDomain
|
||||
: domain.fields ? multipleDomain
|
||||
: singularDomain)(domain, spec, scope);
|
||||
}
|
||||
|
||||
function explicitDomain(domain, spec, scope) {
|
||||
return domain.map(function(v) {
|
||||
return parseLiteral(v, scope);
|
||||
});
|
||||
}
|
||||
|
||||
function singularDomain(domain, spec, scope) {
|
||||
var data = scope.getData(domain.data);
|
||||
if (!data) dataLookupError(domain.data);
|
||||
|
||||
return isDiscrete(spec.type)
|
||||
? data.valuesRef(scope, domain.field, parseSort(domain.sort, false))
|
||||
: isQuantile(spec.type) ? data.domainRef(scope, domain.field)
|
||||
: data.extentRef(scope, domain.field);
|
||||
}
|
||||
|
||||
function multipleDomain(domain, spec, scope) {
|
||||
var data = domain.data,
|
||||
fields = domain.fields.reduce(function(dom, d) {
|
||||
d = isString(d) ? {data: data, field: d}
|
||||
: (isArray(d) || d.signal) ? fieldRef(d, scope)
|
||||
: d;
|
||||
dom.push(d);
|
||||
return dom;
|
||||
}, []);
|
||||
|
||||
return (isDiscrete(spec.type) ? ordinalMultipleDomain
|
||||
: isQuantile(spec.type) ? quantileMultipleDomain
|
||||
: numericMultipleDomain)(domain, scope, fields);
|
||||
}
|
||||
|
||||
function fieldRef(data, scope) {
|
||||
var name = '_:vega:_' + (FIELD_REF_ID++),
|
||||
coll = Collect({});
|
||||
|
||||
if (isArray(data)) {
|
||||
coll.value = {$ingest: data};
|
||||
} else if (data.signal) {
|
||||
var code = 'setdata(' + stringValue(name) + ',' + data.signal + ')';
|
||||
coll.params.input = scope.signalRef(code);
|
||||
}
|
||||
scope.addDataPipeline(name, [coll, Sieve({})]);
|
||||
return {data: name, field: 'data'};
|
||||
}
|
||||
|
||||
function ordinalMultipleDomain(domain, scope, fields) {
|
||||
var sort = parseSort(domain.sort, true),
|
||||
counts, p, a, c, v;
|
||||
|
||||
// get value counts for each domain field
|
||||
counts = fields.map(function(f) {
|
||||
var data = scope.getData(f.data);
|
||||
if (!data) dataLookupError(f.data);
|
||||
return data.countsRef(scope, f.field, sort);
|
||||
});
|
||||
|
||||
// aggregate the results from each domain field
|
||||
p = {groupby: keyFieldRef, pulse: counts};
|
||||
if (sort) {
|
||||
a = sort.op || 'count';
|
||||
v = sort.field ? aggrField(a, sort.field) : 'count';
|
||||
p.ops = [MULTIDOMAIN_SORT_OPS[a]];
|
||||
p.fields = [scope.fieldRef(v)];
|
||||
p.as = [v];
|
||||
}
|
||||
a = scope.add(Aggregate(p));
|
||||
|
||||
// collect aggregate output
|
||||
c = scope.add(Collect({pulse: ref(a)}));
|
||||
|
||||
// extract values for combined domain
|
||||
v = scope.add(Values({
|
||||
field: keyFieldRef,
|
||||
sort: scope.sortRef(sort),
|
||||
pulse: ref(c)
|
||||
}));
|
||||
|
||||
return ref(v);
|
||||
}
|
||||
|
||||
function parseSort(sort, multidomain) {
|
||||
if (sort) {
|
||||
if (!sort.field && !sort.op) {
|
||||
if (isObject(sort)) sort.field = 'key';
|
||||
else sort = {field: 'key'};
|
||||
} else if (!sort.field && sort.op !== 'count') {
|
||||
error('No field provided for sort aggregate op: ' + sort.op);
|
||||
} else if (multidomain && sort.field) {
|
||||
if (sort.op && !MULTIDOMAIN_SORT_OPS[sort.op]) {
|
||||
error('Multiple domain scales can not be sorted using ' + sort.op);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sort;
|
||||
}
|
||||
|
||||
function quantileMultipleDomain(domain, scope, fields) {
|
||||
// get value arrays for each domain field
|
||||
var values = fields.map(function(f) {
|
||||
var data = scope.getData(f.data);
|
||||
if (!data) dataLookupError(f.data);
|
||||
return data.domainRef(scope, f.field);
|
||||
});
|
||||
|
||||
// combine value arrays
|
||||
return ref(scope.add(MultiValues({values: values})));
|
||||
}
|
||||
|
||||
function numericMultipleDomain(domain, scope, fields) {
|
||||
// get extents for each domain field
|
||||
var extents = fields.map(function(f) {
|
||||
var data = scope.getData(f.data);
|
||||
if (!data) dataLookupError(f.data);
|
||||
return data.extentRef(scope, f.field);
|
||||
});
|
||||
|
||||
// combine extents
|
||||
return ref(scope.add(MultiExtent({extents: extents})));
|
||||
}
|
||||
|
||||
// -- SCALE BINS -----
|
||||
|
||||
function parseScaleBins(v, scope) {
|
||||
return v.signal || isArray(v)
|
||||
? parseArray(v, scope)
|
||||
: scope.objectProperty(v);
|
||||
}
|
||||
|
||||
// -- SCALE NICE -----
|
||||
|
||||
function parseScaleNice(nice) {
|
||||
return isObject(nice)
|
||||
? {
|
||||
interval: parseLiteral(nice.interval),
|
||||
step: parseLiteral(nice.step)
|
||||
}
|
||||
: parseLiteral(nice);
|
||||
}
|
||||
|
||||
// -- SCALE INTERPOLATION -----
|
||||
|
||||
function parseScaleInterpolate(interpolate, params) {
|
||||
params.interpolate = parseLiteral(interpolate.type || interpolate);
|
||||
if (interpolate.gamma != null) {
|
||||
params.interpolateGamma = parseLiteral(interpolate.gamma);
|
||||
}
|
||||
}
|
||||
|
||||
// -- SCALE RANGE -----
|
||||
|
||||
function parseScaleRange(spec, scope, params) {
|
||||
var range = spec.range,
|
||||
config = scope.config.range;
|
||||
|
||||
if (range.signal) {
|
||||
return scope.signalRef(range.signal);
|
||||
} else if (isString(range)) {
|
||||
if (config && hasOwnProperty(config, range)) {
|
||||
spec = extend({}, spec, {range: config[range]});
|
||||
return parseScaleRange(spec, scope, params);
|
||||
} else if (range === 'width') {
|
||||
range = [0, {signal: 'width'}];
|
||||
} else if (range === 'height') {
|
||||
range = isDiscrete(spec.type)
|
||||
? [0, {signal: 'height'}]
|
||||
: [{signal: 'height'}, 0];
|
||||
} else {
|
||||
error('Unrecognized scale range value: ' + stringValue(range));
|
||||
}
|
||||
} else if (range.scheme) {
|
||||
params.scheme = isArray(range.scheme)
|
||||
? parseArray(range.scheme, scope)
|
||||
: parseLiteral(range.scheme, scope);
|
||||
if (range.extent) params.schemeExtent = parseArray(range.extent, scope);
|
||||
if (range.count) params.schemeCount = parseLiteral(range.count, scope);
|
||||
return;
|
||||
} else if (range.step) {
|
||||
params.rangeStep = parseLiteral(range.step, scope);
|
||||
return;
|
||||
} else if (isDiscrete(spec.type) && !isArray(range)) {
|
||||
return parseScaleDomain(range, spec, scope);
|
||||
} else if (!isArray(range)) {
|
||||
error('Unsupported range type: ' + stringValue(range));
|
||||
}
|
||||
|
||||
return range.map(v => (isArray(v) ? parseArray : parseLiteral)(v, scope));
|
||||
}
|
||||
50
node_modules/vega-parser/src/parsers/scope.js
generated
vendored
Normal file
50
node_modules/vega-parser/src/parsers/scope.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
import parseSignalUpdates from './signal-updates';
|
||||
import {initScale, parseScale} from './scale';
|
||||
import parseProjection from './projection';
|
||||
import parseLegend from './legend';
|
||||
import parseSignal from './signal';
|
||||
import parseTitle from './title';
|
||||
import parseData from './data';
|
||||
import parseMark from './mark';
|
||||
import parseAxis from './axis';
|
||||
import {array} from 'vega-util';
|
||||
|
||||
export default function(spec, scope, preprocessed) {
|
||||
var signals = array(spec.signals),
|
||||
scales = array(spec.scales);
|
||||
|
||||
// parse signal definitions, if not already preprocessed
|
||||
if (!preprocessed) signals.forEach(_ => parseSignal(_, scope));
|
||||
|
||||
// parse cartographic projection definitions
|
||||
array(spec.projections).forEach(_ => parseProjection(_, scope));
|
||||
|
||||
// initialize scale references
|
||||
scales.forEach(_ => initScale(_, scope));
|
||||
|
||||
// parse data sources
|
||||
array(spec.data).forEach(_ => parseData(_, scope));
|
||||
|
||||
// parse scale definitions
|
||||
scales.forEach(_ => parseScale(_, scope));
|
||||
|
||||
// parse signal updates
|
||||
(preprocessed || signals).forEach(_ => parseSignalUpdates(_, scope));
|
||||
|
||||
// parse axis definitions
|
||||
array(spec.axes).forEach(_ => parseAxis(_, scope));
|
||||
|
||||
// parse mark definitions
|
||||
array(spec.marks).forEach(_ => parseMark(_, scope));
|
||||
|
||||
// parse legend definitions
|
||||
array(spec.legends).forEach(_ => parseLegend(_, scope));
|
||||
|
||||
// parse title, if defined
|
||||
if (spec.title) parseTitle(spec.title, scope);
|
||||
|
||||
// parse collected lambda (anonymous) expressions
|
||||
scope.parseLambdas();
|
||||
|
||||
return scope;
|
||||
}
|
||||
29
node_modules/vega-parser/src/parsers/signal-updates.js
generated
vendored
Normal file
29
node_modules/vega-parser/src/parsers/signal-updates.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
import parseUpdate from './update';
|
||||
import {parseExpression} from 'vega-functions';
|
||||
import {error} from 'vega-util';
|
||||
|
||||
export default function(signal, scope) {
|
||||
var op = scope.getSignal(signal.name),
|
||||
expr = signal.update;
|
||||
|
||||
if (signal.init) {
|
||||
if (expr) {
|
||||
error('Signals can not include both init and update expressions.');
|
||||
} else {
|
||||
expr = signal.init;
|
||||
op.initonly = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (expr) {
|
||||
expr = parseExpression(expr, scope);
|
||||
op.update = expr.$expr;
|
||||
op.params = expr.$params;
|
||||
}
|
||||
|
||||
if (signal.on) {
|
||||
signal.on.forEach(function(_) {
|
||||
parseUpdate(_, scope, op.id);
|
||||
});
|
||||
}
|
||||
}
|
||||
26
node_modules/vega-parser/src/parsers/signal.js
generated
vendored
Normal file
26
node_modules/vega-parser/src/parsers/signal.js
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
import {error, stringValue} from 'vega-util';
|
||||
|
||||
var OUTER = 'outer',
|
||||
OUTER_INVALID = ['value', 'update', 'init', 'react', 'bind'];
|
||||
|
||||
function outerError(prefix, name) {
|
||||
error(prefix + ' for "outer" push: ' + stringValue(name));
|
||||
}
|
||||
|
||||
export default function(signal, scope) {
|
||||
var name = signal.name;
|
||||
|
||||
if (signal.push === OUTER) {
|
||||
// signal must already be defined, raise error if not
|
||||
if (!scope.signals[name]) outerError('No prior signal definition', name);
|
||||
// signal push must not use properties reserved for standard definition
|
||||
OUTER_INVALID.forEach(function(prop) {
|
||||
if (signal[prop] !== undefined) outerError('Invalid property ', prop);
|
||||
});
|
||||
} else {
|
||||
// define a new signal in the current scope
|
||||
var op = scope.addSignal(name, signal.value);
|
||||
if (signal.react === false) op.react = false;
|
||||
if (signal.bind) scope.addBinding(name, signal.bind);
|
||||
}
|
||||
}
|
||||
95
node_modules/vega-parser/src/parsers/stream.js
generated
vendored
Normal file
95
node_modules/vega-parser/src/parsers/stream.js
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
import {Scope, View} from '../util';
|
||||
import {parseExpression} from 'vega-functions';
|
||||
import {error, stringValue} from 'vega-util';
|
||||
|
||||
var Timer = 'timer';
|
||||
|
||||
export default function parseStream(stream, scope) {
|
||||
var method = stream.merge ? mergeStream
|
||||
: stream.stream ? nestedStream
|
||||
: stream.type ? eventStream
|
||||
: error('Invalid stream specification: ' + stringValue(stream));
|
||||
|
||||
return method(stream, scope);
|
||||
}
|
||||
|
||||
function eventSource(source) {
|
||||
return source === Scope ? View : (source || View);
|
||||
}
|
||||
|
||||
function mergeStream(stream, scope) {
|
||||
var list = stream.merge.map(s => parseStream(s, scope)),
|
||||
entry = streamParameters({merge: list}, stream, scope);
|
||||
return scope.addStream(entry).id;
|
||||
}
|
||||
|
||||
function nestedStream(stream, scope) {
|
||||
var id = parseStream(stream.stream, scope),
|
||||
entry = streamParameters({stream: id}, stream, scope);
|
||||
return scope.addStream(entry).id;
|
||||
}
|
||||
|
||||
function eventStream(stream, scope) {
|
||||
var id, entry;
|
||||
|
||||
if (stream.type === Timer) {
|
||||
id = scope.event(Timer, stream.throttle);
|
||||
stream = {between: stream.between, filter: stream.filter};
|
||||
} else {
|
||||
id = scope.event(eventSource(stream.source), stream.type);
|
||||
}
|
||||
|
||||
entry = streamParameters({stream: id}, stream, scope);
|
||||
return Object.keys(entry).length === 1
|
||||
? id
|
||||
: scope.addStream(entry).id;
|
||||
}
|
||||
|
||||
function streamParameters(entry, stream, scope) {
|
||||
var param = stream.between;
|
||||
|
||||
if (param) {
|
||||
if (param.length !== 2) {
|
||||
error('Stream "between" parameter must have 2 entries: ' + stringValue(stream));
|
||||
}
|
||||
entry.between = [
|
||||
parseStream(param[0], scope),
|
||||
parseStream(param[1], scope)
|
||||
];
|
||||
}
|
||||
|
||||
param = stream.filter ? [].concat(stream.filter) : [];
|
||||
if (stream.marktype || stream.markname || stream.markrole) {
|
||||
// add filter for mark type, name and/or role
|
||||
param.push(filterMark(stream.marktype, stream.markname, stream.markrole));
|
||||
}
|
||||
if (stream.source === Scope) {
|
||||
// add filter to limit events from sub-scope only
|
||||
param.push('inScope(event.item)');
|
||||
}
|
||||
if (param.length) {
|
||||
entry.filter = parseExpression('(' + param.join(')&&(') + ')', scope).$expr;
|
||||
}
|
||||
|
||||
if ((param = stream.throttle) != null) {
|
||||
entry.throttle = +param;
|
||||
}
|
||||
|
||||
if ((param = stream.debounce) != null) {
|
||||
entry.debounce = +param;
|
||||
}
|
||||
|
||||
if (stream.consume) {
|
||||
entry.consume = true;
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
function filterMark(type, name, role) {
|
||||
var item = 'event.item';
|
||||
return item
|
||||
+ (type && type !== '*' ? '&&' + item + '.mark.marktype===\'' + type + '\'' : '')
|
||||
+ (role ? '&&' + item + '.mark.role===\'' + role + '\'' : '')
|
||||
+ (name ? '&&' + item + '.mark.name===\'' + name + '\'' : '');
|
||||
}
|
||||
159
node_modules/vega-parser/src/parsers/title.js
generated
vendored
Normal file
159
node_modules/vega-parser/src/parsers/title.js
generated
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
import {addEncoders, extendEncode} from './encode/util';
|
||||
import {GroupSubtitleStyle, GroupTitleStyle, Left, Right, Skip} from './guides/constants';
|
||||
import guideGroup from './guides/guide-group';
|
||||
import guideMark from './guides/guide-mark';
|
||||
import {alignExpr, lookup} from './guides/guide-util';
|
||||
import parseMark from './mark';
|
||||
import {TextMark} from './marks/marktypes';
|
||||
import {TitleRole, TitleSubtitleRole, TitleTextRole} from './marks/roles';
|
||||
import {Collect} from '../transforms';
|
||||
import {ref} from '../util';
|
||||
import {extend, isString} from 'vega-util';
|
||||
|
||||
const angleExpr = `item.orient==="${Left}"?-90:item.orient==="${Right}"?90:0`;
|
||||
|
||||
export default function(spec, scope) {
|
||||
spec = isString(spec) ? {text: spec} : spec;
|
||||
|
||||
var _ = lookup(spec, scope.config.title),
|
||||
encode = spec.encode || {},
|
||||
userEncode = encode.group || {},
|
||||
name = userEncode.name || undefined,
|
||||
interactive = userEncode.interactive,
|
||||
style = userEncode.style,
|
||||
children = [],
|
||||
datum, dataRef;
|
||||
|
||||
// single-element data source for group title
|
||||
datum = {};
|
||||
dataRef = ref(scope.add(Collect(null, [datum])));
|
||||
|
||||
// include title text
|
||||
children.push(buildTitle(spec, _, titleEncode(spec), dataRef));
|
||||
|
||||
// include subtitle text
|
||||
if (spec.subtitle) {
|
||||
children.push(buildSubTitle(spec, _, encode.subtitle, dataRef));
|
||||
}
|
||||
|
||||
// parse title specification
|
||||
return parseMark(
|
||||
guideGroup({
|
||||
role: TitleRole,
|
||||
from: dataRef,
|
||||
encode: groupEncode(_, userEncode),
|
||||
marks: children,
|
||||
aria: _('aria'),
|
||||
description: _('description'),
|
||||
zindex: _('zindex'),
|
||||
name,
|
||||
interactive,
|
||||
style
|
||||
}),
|
||||
scope
|
||||
);
|
||||
}
|
||||
|
||||
// provide backwards-compatibility for title custom encode;
|
||||
// the top-level encode block has been *deprecated*.
|
||||
function titleEncode(spec) {
|
||||
const encode = spec.encode;
|
||||
return (encode && encode.title) || extend({
|
||||
name: spec.name,
|
||||
interactive: spec.interactive,
|
||||
style: spec.style
|
||||
}, encode);
|
||||
}
|
||||
|
||||
function groupEncode(_, userEncode) {
|
||||
var encode = {enter: {}, update: {}};
|
||||
|
||||
addEncoders(encode, {
|
||||
orient: _('orient'),
|
||||
anchor: _('anchor'),
|
||||
align: {signal: alignExpr},
|
||||
angle: {signal: angleExpr},
|
||||
limit: _('limit'),
|
||||
frame: _('frame'),
|
||||
offset: _('offset') || 0,
|
||||
padding: _('subtitlePadding')
|
||||
});
|
||||
|
||||
return extendEncode(encode, userEncode, Skip);
|
||||
}
|
||||
|
||||
function buildTitle(spec, _, userEncode, dataRef) {
|
||||
var zero = {value: 0},
|
||||
text = spec.text,
|
||||
encode = {
|
||||
enter: {opacity: zero},
|
||||
update: {opacity: {value: 1}},
|
||||
exit: {opacity: zero}
|
||||
};
|
||||
|
||||
addEncoders(encode, {
|
||||
text: text,
|
||||
align: {signal: 'item.mark.group.align'},
|
||||
angle: {signal: 'item.mark.group.angle'},
|
||||
limit: {signal: 'item.mark.group.limit'},
|
||||
baseline: 'top',
|
||||
dx: _('dx'),
|
||||
dy: _('dy'),
|
||||
fill: _('color'),
|
||||
font: _('font'),
|
||||
fontSize: _('fontSize'),
|
||||
fontStyle: _('fontStyle'),
|
||||
fontWeight: _('fontWeight'),
|
||||
lineHeight: _('lineHeight')
|
||||
}, { // update
|
||||
align: _('align'),
|
||||
angle: _('angle'),
|
||||
baseline: _('baseline')
|
||||
});
|
||||
|
||||
return guideMark({
|
||||
type: TextMark,
|
||||
role: TitleTextRole,
|
||||
style: GroupTitleStyle,
|
||||
from: dataRef,
|
||||
encode
|
||||
}, userEncode);
|
||||
}
|
||||
|
||||
function buildSubTitle(spec, _, userEncode, dataRef) {
|
||||
var zero = {value: 0},
|
||||
text = spec.subtitle,
|
||||
encode = {
|
||||
enter: {opacity: zero},
|
||||
update: {opacity: {value: 1}},
|
||||
exit: {opacity: zero}
|
||||
};
|
||||
|
||||
addEncoders(encode, {
|
||||
text: text,
|
||||
align: {signal: 'item.mark.group.align'},
|
||||
angle: {signal: 'item.mark.group.angle'},
|
||||
limit: {signal: 'item.mark.group.limit'},
|
||||
baseline: 'top',
|
||||
dx: _('dx'),
|
||||
dy: _('dy'),
|
||||
fill: _('subtitleColor'),
|
||||
font: _('subtitleFont'),
|
||||
fontSize: _('subtitleFontSize'),
|
||||
fontStyle: _('subtitleFontStyle'),
|
||||
fontWeight: _('subtitleFontWeight'),
|
||||
lineHeight: _('subtitleLineHeight')
|
||||
}, { // update
|
||||
align: _('align'),
|
||||
angle: _('angle'),
|
||||
baseline: _('baseline')
|
||||
});
|
||||
|
||||
return guideMark({
|
||||
type: TextMark,
|
||||
role: TitleSubtitleRole,
|
||||
style: GroupSubtitleStyle,
|
||||
from: dataRef,
|
||||
encode
|
||||
}, userEncode);
|
||||
}
|
||||
156
node_modules/vega-parser/src/parsers/transform.js
generated
vendored
Normal file
156
node_modules/vega-parser/src/parsers/transform.js
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
import {Params} from '../transforms';
|
||||
import {entry, fieldRef, isSignal, ref} from '../util';
|
||||
import {definition} from 'vega-dataflow';
|
||||
import {parseExpression} from 'vega-functions';
|
||||
import {error, extend, isArray, isString, stringValue} from 'vega-util';
|
||||
|
||||
/**
|
||||
* Parse a data transform specification.
|
||||
*/
|
||||
export default function(spec, scope) {
|
||||
var def = definition(spec.type);
|
||||
if (!def) error('Unrecognized transform type: ' + stringValue(spec.type));
|
||||
|
||||
var t = entry(def.type.toLowerCase(), null, parseParameters(def, spec, scope));
|
||||
if (spec.signal) scope.addSignal(spec.signal, scope.proxy(t));
|
||||
t.metadata = def.metadata || {};
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse all parameters of a data transform.
|
||||
*/
|
||||
function parseParameters(def, spec, scope) {
|
||||
var params = {}, pdef, i, n;
|
||||
for (i=0, n=def.params.length; i<n; ++i) {
|
||||
pdef = def.params[i];
|
||||
params[pdef.name] = parseParameter(pdef, spec, scope);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a data transform parameter.
|
||||
*/
|
||||
function parseParameter(def, spec, scope) {
|
||||
var type = def.type,
|
||||
value = spec[def.name];
|
||||
|
||||
if (type === 'index') {
|
||||
return parseIndexParameter(def, spec, scope);
|
||||
} else if (value === undefined) {
|
||||
if (def.required) {
|
||||
error('Missing required ' + stringValue(spec.type)
|
||||
+ ' parameter: ' + stringValue(def.name));
|
||||
}
|
||||
return;
|
||||
} else if (type === 'param') {
|
||||
return parseSubParameters(def, spec, scope);
|
||||
} else if (type === 'projection') {
|
||||
return scope.projectionRef(spec[def.name]);
|
||||
}
|
||||
|
||||
return def.array && !isSignal(value)
|
||||
? value.map(function(v) { return parameterValue(def, v, scope); })
|
||||
: parameterValue(def, value, scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a single parameter value.
|
||||
*/
|
||||
function parameterValue(def, value, scope) {
|
||||
var type = def.type;
|
||||
|
||||
if (isSignal(value)) {
|
||||
return isExpr(type) ? error('Expression references can not be signals.')
|
||||
: isField(type) ? scope.fieldRef(value)
|
||||
: isCompare(type) ? scope.compareRef(value)
|
||||
: scope.signalRef(value.signal);
|
||||
} else {
|
||||
var expr = def.expr || isField(type);
|
||||
return expr && outerExpr(value) ? scope.exprRef(value.expr, value.as)
|
||||
: expr && outerField(value) ? fieldRef(value.field, value.as)
|
||||
: isExpr(type) ? parseExpression(value, scope)
|
||||
: isData(type) ? ref(scope.getData(value).values)
|
||||
: isField(type) ? fieldRef(value)
|
||||
: isCompare(type) ? scope.compareRef(value)
|
||||
: value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse parameter for accessing an index of another data set.
|
||||
*/
|
||||
function parseIndexParameter(def, spec, scope) {
|
||||
if (!isString(spec.from)) {
|
||||
error('Lookup "from" parameter must be a string literal.');
|
||||
}
|
||||
return scope.getData(spec.from).lookupRef(scope, spec.key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a parameter that contains one or more sub-parameter objects.
|
||||
*/
|
||||
function parseSubParameters(def, spec, scope) {
|
||||
var value = spec[def.name];
|
||||
|
||||
if (def.array) {
|
||||
if (!isArray(value)) { // signals not allowed!
|
||||
error('Expected an array of sub-parameters. Instead: ' + stringValue(value));
|
||||
}
|
||||
return value.map(function(v) {
|
||||
return parseSubParameter(def, v, scope);
|
||||
});
|
||||
} else {
|
||||
return parseSubParameter(def, value, scope);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a sub-parameter object.
|
||||
*/
|
||||
function parseSubParameter(def, value, scope) {
|
||||
var params, pdef, k, i, n;
|
||||
|
||||
// loop over defs to find matching key
|
||||
for (i=0, n=def.params.length; i<n; ++i) {
|
||||
pdef = def.params[i];
|
||||
for (k in pdef.key) {
|
||||
if (pdef.key[k] !== value[k]) { pdef = null; break; }
|
||||
}
|
||||
if (pdef) break;
|
||||
}
|
||||
// raise error if matching key not found
|
||||
if (!pdef) error('Unsupported parameter: ' + stringValue(value));
|
||||
|
||||
// parse params, create Params transform, return ref
|
||||
params = extend(parseParameters(pdef, value, scope), pdef.key);
|
||||
return ref(scope.add(Params(params)));
|
||||
}
|
||||
|
||||
// -- Utilities -----
|
||||
|
||||
export function outerExpr(_) {
|
||||
return _ && _.expr;
|
||||
}
|
||||
|
||||
export function outerField(_) {
|
||||
return _ && _.field;
|
||||
}
|
||||
|
||||
export function isData(_) {
|
||||
return _ === 'data';
|
||||
}
|
||||
|
||||
export function isExpr(_) {
|
||||
return _ === 'expr';
|
||||
}
|
||||
|
||||
export function isField(_) {
|
||||
return _ === 'field';
|
||||
}
|
||||
|
||||
export function isCompare(_) {
|
||||
return _ === 'compare';
|
||||
}
|
||||
23
node_modules/vega-parser/src/parsers/trigger.js
generated
vendored
Normal file
23
node_modules/vega-parser/src/parsers/trigger.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import {operator} from '../util';
|
||||
import {parseExpression} from 'vega-functions';
|
||||
|
||||
export default function(spec, scope, name) {
|
||||
var remove = spec.remove,
|
||||
insert = spec.insert,
|
||||
toggle = spec.toggle,
|
||||
modify = spec.modify,
|
||||
values = spec.values,
|
||||
op = scope.add(operator()),
|
||||
update, expr;
|
||||
|
||||
update = 'if(' + spec.trigger + ',modify("'
|
||||
+ name + '",'
|
||||
+ [insert, remove, toggle, modify, values]
|
||||
.map(function(_) { return _ == null ? 'null' : _; })
|
||||
.join(',')
|
||||
+ '),0)';
|
||||
|
||||
expr = parseExpression(update, scope);
|
||||
op.update = expr.$expr;
|
||||
op.params = expr.$params;
|
||||
}
|
||||
81
node_modules/vega-parser/src/parsers/update.js
generated
vendored
Normal file
81
node_modules/vega-parser/src/parsers/update.js
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
import parseStream from './stream';
|
||||
import {Scope, View} from '../util';
|
||||
import {selector} from 'vega-event-selector';
|
||||
import {parseExpression} from 'vega-functions';
|
||||
import {array, error, extend, isString, stringValue} from 'vega-util';
|
||||
|
||||
// bypass expression parser for internal operator references
|
||||
const OP_VALUE_EXPR = {
|
||||
code: '_.$value',
|
||||
ast: {type: 'Identifier', value: 'value'}
|
||||
};
|
||||
|
||||
export default function(spec, scope, target) {
|
||||
var events = spec.events,
|
||||
update = spec.update,
|
||||
encode = spec.encode,
|
||||
sources = [],
|
||||
entry = {target: target};
|
||||
|
||||
if (!events) {
|
||||
error('Signal update missing events specification.');
|
||||
}
|
||||
|
||||
// interpret as an event selector string
|
||||
if (isString(events)) {
|
||||
events = selector(events, scope.isSubscope() ? Scope : View);
|
||||
}
|
||||
|
||||
// separate event streams from signal updates
|
||||
events = array(events)
|
||||
.filter(s => s.signal || s.scale ? (sources.push(s), 0) : 1);
|
||||
|
||||
// merge internal operator listeners
|
||||
if (sources.length > 1) {
|
||||
sources = [mergeSources(sources)];
|
||||
}
|
||||
|
||||
// merge event streams, include as source
|
||||
if (events.length) {
|
||||
sources.push(events.length > 1 ? {merge: events} : events[0]);
|
||||
}
|
||||
|
||||
if (encode != null) {
|
||||
if (update) error('Signal encode and update are mutually exclusive.');
|
||||
update = 'encode(item(),' + stringValue(encode) + ')';
|
||||
}
|
||||
|
||||
// resolve update value
|
||||
entry.update = isString(update) ? parseExpression(update, scope)
|
||||
: update.expr != null ? parseExpression(update.expr, scope)
|
||||
: update.value != null ? update.value
|
||||
: update.signal != null ? {
|
||||
$expr: OP_VALUE_EXPR,
|
||||
$params: {$value: scope.signalRef(update.signal)}
|
||||
}
|
||||
: error('Invalid signal update specification.');
|
||||
|
||||
if (spec.force) {
|
||||
entry.options = {force: true};
|
||||
}
|
||||
|
||||
sources.forEach(function(source) {
|
||||
scope.addUpdate(extend(streamSource(source, scope), entry));
|
||||
});
|
||||
}
|
||||
|
||||
function streamSource(stream, scope) {
|
||||
return {
|
||||
source: stream.signal ? scope.signalRef(stream.signal)
|
||||
: stream.scale ? scope.scaleRef(stream.scale)
|
||||
: parseStream(stream, scope)
|
||||
};
|
||||
}
|
||||
|
||||
function mergeSources(sources) {
|
||||
return {
|
||||
signal: '['
|
||||
+ sources.map(s => s.scale ? 'scale("' + s.scale + '")' : s.signal)
|
||||
+ ']'
|
||||
};
|
||||
}
|
||||
132
node_modules/vega-parser/src/parsers/view.js
generated
vendored
Normal file
132
node_modules/vega-parser/src/parsers/view.js
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
import parseAutosize from './autosize';
|
||||
import parsePadding from './padding';
|
||||
import parseEncode from './encode';
|
||||
import parseSignal from './signal';
|
||||
import parseSpec from './scope';
|
||||
import {extendEncode} from './encode/util';
|
||||
import {GroupMark} from './marks/marktypes';
|
||||
import {FrameRole} from './marks/roles';
|
||||
import {operator, ref, value} from '../util';
|
||||
import DataScope from '../DataScope';
|
||||
import {Bound, Collect, Encode, Render, Sieve, ViewLayout} from '../transforms';
|
||||
import {array, extend, hasOwnProperty} from 'vega-util';
|
||||
|
||||
const rootEncode = spec => extendEncode(
|
||||
{
|
||||
enter: {
|
||||
x: {value: 0},
|
||||
y: {value: 0}
|
||||
},
|
||||
update: {
|
||||
width: {signal: 'width'},
|
||||
height: {signal: 'height'}
|
||||
}
|
||||
},
|
||||
spec
|
||||
);
|
||||
|
||||
export default function parseView(spec, scope) {
|
||||
const config = scope.config;
|
||||
|
||||
// add scenegraph root
|
||||
const root = ref(scope.root = scope.add(operator()));
|
||||
|
||||
// parse top-level signal definitions
|
||||
const signals = collectSignals(spec, config);
|
||||
signals.forEach(_ => parseSignal(_, scope));
|
||||
|
||||
// assign description, event, legend, and locale configuration
|
||||
scope.description = spec.description || config.description;
|
||||
scope.eventConfig = config.events;
|
||||
scope.legends = scope.objectProperty(config.legend && config.legend.layout);
|
||||
scope.locale = config.locale;
|
||||
|
||||
// store root group item
|
||||
const input = scope.add(Collect());
|
||||
|
||||
// encode root group item
|
||||
const encode = scope.add(Encode(parseEncode(
|
||||
rootEncode(spec.encode), GroupMark, FrameRole,
|
||||
spec.style, scope, {pulse: ref(input)}
|
||||
)));
|
||||
|
||||
// perform view layout
|
||||
const parent = scope.add(ViewLayout({
|
||||
layout: scope.objectProperty(spec.layout),
|
||||
legends: scope.legends,
|
||||
autosize: scope.signalRef('autosize'),
|
||||
mark: root,
|
||||
pulse: ref(encode)
|
||||
}));
|
||||
scope.operators.pop();
|
||||
|
||||
// parse remainder of specification
|
||||
scope.pushState(ref(encode), ref(parent), null);
|
||||
parseSpec(spec, scope, signals);
|
||||
scope.operators.push(parent);
|
||||
|
||||
// bound / render / sieve root item
|
||||
let op = scope.add(Bound({mark: root, pulse: ref(parent)}));
|
||||
op = scope.add(Render({pulse: ref(op)}));
|
||||
op = scope.add(Sieve({pulse: ref(op)}));
|
||||
|
||||
// track metadata for root item
|
||||
scope.addData('root', new DataScope(scope, input, input, op));
|
||||
|
||||
return scope;
|
||||
}
|
||||
|
||||
function signalObject(name, value) {
|
||||
return value && value.signal
|
||||
? { name, update: value.signal }
|
||||
: { name, value };
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect top-level signals, merging values as needed. Signals
|
||||
* defined in the config signals arrays are added only if that
|
||||
* signal is not explicitly defined in the specification.
|
||||
* Built-in signals (autosize, background, padding, width, height)
|
||||
* receive special treatment. They are initialized using the
|
||||
* top-level spec property, or, if undefined in the spec, using
|
||||
* the corresponding top-level config property. If this property
|
||||
* is a signal reference object, the signal expression maps to the
|
||||
* signal 'update' property. If the spec's top-level signal array
|
||||
* contains an entry that matches a built-in signal, that entry
|
||||
* will be merged with the built-in specification, potentially
|
||||
* overwriting existing 'value' or 'update' properties.
|
||||
*/
|
||||
function collectSignals(spec, config) {
|
||||
const _ = name => value(spec[name], config[name]),
|
||||
signals = [
|
||||
signalObject('background', _('background')),
|
||||
signalObject('autosize', parseAutosize(_('autosize'))),
|
||||
signalObject('padding', parsePadding(_('padding'))),
|
||||
signalObject('width', _('width') || 0),
|
||||
signalObject('height', _('height') || 0)
|
||||
],
|
||||
pre = signals.reduce((p, s) => (p[s.name] = s, p), {}),
|
||||
map = {};
|
||||
|
||||
// add spec signal array
|
||||
array(spec.signals).forEach(s => {
|
||||
if (hasOwnProperty(pre, s.name)) {
|
||||
// merge if built-in signal
|
||||
s = extend(pre[s.name], s);
|
||||
} else {
|
||||
// otherwise add to signal list
|
||||
signals.push(s);
|
||||
}
|
||||
map[s.name] = s;
|
||||
});
|
||||
|
||||
// add config signal array
|
||||
array(config.signals).forEach(s => {
|
||||
if (!hasOwnProperty(map, s.name) && !hasOwnProperty(pre, s.name)) {
|
||||
// add to signal list if not already defined
|
||||
signals.push(s);
|
||||
}
|
||||
});
|
||||
|
||||
return signals;
|
||||
}
|
||||
34
node_modules/vega-parser/src/transforms.js
generated
vendored
Normal file
34
node_modules/vega-parser/src/transforms.js
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
import {entry} from './util';
|
||||
|
||||
const transform = name => (params, value, parent) =>
|
||||
entry(name, value, params || undefined, parent);
|
||||
|
||||
export var Aggregate = transform('aggregate');
|
||||
export var AxisTicks = transform('axisticks');
|
||||
export var Bound = transform('bound');
|
||||
export var Collect = transform('collect');
|
||||
export var Compare = transform('compare');
|
||||
export var DataJoin = transform('datajoin');
|
||||
export var Encode = transform('encode');
|
||||
export var Expression = transform('expression');
|
||||
export var Extent = transform('extent');
|
||||
export var Facet = transform('facet');
|
||||
export var Field = transform('field');
|
||||
export var Key = transform('key');
|
||||
export var LegendEntries = transform('legendentries');
|
||||
export var Load = transform('load');
|
||||
export var Mark = transform('mark');
|
||||
export var MultiExtent = transform('multiextent');
|
||||
export var MultiValues = transform('multivalues');
|
||||
export var Overlap = transform('overlap');
|
||||
export var Params = transform('params');
|
||||
export var PreFacet = transform('prefacet');
|
||||
export var Projection = transform('projection');
|
||||
export var Proxy = transform('proxy');
|
||||
export var Relay = transform('relay');
|
||||
export var Render = transform('render');
|
||||
export var Scale = transform('scale');
|
||||
export var Sieve = transform('sieve');
|
||||
export var SortItems = transform('sortitems');
|
||||
export var ViewLayout = transform('viewlayout');
|
||||
export var Values = transform('values');
|
||||
95
node_modules/vega-parser/src/util.js
generated
vendored
Normal file
95
node_modules/vega-parser/src/util.js
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
import {isObject} from 'vega-util';
|
||||
|
||||
export function Entry(type, value, params, parent) {
|
||||
this.id = -1;
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
this.params = params;
|
||||
if (parent) this.parent = parent;
|
||||
}
|
||||
|
||||
export function entry(type, value, params, parent) {
|
||||
return new Entry(type, value, params, parent);
|
||||
}
|
||||
|
||||
export function operator(value, params) {
|
||||
return entry('operator', value, params);
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
export function ref(op) {
|
||||
var ref = {$ref: op.id};
|
||||
// if operator not yet registered, cache ref to resolve later
|
||||
if (op.id < 0) (op.refs = op.refs || []).push(ref);
|
||||
return ref;
|
||||
}
|
||||
|
||||
export var tupleidRef = {
|
||||
$tupleid: 1,
|
||||
toString: function() { return ':_tupleid_:'; }
|
||||
};
|
||||
|
||||
export function fieldRef(field, name) {
|
||||
return name ? {$field: field, $name: name} : {$field: field};
|
||||
}
|
||||
|
||||
export var keyFieldRef = fieldRef('key');
|
||||
|
||||
export function compareRef(fields, orders) {
|
||||
return {$compare: fields, $order: orders};
|
||||
}
|
||||
|
||||
export function keyRef(fields, flat) {
|
||||
var ref = {$key: fields};
|
||||
if (flat) ref.$flat = true;
|
||||
return ref;
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
export var Ascending = 'ascending';
|
||||
|
||||
export var Descending = 'descending';
|
||||
|
||||
export function sortKey(sort) {
|
||||
return !isObject(sort) ? ''
|
||||
: (sort.order === Descending ? '-' : '+')
|
||||
+ aggrField(sort.op, sort.field);
|
||||
}
|
||||
|
||||
export function aggrField(op, field) {
|
||||
return (op && op.signal ? '$' + op.signal : op || '')
|
||||
+ (op && field ? '_' : '')
|
||||
+ (field && field.signal ? '$' + field.signal : field || '');
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
export var Scope = 'scope';
|
||||
|
||||
export var View = 'view';
|
||||
|
||||
export function isSignal(_) {
|
||||
return _ && _.signal;
|
||||
}
|
||||
|
||||
export function isExpr(_) {
|
||||
return _ && _.expr;
|
||||
}
|
||||
|
||||
export function hasSignal(_) {
|
||||
if (isSignal(_)) return true;
|
||||
if (isObject(_)) for (var key in _) {
|
||||
if (hasSignal(_[key])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function value(specValue, defaultValue) {
|
||||
return specValue != null ? specValue : defaultValue;
|
||||
}
|
||||
|
||||
export function deref(v) {
|
||||
return v && v.signal || v;
|
||||
}
|
||||
Reference in New Issue
Block a user