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