Bar graph added.

This commit is contained in:
prabhatdev
2020-07-28 00:48:25 +05:30
parent d0a6e2667d
commit 194b41124d
3468 changed files with 640611 additions and 169 deletions

139
node_modules/vega-parser/src/DataScope.js generated vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}

View 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
View 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
View 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
View 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])
);
}

View 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;
}

View 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};
}

View 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;
}

View 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);
}

View 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);
}

View 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));
}

View 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;
};

View 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};

View File

@@ -0,0 +1,7 @@
import {GroupMark} from '../marks/marktypes';
export default function(mark) {
mark.type = GroupMark;
mark.interactive = mark.interactive || false;
return mark;
}

View 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;
}

View 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) });
}

View 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);
}

View 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);
}

View 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);
}

View 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')
}
};
}

View 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
View 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
View 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
View 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
View 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);
}

View 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
View 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()
};
}

View File

@@ -0,0 +1,5 @@
export default function(spec, scope) {
return spec && spec.signal ? scope.signalRef(spec.signal)
: spec === false ? false
: true;
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}