Website/slides/talks/vega/vega-lite.js
2017-09-13 01:05:37 -04:00

13012 lines
499 KiB
JavaScript

(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.vl = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var json = typeof JSON !== 'undefined' ? JSON : require('jsonify');
module.exports = function (obj, opts) {
if (!opts) opts = {};
if (typeof opts === 'function') opts = { cmp: opts };
var space = opts.space || '';
if (typeof space === 'number') space = Array(space+1).join(' ');
var cycles = (typeof opts.cycles === 'boolean') ? opts.cycles : false;
var replacer = opts.replacer || function(key, value) { return value; };
var cmp = opts.cmp && (function (f) {
return function (node) {
return function (a, b) {
var aobj = { key: a, value: node[a] };
var bobj = { key: b, value: node[b] };
return f(aobj, bobj);
};
};
})(opts.cmp);
var seen = [];
return (function stringify (parent, key, node, level) {
var indent = space ? ('\n' + new Array(level + 1).join(space)) : '';
var colonSeparator = space ? ': ' : ':';
if (node && node.toJSON && typeof node.toJSON === 'function') {
node = node.toJSON();
}
node = replacer.call(parent, key, node);
if (node === undefined) {
return;
}
if (typeof node !== 'object' || node === null) {
return json.stringify(node);
}
if (isArray(node)) {
var out = [];
for (var i = 0; i < node.length; i++) {
var item = stringify(node, i, node[i], level+1) || json.stringify(null);
out.push(indent + space + item);
}
return '[' + out.join(',') + indent + ']';
}
else {
if (seen.indexOf(node) !== -1) {
if (cycles) return json.stringify('__cycle__');
throw new TypeError('Converting circular structure to JSON');
}
else seen.push(node);
var keys = objectKeys(node).sort(cmp && cmp(node));
var out = [];
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var value = stringify(node, key, node[key], level+1);
if(!value) continue;
var keyValue = json.stringify(key)
+ colonSeparator
+ value;
;
out.push(indent + space + keyValue);
}
seen.splice(seen.indexOf(node), 1);
return '{' + out.join(',') + indent + '}';
}
})({ '': obj }, '', obj, 0);
};
var isArray = Array.isArray || function (x) {
return {}.toString.call(x) === '[object Array]';
};
var objectKeys = Object.keys || function (obj) {
var has = Object.prototype.hasOwnProperty || function () { return true };
var keys = [];
for (var key in obj) {
if (has.call(obj, key)) keys.push(key);
}
return keys;
};
},{"jsonify":2}],2:[function(require,module,exports){
exports.parse = require('./lib/parse');
exports.stringify = require('./lib/stringify');
},{"./lib/parse":3,"./lib/stringify":4}],3:[function(require,module,exports){
var at, // The index of the current character
ch, // The current character
escapee = {
'"': '"',
'\\': '\\',
'/': '/',
b: '\b',
f: '\f',
n: '\n',
r: '\r',
t: '\t'
},
text,
error = function (m) {
// Call error when something is wrong.
throw {
name: 'SyntaxError',
message: m,
at: at,
text: text
};
},
next = function (c) {
// If a c parameter is provided, verify that it matches the current character.
if (c && c !== ch) {
error("Expected '" + c + "' instead of '" + ch + "'");
}
// Get the next character. When there are no more characters,
// return the empty string.
ch = text.charAt(at);
at += 1;
return ch;
},
number = function () {
// Parse a number value.
var number,
string = '';
if (ch === '-') {
string = '-';
next('-');
}
while (ch >= '0' && ch <= '9') {
string += ch;
next();
}
if (ch === '.') {
string += '.';
while (next() && ch >= '0' && ch <= '9') {
string += ch;
}
}
if (ch === 'e' || ch === 'E') {
string += ch;
next();
if (ch === '-' || ch === '+') {
string += ch;
next();
}
while (ch >= '0' && ch <= '9') {
string += ch;
next();
}
}
number = +string;
if (!isFinite(number)) {
error("Bad number");
} else {
return number;
}
},
string = function () {
// Parse a string value.
var hex,
i,
string = '',
uffff;
// When parsing for string values, we must look for " and \ characters.
if (ch === '"') {
while (next()) {
if (ch === '"') {
next();
return string;
} else if (ch === '\\') {
next();
if (ch === 'u') {
uffff = 0;
for (i = 0; i < 4; i += 1) {
hex = parseInt(next(), 16);
if (!isFinite(hex)) {
break;
}
uffff = uffff * 16 + hex;
}
string += String.fromCharCode(uffff);
} else if (typeof escapee[ch] === 'string') {
string += escapee[ch];
} else {
break;
}
} else {
string += ch;
}
}
}
error("Bad string");
},
white = function () {
// Skip whitespace.
while (ch && ch <= ' ') {
next();
}
},
word = function () {
// true, false, or null.
switch (ch) {
case 't':
next('t');
next('r');
next('u');
next('e');
return true;
case 'f':
next('f');
next('a');
next('l');
next('s');
next('e');
return false;
case 'n':
next('n');
next('u');
next('l');
next('l');
return null;
}
error("Unexpected '" + ch + "'");
},
value, // Place holder for the value function.
array = function () {
// Parse an array value.
var array = [];
if (ch === '[') {
next('[');
white();
if (ch === ']') {
next(']');
return array; // empty array
}
while (ch) {
array.push(value());
white();
if (ch === ']') {
next(']');
return array;
}
next(',');
white();
}
}
error("Bad array");
},
object = function () {
// Parse an object value.
var key,
object = {};
if (ch === '{') {
next('{');
white();
if (ch === '}') {
next('}');
return object; // empty object
}
while (ch) {
key = string();
white();
next(':');
if (Object.hasOwnProperty.call(object, key)) {
error('Duplicate key "' + key + '"');
}
object[key] = value();
white();
if (ch === '}') {
next('}');
return object;
}
next(',');
white();
}
}
error("Bad object");
};
value = function () {
// Parse a JSON value. It could be an object, an array, a string, a number,
// or a word.
white();
switch (ch) {
case '{':
return object();
case '[':
return array();
case '"':
return string();
case '-':
return number();
default:
return ch >= '0' && ch <= '9' ? number() : word();
}
};
// Return the json_parse function. It will have access to all of the above
// functions and variables.
module.exports = function (source, reviver) {
var result;
text = source;
at = 0;
ch = ' ';
result = value();
white();
if (ch) {
error("Syntax error");
}
// If there is a reviver function, we recursively walk the new structure,
// passing each name/value pair to the reviver function for possible
// transformation, starting with a temporary root object that holds the result
// in an empty key. If there is not a reviver function, we simply return the
// result.
return typeof reviver === 'function' ? (function walk(holder, key) {
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}({'': result}, '')) : result;
};
},{}],4:[function(require,module,exports){
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
gap,
indent,
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
escapable.lastIndex = 0;
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string' ? c :
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' : '"' + string + '"';
}
function str(key, holder) {
// Produce a string from holder[key].
var i, // The loop counter.
k, // The member key.
v, // The member value.
length,
mind = gap,
partial,
value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
case 'object':
if (!value) return 'null';
gap += indent;
partial = [];
// Array.isArray
if (Object.prototype.toString.apply(value) === '[object Array]') {
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
// Join all of the elements together, separated with commas, and
// wrap them in brackets.
v = partial.length === 0 ? '[]' : gap ?
'[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
'[' + partial.join(',') + ']';
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be
// stringified.
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
k = rep[i];
if (typeof k === 'string') {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0 ? '{}' : gap ?
'{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
'{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
module.exports = function (value, replacer, space) {
var i;
gap = '';
indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
}
// If the space parameter is a string, it will be used as the indent string.
else if (typeof space === 'string') {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== 'function'
&& (typeof replacer !== 'object' || typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str('', {'': value});
};
},{}],5:[function(require,module,exports){
(function (global){
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/* global global, define, System, Reflect, Promise */
var __extends;
var __assign;
var __rest;
var __decorate;
var __param;
var __metadata;
var __awaiter;
var __generator;
var __exportStar;
var __values;
var __read;
var __spread;
var __await;
var __asyncGenerator;
var __asyncDelegator;
var __asyncValues;
(function (factory) {
var root = typeof global === "object" ? global : typeof self === "object" ? self : typeof this === "object" ? this : {};
if (typeof define === "function" && define.amd) {
define("tslib", ["exports"], function (exports) { factory(createExporter(root, createExporter(exports))); });
}
else if (typeof module === "object" && typeof module.exports === "object") {
factory(createExporter(root, createExporter(module.exports)));
}
else {
factory(createExporter(root));
}
function createExporter(exports, previous) {
return function (id, v) { return exports[id] = previous ? previous(id, v) : v; };
}
})
(function (exporter) {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
__extends = function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
__assign = Object.assign || function (t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
__rest = function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
t[p[i]] = s[p[i]];
return t;
};
__decorate = function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
__param = function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
__metadata = function (metadataKey, metadataValue) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
};
__awaiter = function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
__generator = function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [0, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
__exportStar = function (m, exports) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
};
__values = function (o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
if (m) return m.call(o);
return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
};
__read = function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
__spread = function () {
for (var ar = [], i = 0; i < arguments.length; i++)
ar = ar.concat(__read(arguments[i]));
return ar;
};
__await = function (v) {
return this instanceof __await ? (this.v = v, this) : new __await(v);
};
__asyncGenerator = function (thisArg, _arguments, generator) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var g = generator.apply(thisArg, _arguments || []), i, q = [];
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
function fulfill(value) { resume("next", value); }
function reject(value) { resume("throw", value); }
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
};
__asyncDelegator = function (o) {
var i, p;
return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; }
};
__asyncValues = function (o) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var m = o[Symbol.asyncIterator];
return m ? m.call(o) : typeof __values === "function" ? __values(o) : o[Symbol.iterator]();
};
exporter("__extends", __extends);
exporter("__assign", __assign);
exporter("__rest", __rest);
exporter("__decorate", __decorate);
exporter("__param", __param);
exporter("__metadata", __metadata);
exporter("__awaiter", __awaiter);
exporter("__generator", __generator);
exporter("__exportStar", __exportStar);
exporter("__values", __values);
exporter("__read", __read);
exporter("__spread", __spread);
exporter("__await", __await);
exporter("__asyncGenerator", __asyncGenerator);
exporter("__asyncDelegator", __asyncDelegator);
exporter("__asyncValues", __asyncValues);
});
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],6:[function(require,module,exports){
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.vega = global.vega || {})));
}(this, (function (exports) { 'use strict';
/**
* Parse an event selector string.
* Returns an array of event stream definitions.
*/
var eventSelector = function(selector, source, marks) {
DEFAULT_SOURCE = source || VIEW;
MARKS = marks || DEFAULT_MARKS;
return parseMerge(selector.trim()).map(parseSelector);
};
var VIEW = 'view';
var LBRACK = '[';
var RBRACK = ']';
var LBRACE = '{';
var RBRACE = '}';
var COLON = ':';
var COMMA = ',';
var NAME = '@';
var GT = '>';
var ILLEGAL = /[[\]{}]/;
var DEFAULT_SOURCE;
var MARKS;
var DEFAULT_MARKS = {
'*': 1,
arc: 1,
area: 1,
group: 1,
image: 1,
line: 1,
path: 1,
rect: 1,
rule: 1,
shape: 1,
symbol: 1,
text: 1,
trail: 1
};
function isMarkType(type) {
return MARKS.hasOwnProperty(type);
}
function find(s, i, endChar, pushChar, popChar) {
var count = 0,
n = s.length,
c;
for (; i<n; ++i) {
c = s[i];
if (!count && c === endChar) return i;
else if (popChar && popChar.indexOf(c) >= 0) --count;
else if (pushChar && pushChar.indexOf(c) >= 0) ++count;
}
return i;
}
function parseMerge(s) {
var output = [],
start = 0,
n = s.length,
i = 0;
while (i < n) {
i = find(s, i, COMMA, LBRACK + LBRACE, RBRACK + RBRACE);
output.push(s.substring(start, i).trim());
start = ++i;
}
if (output.length === 0) {
throw 'Empty event selector: ' + s;
}
return output;
}
function parseSelector(s) {
return s[0] === '['
? parseBetween(s)
: parseStream(s);
}
function parseBetween(s) {
var n = s.length,
i = 1,
b, stream;
i = find(s, i, RBRACK, LBRACK, RBRACK);
if (i === n) {
throw 'Empty between selector: ' + s;
}
b = parseMerge(s.substring(1, i));
if (b.length !== 2) {
throw 'Between selector must have two elements: ' + s;
}
s = s.slice(i + 1).trim();
if (s[0] !== GT) {
throw 'Expected \'>\' after between selector: ' + s;
}
b = b.map(parseSelector);
stream = parseSelector(s.slice(1).trim());
if (stream.between) {
return {
between: b,
stream: stream
};
} else {
stream.between = b;
}
return stream;
}
function parseStream(s) {
var stream = {source: DEFAULT_SOURCE},
source = [],
throttle = [0, 0],
markname = 0,
start = 0,
n = s.length,
i = 0, j,
filter;
// extract throttle from end
if (s[n-1] === RBRACE) {
i = s.lastIndexOf(LBRACE);
if (i >= 0) {
try {
throttle = parseThrottle(s.substring(i+1, n-1));
} catch (e) {
throw 'Invalid throttle specification: ' + s;
}
s = s.slice(0, i).trim();
n = s.length;
} else throw 'Unmatched right brace: ' + s;
i = 0;
}
if (!n) throw s;
// set name flag based on first char
if (s[0] === NAME) markname = ++i;
// extract first part of multi-part stream selector
j = find(s, i, COLON);
if (j < n) {
source.push(s.substring(start, j).trim());
start = i = ++j;
}
// extract remaining part of stream selector
i = find(s, i, LBRACK);
if (i === n) {
source.push(s.substring(start, n).trim());
} else {
source.push(s.substring(start, i).trim());
filter = [];
start = ++i;
if (start === n) throw 'Unmatched left bracket: ' + s;
}
// extract filters
while (i < n) {
i = find(s, i, RBRACK);
if (i === n) throw 'Unmatched left bracket: ' + s;
filter.push(s.substring(start, i).trim());
if (i < n-1 && s[++i] !== LBRACK) throw 'Expected left bracket: ' + s;
start = ++i;
}
// marshall event stream specification
if (!(n = source.length) || ILLEGAL.test(source[n-1])) {
throw 'Invalid event selector: ' + s;
}
if (n > 1) {
stream.type = source[1];
if (markname) {
stream.markname = source[0].slice(1);
} else if (isMarkType(source[0])) {
stream.marktype = source[0];
} else {
stream.source = source[0];
}
} else {
stream.type = source[0];
}
if (stream.type.slice(-1) === '!') {
stream.consume = true;
stream.type = stream.type.slice(0, -1);
}
if (filter != null) stream.filter = filter;
if (throttle[0]) stream.throttle = throttle[0];
if (throttle[1]) stream.debounce = throttle[1];
return stream;
}
function parseThrottle(s) {
var a = s.split(COMMA);
if (!s.length || a.length > 2) throw s;
return a.map(function(_) {
var x = +_;
if (x !== x) throw s;
return x;
});
}
exports.selector = eventSelector;
Object.defineProperty(exports, '__esModule', { value: true });
})));
},{}],7:[function(require,module,exports){
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.vega = global.vega || {})));
}(this, (function (exports) { 'use strict';
var accessor = function(fn, fields, name) {
fn.fields = fields || [];
fn.fname = name;
return fn;
};
function accessorName(fn) {
return fn == null ? null : fn.fname;
}
function accessorFields(fn) {
return fn == null ? null : fn.fields;
}
var error = function(message) {
throw Error(message);
};
var splitAccessPath = function(p) {
var path = [],
q = null,
b = 0,
n = p.length,
s = '',
i, j, c;
p = p + '';
function push() {
path.push(s + p.substring(i, j));
s = '';
i = j + 1;
}
for (i=j=0; j<n; ++j) {
c = p[j];
if (c === '\\') {
s += p.substring(i, j);
i = ++j;
} else if (c === q) {
push();
q = null;
b = -1;
} else if (q) {
continue;
} else if (i === b && c === '"') {
i = j + 1;
q = c;
} else if (i === b && c === "'") {
i = j + 1;
q = c;
} else if (c === '.' && !b) {
if (j > i) {
push();
} else {
i = j + 1;
}
} else if (c === '[') {
if (j > i) push();
b = i = j + 1;
} else if (c === ']') {
if (!b) error('Access path missing open bracket: ' + p);
if (b > 0) push();
b = 0;
i = j + 1;
}
}
if (b) error('Access path missing closing bracket: ' + p);
if (q) error('Access path missing closing quote: ' + p);
if (j > i) {
j++;
push();
}
return path;
};
var isArray = Array.isArray;
var isObject = function(_) {
return _ === Object(_);
};
var isString = function(_) {
return typeof _ === 'string';
};
function $(x) {
return isArray(x) ? '[' + x.map($) + ']'
: isObject(x) || isString(x) ?
// Output valid JSON and JS source strings.
// See http://timelessrepo.com/json-isnt-a-javascript-subset
JSON.stringify(x).replace('\u2028','\\u2028').replace('\u2029', '\\u2029')
: x;
}
var field = function(field, name) {
var path = splitAccessPath(field),
code = 'return _[' + path.map($).join('][') + '];';
return accessor(
Function('_', code),
[(field = path.length===1 ? path[0] : field)],
name || field
);
};
var empty = [];
var id = field('id');
var identity = accessor(function(_) { return _; }, empty, 'identity');
var zero = accessor(function() { return 0; }, empty, 'zero');
var one = accessor(function() { return 1; }, empty, 'one');
var truthy = accessor(function() { return true; }, empty, 'true');
var falsy = accessor(function() { return false; }, empty, 'false');
function log(method, level, input) {
var args = [level].concat([].slice.call(input));
console[method].apply(console, args); // eslint-disable-line no-console
}
var None = 0;
var Error$1 = 1;
var Warn = 2;
var Info = 3;
var Debug = 4;
var logger = function(_) {
var level = _ || None;
return {
level: function(_) {
if (arguments.length) {
level = +_;
return this;
} else {
return level;
}
},
error: function() {
if (level >= Error$1) log('error', 'ERROR', arguments);
return this;
},
warn: function() {
if (level >= Warn) log('warn', 'WARN', arguments);
return this;
},
info: function() {
if (level >= Info) log('log', 'INFO', arguments);
return this;
},
debug: function() {
if (level >= Debug) log('log', 'DEBUG', arguments);
return this;
}
}
};
var array = function(_) {
return _ != null ? (isArray(_) ? _ : [_]) : [];
};
var isFunction = function(_) {
return typeof _ === 'function';
};
var compare = function(fields, orders) {
var idx = [],
cmp = (fields = array(fields)).map(function(f, i) {
if (f == null) {
return null;
} else {
idx.push(i);
return isFunction(f) ? f
: splitAccessPath(f).map($).join('][');
}
}),
n = idx.length - 1,
ord = array(orders),
code = 'var u,v;return ',
i, j, f, u, v, d, t, lt, gt;
if (n < 0) return null;
for (j=0; j<=n; ++j) {
i = idx[j];
f = cmp[i];
if (isFunction(f)) {
d = 'f' + i;
u = '(u=this.' + d + '(a))';
v = '(v=this.' + d + '(b))';
(t = t || {})[d] = f;
} else {
u = '(u=a['+f+'])';
v = '(v=b['+f+'])';
}
d = '((v=v instanceof Date?+v:v),(u=u instanceof Date?+u:u))';
if (ord[i] !== 'descending') {
gt = 1;
lt = -1;
} else {
gt = -1;
lt = 1;
}
code += '(' + u+'<'+v+'||u==null)&&v!=null?' + lt
+ ':(u>v||v==null)&&u!=null?' + gt
+ ':'+d+'!==u&&v===v?' + lt
+ ':v!==v&&u===u?' + gt
+ (i < n ? ':' : ':0');
}
f = Function('a', 'b', code + ';');
if (t) f = f.bind(t);
fields = fields.reduce(function(map, field) {
if (isFunction(field)) {
(accessorFields(field) || []).forEach(function(_) { map[_] = 1; });
} else if (field != null) {
map[field + ''] = 1;
}
return map;
}, {});
return accessor(f, Object.keys(fields));
};
var constant = function(_) {
return isFunction(_) ? _ : function() { return _; };
};
var debounce = function(delay, handler) {
var tid, evt;
function callback() {
handler(evt);
tid = evt = null;
}
return function(e) {
evt = e;
if (tid) clearTimeout(tid);
tid = setTimeout(callback, delay);
};
};
var extend = function(_) {
for (var x, k, i=1, len=arguments.length; i<len; ++i) {
x = arguments[i];
for (k in x) { _[k] = x[k]; }
}
return _;
};
var extentIndex = function(array, f) {
var i = -1,
n = array.length,
a, b, c, u, v;
if (f == null) {
while (++i < n) {
b = array[i];
if (b != null && b >= b) {
a = c = b;
break;
}
}
u = v = i;
while (++i < n) {
b = array[i];
if (b != null) {
if (a > b) {
a = b;
u = i;
}
if (c < b) {
c = b;
v = i;
}
}
}
} else {
while (++i < n) {
b = f(array[i], i, array);
if (b != null && b >= b) {
a = c = b;
break;
}
}
u = v = i;
while (++i < n) {
b = f(array[i], i, array);
if (b != null) {
if (a > b) {
a = b;
u = i;
}
if (c < b) {
c = b;
v = i;
}
}
}
}
return [u, v];
};
var NULL = {};
var fastmap = function(input) {
var obj = {},
map,
test;
function has(key) {
return obj.hasOwnProperty(key) && obj[key] !== NULL;
}
map = {
size: 0,
empty: 0,
object: obj,
has: has,
get: function(key) {
return has(key) ? obj[key] : undefined;
},
set: function(key, value) {
if (!has(key)) {
++map.size;
if (obj[key] === NULL) --map.empty;
}
obj[key] = value;
return this;
},
delete: function(key) {
if (has(key)) {
--map.size;
++map.empty;
obj[key] = NULL;
}
return this;
},
clear: function() {
map.size = map.empty = 0;
map.object = obj = {};
},
test: function(_) {
if (arguments.length) {
test = _;
return map;
} else {
return test;
}
},
clean: function() {
var next = {},
size = 0,
key, value;
for (key in obj) {
value = obj[key];
if (value !== NULL && (!test || !test(value))) {
next[key] = value;
++size;
}
}
map.size = size;
map.empty = 0;
map.object = (obj = next);
}
};
if (input) Object.keys(input).forEach(function(key) {
map.set(key, input[key]);
});
return map;
};
var inherits = function(child, parent) {
var proto = (child.prototype = Object.create(parent.prototype));
proto.constructor = child;
return proto;
};
var isBoolean = function(_) {
return typeof _ === 'boolean';
};
var isDate = function(_) {
return Object.prototype.toString.call(_) === '[object Date]';
};
var isNumber = function(_) {
return typeof _ === 'number';
};
var isRegExp = function(_) {
return Object.prototype.toString.call(_) === '[object RegExp]';
};
var key = function(fields) {
fields = fields ? array(fields) : fields;
var fn = !(fields && fields.length)
? function() { return ''; }
: Function('_', 'return \'\'+' +
fields.map(function(f) {
return '_[' + splitAccessPath(f).map($).join('][') + ']';
}).join('+\'|\'+') + ';');
return accessor(fn, fields, 'key');
};
var merge = function(compare, array0, array1, output) {
var n0 = array0.length,
n1 = array1.length;
if (!n1) return array0;
if (!n0) return array1;
var merged = output || new array0.constructor(n0 + n1),
i0 = 0, i1 = 0, i = 0;
for (; i0<n0 && i1<n1; ++i) {
merged[i] = compare(array0[i0], array1[i1]) > 0
? array1[i1++]
: array0[i0++];
}
for (; i0<n0; ++i0, ++i) {
merged[i] = array0[i0];
}
for (; i1<n1; ++i1, ++i) {
merged[i] = array1[i1];
}
return merged;
};
var repeat = function(str, reps) {
var s = '';
while (--reps >= 0) s += str;
return s;
};
var pad = function(str, length, padchar, align) {
var c = padchar || ' ',
s = str + '',
n = length - s.length;
return n <= 0 ? s
: align === 'left' ? repeat(c, n) + s
: align === 'center' ? repeat(c, ~~(n/2)) + s + repeat(c, Math.ceil(n/2))
: s + repeat(c, n);
};
var peek = function(array) {
return array[array.length - 1];
};
var toBoolean = function(_) {
return _ == null || _ === '' ? null : !_ || _ === 'false' || _ === '0' ? false : !!_;
};
function defaultParser(_) {
return isNumber(_) ? _ : isDate(_) ? _ : Date.parse(_);
}
var toDate = function(_, parser) {
parser = parser || defaultParser;
return _ == null || _ === '' ? null : parser(_);
};
var toNumber = function(_) {
return _ == null || _ === '' ? null : +_;
};
var toString = function(_) {
return _ == null || _ === '' ? null : _ + '';
};
var toSet = function(_) {
for (var s={}, i=0, n=_.length; i<n; ++i) s[_[i]] = 1;
return s;
};
var truncate = function(str, length, align, ellipsis) {
var e = ellipsis != null ? ellipsis : '\u2026',
s = str + '',
n = s.length,
l = Math.max(0, length - e.length);
return n <= length ? s
: align === 'left' ? e + s.slice(n - l)
: align === 'center' ? s.slice(0, Math.ceil(l/2)) + e + s.slice(n - ~~(l/2))
: s.slice(0, l) + e;
};
var visitArray = function(array, filter, visitor) {
if (array) {
var i = 0, n = array.length, t;
if (filter) {
for (; i<n; ++i) {
if (t = filter(array[i])) visitor(t, i, array);
}
} else {
array.forEach(visitor);
}
}
};
exports.accessor = accessor;
exports.accessorName = accessorName;
exports.accessorFields = accessorFields;
exports.id = id;
exports.identity = identity;
exports.zero = zero;
exports.one = one;
exports.truthy = truthy;
exports.falsy = falsy;
exports.logger = logger;
exports.None = None;
exports.Error = Error$1;
exports.Warn = Warn;
exports.Info = Info;
exports.Debug = Debug;
exports.array = array;
exports.compare = compare;
exports.constant = constant;
exports.debounce = debounce;
exports.error = error;
exports.extend = extend;
exports.extentIndex = extentIndex;
exports.fastmap = fastmap;
exports.field = field;
exports.inherits = inherits;
exports.isArray = isArray;
exports.isBoolean = isBoolean;
exports.isDate = isDate;
exports.isFunction = isFunction;
exports.isNumber = isNumber;
exports.isObject = isObject;
exports.isRegExp = isRegExp;
exports.isString = isString;
exports.key = key;
exports.merge = merge;
exports.pad = pad;
exports.peek = peek;
exports.repeat = repeat;
exports.splitAccessPath = splitAccessPath;
exports.stringValue = $;
exports.toBoolean = toBoolean;
exports.toDate = toDate;
exports.toNumber = toNumber;
exports.toString = toString;
exports.toSet = toSet;
exports.truncate = truncate;
exports.visitArray = visitArray;
Object.defineProperty(exports, '__esModule', { value: true });
})));
},{}],8:[function(require,module,exports){
module.exports={
"name": "vega-lite",
"author": "Jeffrey Heer, Dominik Moritz, Kanit \"Ham\" Wongsuphasawat",
"version": "2.0.0-rc2",
"collaborators": [
"Kanit Wongsuphasawat <kanitw@gmail.com> (http://kanitw.yellowpigz.com)",
"Dominik Moritz <domoritz@cs.washington.edu> (https://www.domoritz.de)",
"Jeffrey Heer <jheer@uw.edu> (http://jheer.org)"
],
"homepage": "https://vega.github.io/vega-lite/",
"description": "Vega-lite provides a higher-level grammar for visual analysis, comparable to ggplot or Tableau, that generates complete Vega specifications.",
"main": "build/src/index.js",
"types": "typings/vega-lite.d.ts",
"bin": {
"vl2png": "./bin/vl2png",
"vl2svg": "./bin/vl2svg",
"vl2vg": "./bin/vl2vg"
},
"directories": {
"test": "test"
},
"scripts": {
"pretsc": "mkdir -p build && rm -rf build/*/** && cp package.json build/",
"tsc": "tsc",
"prebuild": "mkdir -p build/site build/test-gallery",
"build": "npm run build:only",
"build:only": "npm run tsc && cp package.json build && browserify src/index.ts -p tsify -d -s vl | exorcist build/vega-lite.js.map > build/vega-lite.js",
"postbuild": "node node_modules/uglify-js/bin/uglifyjs build/vega-lite.js -cm --source-map content=build/vega-lite.js.map,filename=build/vega-lite.min.js.map -o build/vega-lite.min.js && npm run schema",
"build:examples": "npm run data && npm run build:only && npm run build:examples-only",
"build:examples-only": "TZ=America/Los_Angeles ./scripts/build-examples.sh && rm -f examples/specs/normalized/*.vl.json && scripts/build-normalized-examples",
"build:example": "./scripts/build-example.sh",
"build:toc": "bundle exec jekyll build -q && scripts/generate-toc",
"build:site": "browserify site/static/main.ts -p [tsify -p site] -d | exorcist build/site/main.js.map > build/site/main.js",
"build:versions": "scripts/update-version.sh",
"build:test-gallery": "browserify test-gallery/main.ts -p [tsify -p test-gallery] -d > build/test-gallery/main.js",
"check:examples": "scripts/check-examples.sh",
"check:schema": "scripts/check-schema.sh",
"clean": "rm -rf build && rm -f vega-lite.* & find -E src test site examples -regex '.*\\.(js|js.map|d.ts)' -delete",
"data": "rsync -r node_modules/vega-datasets/data/* data",
"link": "npm link && npm link vega-lite",
"deploy": "scripts/deploy.sh",
"deploy:gh": "scripts/deploy-gh.sh",
"deploy:schema": "scripts/deploy-schema.sh",
"prestart": "npm run data && npm run build && scripts/index-examples",
"start": "nodemon -x 'npm run build:test-gallery' & browser-sync start --server --files 'build/test-gallery/main.js' --index 'test-gallery/index.html'",
"poststart": "rm examples/all-examples.json",
"preschema": "npm run prebuild",
"schema": "ts-json-schema-generator --path tsconfig.json --type TopLevelExtendedSpec > build/vega-lite-schema.json && npm run renameschema && cp build/vega-lite-schema.json _data/",
"renameschema": "scripts/rename-schema.sh",
"presite": "npm run build && npm run data && npm run build:site && npm run build:toc && npm run build:versions",
"site": "bundle exec jekyll serve",
"lint": "tslint --project tsconfig.json -c tslint.json --type-check",
"test": "npm run build:only && npm run test:only && npm run test:runtime && npm run lint",
"posttest": "npm run schema && npm run data && npm run mocha:examples",
"test:nocompile": "npm run test:only && npm run test:runtime && npm run lint && npm run mocha:examples",
"test:only": "nyc --reporter=html --reporter=text-summary npm run mocha:test",
"test:runtime": "TZ=America/Los_Angeles wdio wdio.conf.js",
"test:runtime:generate": "rm -Rf test-runtime/resources && VL_GENERATE_TESTS=true npm run test:runtime",
"test:debug": "npm run tsc && mocha --recursive --debug-brk --inspect build/test",
"test:debug-examples": "npm run tsc && npm run schema && mocha --recursive --debug-brk --inspect build/examples",
"mocha:test": "mocha --require source-map-support/register --reporter dot --recursive build/test",
"mocha:examples": "mocha --require source-map-support/register --reporter dot --recursive build/examples",
"codecov": "nyc report --reporter=json && codecov -f coverage/*.json",
"watch:build": "watchify src/index.ts -p tsify -v -d -s vl -o 'exorcist build/vega-lite.js.map > build/vega-lite.js'",
"watch:tsc": "npm run tsc -- -w",
"watch:test": "nodemon -x 'npm test'",
"watch": "nodemon -x 'npm run build && npm run test:nocompile' # already ran schema in build"
},
"repository": {
"type": "git",
"url": "https://github.com/vega/vega-lite.git"
},
"license": "BSD-3-Clause",
"bugs": {
"url": "https://github.com/vega/vega-lite/issues"
},
"devDependencies": {
"@types/chai": "^4.0.2",
"@types/d3": "^4.10.0",
"@types/highlight.js": "^9.1.9",
"@types/json-stable-stringify": "^1.0.31",
"@types/mkdirp": "^0.5.0",
"@types/mocha": "^2.2.41",
"@types/node": "^8.0.19",
"@types/webdriverio": "^4.8.4",
"ajv": "5.2.2",
"browser-sync": "^2.18.13",
"browserify": "^14.4.0",
"browserify-shim": "^3.8.14",
"chai": "^4.1.0",
"cheerio": "^1.0.0-rc.2",
"chromedriver": "^2.30.1",
"codecov": "^2.3.0",
"d3": "^4.10.0",
"exorcist": "^0.4.0",
"highlight.js": "^9.12.0",
"mkdirp": "^0.5.1",
"mocha": "^3.5.0",
"nodemon": "^1.11.0",
"nyc": "^11.1.0",
"source-map-support": "^0.4.15",
"ts-json-schema-generator": "^0.12.0",
"ts-node": "^3.2.1",
"tsify": "^3.0.1",
"tslint": "5.4.3",
"tslint-eslint-rules": "^4.1.1",
"typescript": "^2.4.2",
"uglify-js": "^3.0.27",
"vega": "^3.0.0",
"vega-datasets": "vega/vega-datasets#gh-pages",
"vega-embed": "^3.0.0-beta.20",
"vega-tooltip": "^0.4.2",
"watchify": "^3.9.0",
"wdio-chromedriver-service": "^0.1.0",
"wdio-dot-reporter": "0.0.9",
"wdio-mocha-framework": "^0.5.10",
"wdio-static-server-service": "^1.0.1",
"webdriverio": "^4.8.0",
"yaml-front-matter": "^3.4.0"
},
"dependencies": {
"json-stable-stringify": "^1.0.1",
"tslib": "^1.7.1",
"vega-event-selector": "^2.0.0",
"vega-util": "^1.5.0",
"yargs": "^8.0.2"
}
}
},{}],9:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var util_1 = require("./util");
var AGGREGATE_OP_INDEX = {
values: 1,
count: 1,
valid: 1,
missing: 1,
distinct: 1,
sum: 1,
mean: 1,
average: 1,
variance: 1,
variancep: 1,
stdev: 1,
stdevp: 1,
median: 1,
q1: 1,
q3: 1,
ci0: 1,
ci1: 1,
min: 1,
max: 1,
argmin: 1,
argmax: 1,
};
exports.AGGREGATE_OPS = util_1.flagKeys(AGGREGATE_OP_INDEX);
function isAggregateOp(a) {
return !!AGGREGATE_OP_INDEX[a];
}
exports.isAggregateOp = isAggregateOp;
exports.COUNTING_OPS = ['count', 'valid', 'missing', 'distinct'];
function isCountingAggregateOp(aggregate) {
return aggregate && util_1.contains(exports.COUNTING_OPS, aggregate);
}
exports.isCountingAggregateOp = isCountingAggregateOp;
/** Additive-based aggregation operations. These can be applied to stack. */
exports.SUM_OPS = [
'count',
'sum',
'distinct',
'valid',
'missing'
];
/**
* Aggregation operators that always produce values within the range [domainMin, domainMax].
*/
exports.SHARED_DOMAIN_OPS = [
'mean',
'average',
'median',
'q1',
'q3',
'min',
'max',
];
exports.SHARED_DOMAIN_OP_INDEX = util_1.toSet(exports.SHARED_DOMAIN_OPS);
},{"./util":114}],10:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* A dictionary listing whether a certain axis property is applicable for only main axes or only grid axes.
* (Properties not listed are applicable for both)
*/
exports.AXIS_PROPERTY_TYPE = {
grid: 'grid',
labelOverlap: 'main',
offset: 'main',
title: 'main'
};
exports.AXIS_PROPERTIES = [
'domain', 'format', 'grid', 'labelPadding', 'labels', 'labelOverlap', 'maxExtent', 'minExtent', 'offset', 'orient', 'position', 'tickCount', 'ticks', 'tickSize', 'title', 'titlePadding', 'values', 'zindex'
];
exports.VG_AXIS_PROPERTIES = [].concat(exports.AXIS_PROPERTIES, ['gridScale']);
},{}],11:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var channel_1 = require("./channel");
var util_1 = require("./util");
function binToString(bin) {
if (util_1.isBoolean(bin)) {
return 'bin';
}
return 'bin' + util_1.keys(bin).map(function (p) { return "_" + p + "_" + bin[p]; }).join('');
}
exports.binToString = binToString;
function autoMaxBins(channel) {
switch (channel) {
case channel_1.ROW:
case channel_1.COLUMN:
case channel_1.SIZE:
case channel_1.COLOR:
case channel_1.OPACITY:
// Facets and Size shouldn't have too many bins
// We choose 6 like shape to simplify the rule
case channel_1.SHAPE:
return 6; // Vega's "shape" has 6 distinct values
default:
return 10;
}
}
exports.autoMaxBins = autoMaxBins;
},{"./channel":12,"./util":114}],12:[function(require,module,exports){
"use strict";
/*
* Constants and utilities for encoding channels (Visual variables)
* such as 'x', 'y', 'color'.
*/
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var util_1 = require("./util");
var Channel;
(function (Channel) {
// Facet
Channel.ROW = 'row';
Channel.COLUMN = 'column';
// Position
Channel.X = 'x';
Channel.Y = 'y';
Channel.X2 = 'x2';
Channel.Y2 = 'y2';
// Mark property with scale
Channel.COLOR = 'color';
Channel.SHAPE = 'shape';
Channel.SIZE = 'size';
Channel.OPACITY = 'opacity';
// Non-scale channel
Channel.TEXT = 'text';
Channel.ORDER = 'order';
Channel.DETAIL = 'detail';
Channel.TOOLTIP = 'tooltip';
})(Channel = exports.Channel || (exports.Channel = {}));
exports.X = Channel.X;
exports.Y = Channel.Y;
exports.X2 = Channel.X2;
exports.Y2 = Channel.Y2;
exports.ROW = Channel.ROW;
exports.COLUMN = Channel.COLUMN;
exports.SHAPE = Channel.SHAPE;
exports.SIZE = Channel.SIZE;
exports.COLOR = Channel.COLOR;
exports.TEXT = Channel.TEXT;
exports.DETAIL = Channel.DETAIL;
exports.ORDER = Channel.ORDER;
exports.OPACITY = Channel.OPACITY;
exports.TOOLTIP = Channel.TOOLTIP;
var UNIT_CHANNEL_INDEX = {
x: 1,
y: 1,
x2: 1,
y2: 1,
size: 1,
shape: 1,
color: 1,
order: 1,
opacity: 1,
text: 1,
detail: 1,
tooltip: 1
};
var FACET_CHANNEL_INDEX = {
row: 1,
column: 1
};
var CHANNEL_INDEX = tslib_1.__assign({}, UNIT_CHANNEL_INDEX, FACET_CHANNEL_INDEX);
exports.CHANNELS = util_1.flagKeys(CHANNEL_INDEX);
var _o = CHANNEL_INDEX.order, _d = CHANNEL_INDEX.detail, SINGLE_DEF_CHANNEL_INDEX = tslib_1.__rest(CHANNEL_INDEX, ["order", "detail"]);
/**
* Channels that cannot have an array of channelDef.
* model.fieldDef, getFieldDef only work for these channels.
*
* (The only two channels that can have an array of channelDefs are "detail" and "order".
* Since there can be multiple fieldDefs for detail and order, getFieldDef/model.fieldDef
* are not applicable for them. Similarly, selection projecttion won't work with "detail" and "order".)
*/
exports.SINGLE_DEF_CHANNELS = util_1.flagKeys(SINGLE_DEF_CHANNEL_INDEX);
function isChannel(str) {
return !!CHANNEL_INDEX[str];
}
exports.isChannel = isChannel;
// CHANNELS without COLUMN, ROW
exports.UNIT_CHANNELS = util_1.flagKeys(UNIT_CHANNEL_INDEX);
// NONSPATIAL_CHANNELS = UNIT_CHANNELS without X, Y, X2, Y2;
var _x = UNIT_CHANNEL_INDEX.x, _y = UNIT_CHANNEL_INDEX.y,
// x2 and y2 share the same scale as x and y
_x2 = UNIT_CHANNEL_INDEX.x2, _y2 = UNIT_CHANNEL_INDEX.y2,
// The rest of unit channels then have scale
NONSPATIAL_CHANNEL_INDEX = tslib_1.__rest(UNIT_CHANNEL_INDEX, ["x", "y", "x2", "y2"]);
exports.NONSPATIAL_CHANNELS = util_1.flagKeys(NONSPATIAL_CHANNEL_INDEX);
// SPATIAL_SCALE_CHANNELS = X and Y;
var SPATIAL_SCALE_CHANNEL_INDEX = { x: 1, y: 1 };
exports.SPATIAL_SCALE_CHANNELS = util_1.flagKeys(SPATIAL_SCALE_CHANNEL_INDEX);
// NON_SPATIAL_SCALE_CHANNEL = SCALE_CHANNELS without X, Y
var
// x2 and y2 share the same scale as x and y
// text and tooltip has format instead of scale
_t = NONSPATIAL_CHANNEL_INDEX.text, _tt = NONSPATIAL_CHANNEL_INDEX.tooltip,
// detail and order have no scale
_dd = NONSPATIAL_CHANNEL_INDEX.detail, _oo = NONSPATIAL_CHANNEL_INDEX.order, NONSPATIAL_SCALE_CHANNEL_INDEX = tslib_1.__rest(NONSPATIAL_CHANNEL_INDEX, ["text", "tooltip", "detail", "order"]);
exports.NONSPATIAL_SCALE_CHANNELS = util_1.flagKeys(NONSPATIAL_SCALE_CHANNEL_INDEX);
// Declare SCALE_CHANNEL_INDEX
var SCALE_CHANNEL_INDEX = tslib_1.__assign({}, SPATIAL_SCALE_CHANNEL_INDEX, NONSPATIAL_SCALE_CHANNEL_INDEX);
/** List of channels with scales */
exports.SCALE_CHANNELS = util_1.flagKeys(SCALE_CHANNEL_INDEX);
function isScaleChannel(channel) {
return !!SCALE_CHANNEL_INDEX[channel];
}
exports.isScaleChannel = isScaleChannel;
/**
* Return whether a channel supports a particular mark type.
* @param channel channel name
* @param mark the mark type
* @return whether the mark supports the channel
*/
function supportMark(channel, mark) {
return mark in getSupportedMark(channel);
}
exports.supportMark = supportMark;
/**
* Return a dictionary showing whether a channel supports mark type.
* @param channel
* @return A dictionary mapping mark types to boolean values.
*/
function getSupportedMark(channel) {
switch (channel) {
case exports.X:
case exports.Y:
case exports.COLOR:
case exports.DETAIL:
case exports.TOOLTIP:
case exports.ORDER: // TODO: revise (order might not support rect, which is not stackable?)
case exports.OPACITY:
case exports.ROW:
case exports.COLUMN:
return {
point: true, tick: true, rule: true, circle: true, square: true,
bar: true, rect: true, line: true, area: true, text: true
};
case exports.X2:
case exports.Y2:
return {
rule: true, bar: true, rect: true, area: true
};
case exports.SIZE:
return {
point: true, tick: true, rule: true, circle: true, square: true,
bar: true, text: true, line: true
};
case exports.SHAPE:
return { point: true };
case exports.TEXT:
return { text: true };
}
}
exports.getSupportedMark = getSupportedMark;
function rangeType(channel) {
switch (channel) {
case exports.X:
case exports.Y:
case exports.SIZE:
case exports.OPACITY:
// X2 and Y2 use X and Y scales, so they similarly have continuous range.
case exports.X2:
case exports.Y2:
return 'continuous';
case exports.ROW:
case exports.COLUMN:
case exports.SHAPE:
// TEXT and TOOLTIP have no scale but have discrete output
case exports.TEXT:
case exports.TOOLTIP:
return 'discrete';
// Color can be either continuous or discrete, depending on scale type.
case exports.COLOR:
return 'flexible';
// No scale, no range type.
case exports.DETAIL:
case exports.ORDER:
return undefined;
}
/* istanbul ignore next: should never reach here. */
throw new Error('getSupportedRole not implemented for ' + channel);
}
exports.rangeType = rangeType;
},{"./util":114,"tslib":5}],13:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var mainAxisReducer = getAxisReducer('main');
var gridAxisReducer = getAxisReducer('grid');
function getAxisReducer(axisType) {
return function (axes, axis) {
if (axis[axisType]) {
// Need to cast here so it's not longer partial type.
axes.push(axis[axisType].combine());
}
return axes;
};
}
function assembleAxes(axisComponents) {
return [].concat(axisComponents.x ? [].concat(axisComponents.x.reduce(mainAxisReducer, []), axisComponents.x.reduce(gridAxisReducer, [])) : [], axisComponents.y ? [].concat(axisComponents.y.reduce(mainAxisReducer, []), axisComponents.y.reduce(gridAxisReducer, [])) : []);
}
exports.assembleAxes = assembleAxes;
},{}],14:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var split_1 = require("../split");
var AxisComponentPart = /** @class */ (function (_super) {
tslib_1.__extends(AxisComponentPart, _super);
function AxisComponentPart() {
return _super !== null && _super.apply(this, arguments) || this;
}
return AxisComponentPart;
}(split_1.Split));
exports.AxisComponentPart = AxisComponentPart;
},{"../split":86,"tslib":5}],15:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var channel_1 = require("../../channel");
var fielddef_1 = require("../../fielddef");
var scale_1 = require("../../scale");
var type_1 = require("../../type");
var util_1 = require("../../util");
var common_1 = require("../common");
function labels(model, channel, specifiedLabelsSpec, def) {
var fieldDef = model.fieldDef(channel) ||
(channel === 'x' ? model.fieldDef('x2') :
channel === 'y' ? model.fieldDef('y2') :
undefined);
var axis = model.axis(channel);
var config = model.config;
var labelsSpec = {};
// Text
if (fielddef_1.isTimeFieldDef(fieldDef)) {
var isUTCScale = model.getScaleComponent(channel).get('type') === scale_1.ScaleType.UTC;
labelsSpec.text = {
signal: common_1.timeFormatExpression('datum.value', fieldDef.timeUnit, axis.format, config.axis.shortTimeLabels, config.timeFormat, isUTCScale)
};
}
// Label Angle
var angle = labelAngle(axis, channel, fieldDef);
if (angle) {
labelsSpec.angle = { value: angle };
}
if (labelsSpec.angle && channel === 'x') {
var align = labelAlign(angle, def.get('orient'));
if (align) {
labelsSpec.align = { value: align };
}
// Auto set baseline if x is rotated by 90, or -90
if (util_1.contains([90, 270], angle)) {
labelsSpec.baseline = { value: 'middle' };
}
}
labelsSpec = tslib_1.__assign({}, labelsSpec, specifiedLabelsSpec);
return util_1.keys(labelsSpec).length === 0 ? undefined : labelsSpec;
}
exports.labels = labels;
function labelAngle(axis, channel, fieldDef) {
if (axis.labelAngle !== undefined) {
// Make angle within [0,360)
return ((axis.labelAngle % 360) + 360) % 360;
}
else {
// auto rotate for X
if (channel === channel_1.X && (util_1.contains([type_1.NOMINAL, type_1.ORDINAL], fieldDef.type) || !!fieldDef.bin || fielddef_1.isTimeFieldDef(fieldDef))) {
return 270;
}
}
return undefined;
}
exports.labelAngle = labelAngle;
function labelAlign(angle, orient) {
if (angle && angle > 0) {
if (angle > 180) {
return orient === 'top' ? 'left' : 'right';
}
else if (angle < 180) {
return orient === 'top' ? 'right' : 'left';
}
}
return undefined;
}
exports.labelAlign = labelAlign;
},{"../../channel":12,"../../fielddef":96,"../../scale":104,"../../type":113,"../../util":114,"../common":20,"tslib":5}],16:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var axis_1 = require("../../axis");
var channel_1 = require("../../channel");
var util_1 = require("../../util");
var common_1 = require("../common");
var resolve_1 = require("../resolve");
var split_1 = require("../split");
var component_1 = require("./component");
var encode = require("./encode");
var properties = require("./properties");
var AXIS_PARTS = ['domain', 'grid', 'labels', 'ticks', 'title'];
function parseUnitAxis(model) {
return channel_1.SPATIAL_SCALE_CHANNELS.reduce(function (axis, channel) {
if (model.axis(channel)) {
var axisComponent = {};
// TODO: support multiple axis
var main = parseMainAxis(channel, model);
if (main && isVisibleAxis(main)) {
axisComponent.main = main;
}
var grid = parseGridAxis(channel, model);
if (grid && isVisibleAxis(grid)) {
axisComponent.grid = grid;
}
axis[channel] = [axisComponent];
}
return axis;
}, {});
}
exports.parseUnitAxis = parseUnitAxis;
var OPPOSITE_ORIENT = {
bottom: 'top',
top: 'bottom',
left: 'right',
right: 'left'
};
function parseLayerAxis(model) {
var _a = model.component, axes = _a.axes, resolve = _a.resolve;
var axisCount = { top: 0, bottom: 0, right: 0, left: 0 };
var _loop_1 = function (child) {
child.parseAxisAndHeader();
util_1.keys(child.component.axes).forEach(function (channel) {
resolve.axis[channel] = resolve_1.parseGuideResolve(model.component.resolve, channel);
if (resolve.axis[channel] === 'shared') {
// If the resolve says shared (and has not been overridden)
// We will try to merge and see if there is a conflict
axes[channel] = mergeAxisComponents(axes[channel], child.component.axes[channel]);
if (!axes[channel]) {
// If merge returns nothing, there is a conflict so we cannot make the axis shared.
// Thus, mark axis as independent and remove the axis component.
resolve.axis[channel] = 'independent';
delete axes[channel];
}
}
});
};
for (var _i = 0, _b = model.children; _i < _b.length; _i++) {
var child = _b[_i];
_loop_1(child);
}
// Move axes to layer's axis component and merge shared axes
['x', 'y'].forEach(function (channel) {
for (var _i = 0, _a = model.children; _i < _a.length; _i++) {
var child = _a[_i];
if (!child.component.axes[channel]) {
// skip if the child does not have a particular axis
continue;
}
if (resolve.axis[channel] === 'independent') {
// If axes are independent, concat the axisComponent array.
axes[channel] = (axes[channel] || []).concat(child.component.axes[channel]);
// Automatically adjust orient
child.component.axes[channel].forEach(function (axisComponent) {
var _a = axisComponent.main.getWithExplicit('orient'), orient = _a.value, explicit = _a.explicit;
if (axisCount[orient] > 0 && !explicit) {
// Change axis orient if the number do not match
var oppositeOrient = OPPOSITE_ORIENT[orient];
if (axisCount[orient] > axisCount[oppositeOrient]) {
axisComponent.main.set('orient', oppositeOrient, false);
}
}
axisCount[orient]++;
// TODO(https://github.com/vega/vega-lite/issues/2634): automaticaly add extra offset?
});
}
// After merging, make sure to remove axes from child
delete child.component.axes[channel];
}
});
}
exports.parseLayerAxis = parseLayerAxis;
function mergeAxisComponents(mergedAxisCmpts, childAxisCmpts) {
if (mergedAxisCmpts) {
if (mergedAxisCmpts.length !== childAxisCmpts.length) {
return undefined; // Cannot merge axis component with different number of axes.
}
var length_1 = mergedAxisCmpts.length;
for (var i = 0; i < length_1; i++) {
var mergedMain = mergedAxisCmpts[i].main;
var childMain = childAxisCmpts[i].main;
if ((!!mergedMain) !== (!!childMain)) {
return undefined;
}
else if (mergedMain && childMain) {
var mergedOrient = mergedMain.getWithExplicit('orient');
var childOrient = childMain.getWithExplicit('orient');
if (mergedOrient.explicit && childOrient.explicit && mergedOrient.value !== childOrient.value) {
// TODO: throw warning if resolve is explicit (We don't have info about explicit/implicit resolve yet.)
// Cannot merge due to inconsistent orient
return undefined;
}
else {
mergedAxisCmpts[i].main = mergeAxisComponentPart(mergedMain, childMain);
}
}
var mergedGrid = mergedAxisCmpts[i].grid;
var childGrid = childAxisCmpts[i].grid;
if ((!!mergedGrid) !== (!!childGrid)) {
return undefined;
}
else if (mergedGrid && childGrid) {
mergedAxisCmpts[i].grid = mergeAxisComponentPart(mergedGrid, childGrid);
}
}
}
else {
// For first one, return a copy of the child
return childAxisCmpts.map(function (axisComponent) { return (tslib_1.__assign({}, (axisComponent.main ? { main: axisComponent.main.clone() } : {}), (axisComponent.grid ? { grid: axisComponent.grid.clone() } : {}))); });
}
return mergedAxisCmpts;
}
function mergeAxisComponentPart(merged, child) {
var _loop_2 = function (prop) {
var mergedValueWithExplicit = split_1.mergeValuesWithExplicit(merged.getWithExplicit(prop), child.getWithExplicit(prop), prop, 'axis',
// Tie breaker function
function (v1, v2) {
switch (prop) {
case 'title':
return common_1.titleMerger(v1, v2);
case 'gridScale':
return {
explicit: v1.explicit,
value: v1.value || v2.value
};
}
return split_1.defaultTieBreaker(v1, v2, prop, 'axis');
});
merged.setWithExplicit(prop, mergedValueWithExplicit);
};
for (var _i = 0, VG_AXIS_PROPERTIES_1 = axis_1.VG_AXIS_PROPERTIES; _i < VG_AXIS_PROPERTIES_1.length; _i++) {
var prop = VG_AXIS_PROPERTIES_1[_i];
_loop_2(prop);
}
return merged;
}
function isFalseOrNull(v) {
return v === false || v === null;
}
/**
* Return if an axis is visible (shows at least one part of the axis).
*/
function isVisibleAxis(axis) {
return util_1.some(AXIS_PARTS, function (part) { return hasAxisPart(axis, part); });
}
function hasAxisPart(axis, part) {
// FIXME(https://github.com/vega/vega-lite/issues/2552) this method can be wrong if users use a Vega theme.
if (part === 'axis') {
return true;
}
if (part === 'grid' || part === 'title') {
return !!axis.get(part);
}
// Other parts are enabled by default, so they should not be false or null.
return !isFalseOrNull(axis.get(part));
}
/**
* Make an inner axis for showing grid for shared axis.
*/
function parseGridAxis(channel, model) {
// FIXME: support adding ticks for grid axis that are inner axes of faceted plots.
return parseAxis(channel, model, true);
}
exports.parseGridAxis = parseGridAxis;
function parseMainAxis(channel, model) {
return parseAxis(channel, model, false);
}
exports.parseMainAxis = parseMainAxis;
function parseAxis(channel, model, isGridAxis) {
var axis = model.axis(channel);
var axisComponent = new component_1.AxisComponentPart({}, { scale: model.scaleName(channel) } // implicit
);
// 1.2. Add properties
axis_1.AXIS_PROPERTIES.forEach(function (property) {
var value = getProperty(property, axis, channel, model, isGridAxis);
if (value !== undefined) {
var explicit = property === 'values' ?
!!axis.values :
value === axis[property];
axisComponent.set(property, value, explicit);
}
});
// Special case for gridScale since gridScale is not a Vega-Lite Axis property.
var gridScale = properties.gridScale(model, channel, isGridAxis);
if (gridScale !== undefined) {
axisComponent.set('gridScale', gridScale, false);
}
// 2) Add guide encode definition groups
var axisEncoding = axis.encoding || {};
var axisEncode = AXIS_PARTS.reduce(function (e, part) {
if (!hasAxisPart(axisComponent, part)) {
// No need to create encode for a disabled part.
return e;
}
var value = part === 'labels' ?
encode.labels(model, channel, axisEncoding.labels || {}, axisComponent) :
axisEncoding[part] || {};
if (value !== undefined && util_1.keys(value).length > 0) {
e[part] = { update: value };
}
return e;
}, {});
// FIXME: By having encode as one property, we won't have fine grained encode merging.
if (util_1.keys(axisEncode).length > 0) {
axisComponent.set('encode', axisEncode, !!axis.encoding || !!axis.labelAngle);
}
return axisComponent;
}
function getProperty(property, specifiedAxis, channel, model, isGridAxis) {
var fieldDef = model.fieldDef(channel);
if ((isGridAxis && axis_1.AXIS_PROPERTY_TYPE[property] === 'main') ||
(!isGridAxis && axis_1.AXIS_PROPERTY_TYPE[property] === 'grid')) {
// Do not apply unapplicable properties
return undefined;
}
switch (property) {
case 'domain':
return properties.domain(property, specifiedAxis, isGridAxis, channel);
case 'format':
// We don't include temporal field here as we apply format in encode block
return common_1.numberFormat(fieldDef, specifiedAxis.format, model.config);
case 'grid': {
var scaleType = model.getScaleComponent(channel).get('type');
return common_1.getSpecifiedOrDefaultValue(specifiedAxis.grid, properties.grid(scaleType, fieldDef));
}
case 'labels':
return isGridAxis ? false : specifiedAxis.labels;
case 'labelOverlap': {
var scaleType = model.getScaleComponent(channel).get('type');
return properties.labelOverlap(fieldDef, specifiedAxis, channel, scaleType);
}
case 'minExtent': {
return properties.minMaxExtent(specifiedAxis.minExtent, isGridAxis);
}
case 'maxExtent': {
return properties.minMaxExtent(specifiedAxis.maxExtent, isGridAxis);
}
case 'orient':
return common_1.getSpecifiedOrDefaultValue(specifiedAxis.orient, properties.orient(channel));
case 'tickCount': {
var scaleType = model.getScaleComponent(channel).get('type');
var sizeType = channel === 'x' ? 'width' : channel === 'y' ? 'height' : undefined;
var size = sizeType ? model.getSizeSignalRef(sizeType)
: undefined;
return common_1.getSpecifiedOrDefaultValue(specifiedAxis.tickCount, properties.tickCount(channel, fieldDef, scaleType, size));
}
case 'ticks':
return properties.ticks(property, specifiedAxis, isGridAxis, channel);
case 'title':
return common_1.getSpecifiedOrDefaultValue(specifiedAxis.title, properties.title(specifiedAxis.titleMaxLength, fieldDef, model.config));
case 'values':
return properties.values(specifiedAxis, model, fieldDef);
case 'zindex':
return common_1.getSpecifiedOrDefaultValue(specifiedAxis.zindex, properties.zindex(isGridAxis));
}
// Otherwise, return specified property.
return specifiedAxis[property];
}
},{"../../axis":10,"../../channel":12,"../../util":114,"../common":20,"../resolve":66,"../split":86,"./component":14,"./encode":15,"./properties":17,"tslib":5}],17:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var channel_1 = require("../../channel");
var datetime_1 = require("../../datetime");
var fielddef_1 = require("../../fielddef");
var log = require("../../log");
var scale_1 = require("../../scale");
var util_1 = require("../../util");
function domainAndTicks(property, specifiedAxis, isGridAxis, channel) {
if (isGridAxis) {
return false;
}
return specifiedAxis[property];
}
exports.domainAndTicks = domainAndTicks;
exports.domain = domainAndTicks;
exports.ticks = domainAndTicks;
// TODO: we need to refactor this method after we take care of config refactoring
/**
* Default rules for whether to show a grid should be shown for a channel.
* If `grid` is unspecified, the default value is `true` for ordinal scales that are not binned
*/
function grid(scaleType, fieldDef) {
return !scale_1.hasDiscreteDomain(scaleType) && !fieldDef.bin;
}
exports.grid = grid;
function gridScale(model, channel, isGridAxis) {
if (isGridAxis) {
var gridChannel = channel === 'x' ? 'y' : 'x';
if (model.getScaleComponent(gridChannel)) {
return model.scaleName(gridChannel);
}
}
return undefined;
}
exports.gridScale = gridScale;
function labelOverlap(fieldDef, specifiedAxis, channel, scaleType) {
// do not prevent overlap for nominal data because there is no way to infer what the missing labels are
if (fieldDef.type !== 'nominal') {
if (scaleType === 'log') {
return 'greedy';
}
return true;
}
return undefined;
}
exports.labelOverlap = labelOverlap;
function minMaxExtent(specifiedExtent, isGridAxis) {
if (isGridAxis) {
// Always return 0 to make sure that `config.axis*.minExtent` and `config.axis*.maxExtent`
// would not affect gridAxis
return 0;
}
else {
return specifiedExtent;
}
}
exports.minMaxExtent = minMaxExtent;
function orient(channel) {
switch (channel) {
case channel_1.X:
return 'bottom';
case channel_1.Y:
return 'left';
}
/* istanbul ignore next: This should never happen. */
throw new Error(log.message.INVALID_CHANNEL_FOR_AXIS);
}
exports.orient = orient;
function tickCount(channel, fieldDef, scaleType, size) {
if (!scale_1.hasDiscreteDomain(scaleType) && scaleType !== 'log' && !util_1.contains(['month', 'hours', 'day', 'quarter'], fieldDef.timeUnit)) {
if (fieldDef.bin) {
// for binned data, we don't want more ticks than maxbins
return { signal: "min(ceil(" + size.signal + "/40), " + fieldDef.bin.maxbins + ")" };
}
return { signal: "ceil(" + size.signal + "/40)" };
}
return undefined;
}
exports.tickCount = tickCount;
function title(maxLength, fieldDef, config) {
// if not defined, automatically determine axis title from field def
var fieldTitle = fielddef_1.title(fieldDef, config);
return maxLength ? util_1.truncate(fieldTitle, maxLength) : fieldTitle;
}
exports.title = title;
function values(specifiedAxis, model, fieldDef) {
var vals = specifiedAxis.values;
if (specifiedAxis.values && datetime_1.isDateTime(vals[0])) {
return vals.map(function (dt) {
// normalize = true as end user won't put 0 = January
return { signal: datetime_1.dateTimeExpr(dt, true) };
});
}
return vals;
}
exports.values = values;
function zindex(isGridAxis) {
if (isGridAxis) {
// if grid is true, need to put layer on the back so that grid is behind marks
return 0;
}
return 1; // otherwise return undefined and use Vega's default.
}
exports.zindex = zindex;
},{"../../channel":12,"../../datetime":93,"../../fielddef":96,"../../log":101,"../../scale":104,"../../util":114}],18:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var util_1 = require("../util");
var parse_1 = require("./data/parse");
var assemble_1 = require("./layoutsize/assemble");
var model_1 = require("./model");
var BaseConcatModel = /** @class */ (function (_super) {
tslib_1.__extends(BaseConcatModel, _super);
function BaseConcatModel(spec, parent, parentGivenName, config, resolve) {
return _super.call(this, spec, parent, parentGivenName, config, resolve) || this;
}
BaseConcatModel.prototype.parseData = function () {
this.component.data = parse_1.parseData(this);
this.children.forEach(function (child) {
child.parseData();
});
};
BaseConcatModel.prototype.parseSelection = function () {
var _this = this;
// Merge selections up the hierarchy so that they may be referenced
// across unit specs. Persist their definitions within each child
// to assemble signals which remain within output Vega unit groups.
this.component.selection = {};
var _loop_1 = function (child) {
child.parseSelection();
util_1.keys(child.component.selection).forEach(function (key) {
_this.component.selection[key] = child.component.selection[key];
});
};
for (var _i = 0, _a = this.children; _i < _a.length; _i++) {
var child = _a[_i];
_loop_1(child);
}
};
BaseConcatModel.prototype.parseMarkGroup = function () {
for (var _i = 0, _a = this.children; _i < _a.length; _i++) {
var child = _a[_i];
child.parseMarkGroup();
}
};
BaseConcatModel.prototype.parseAxisAndHeader = function () {
for (var _i = 0, _a = this.children; _i < _a.length; _i++) {
var child = _a[_i];
child.parseAxisAndHeader();
}
// TODO(#2415): support shared axes
};
BaseConcatModel.prototype.assembleSelectionTopLevelSignals = function (signals) {
return this.children.reduce(function (sg, child) { return child.assembleSelectionTopLevelSignals(sg); }, signals);
};
BaseConcatModel.prototype.assembleSelectionSignals = function () {
this.children.forEach(function (child) { return child.assembleSelectionSignals(); });
return [];
};
BaseConcatModel.prototype.assembleLayoutSignals = function () {
return this.children.reduce(function (signals, child) {
return signals.concat(child.assembleLayoutSignals());
}, assemble_1.assembleLayoutSignals(this));
};
BaseConcatModel.prototype.assembleSelectionData = function (data) {
return this.children.reduce(function (db, child) { return child.assembleSelectionData(db); }, []);
};
BaseConcatModel.prototype.assembleMarks = function () {
// only children have marks
return this.children.map(function (child) {
var title = child.assembleTitle();
var style = child.assembleGroupStyle();
var layoutSizeEncodeEntry = child.assembleLayoutSize();
return tslib_1.__assign({ type: 'group', name: child.getName('group') }, (title ? { title: title } : {}), (style ? { style: style } : {}), (layoutSizeEncodeEntry ? {
encode: {
update: layoutSizeEncodeEntry
}
} : {}), child.assembleGroup());
});
};
return BaseConcatModel;
}(model_1.Model));
exports.BaseConcatModel = BaseConcatModel;
},{"../util":114,"./data/parse":37,"./layoutsize/assemble":44,"./model":63,"tslib":5}],19:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var log = require("../log");
var spec_1 = require("../spec");
var concat_1 = require("./concat");
var facet_1 = require("./facet");
var layer_1 = require("./layer");
var repeat_1 = require("./repeat");
var unit_1 = require("./unit");
function buildModel(spec, parent, parentGivenName, unitSize, repeater, config) {
if (spec_1.isFacetSpec(spec)) {
return new facet_1.FacetModel(spec, parent, parentGivenName, repeater, config);
}
if (spec_1.isLayerSpec(spec)) {
return new layer_1.LayerModel(spec, parent, parentGivenName, unitSize, repeater, config);
}
if (spec_1.isUnitSpec(spec)) {
return new unit_1.UnitModel(spec, parent, parentGivenName, unitSize, repeater, config);
}
if (spec_1.isRepeatSpec(spec)) {
return new repeat_1.RepeatModel(spec, parent, parentGivenName, repeater, config);
}
if (spec_1.isConcatSpec(spec)) {
return new concat_1.ConcatModel(spec, parent, parentGivenName, repeater, config);
}
throw new Error(log.message.INVALID_SPEC);
}
exports.buildModel = buildModel;
},{"../log":101,"../spec":107,"./concat":22,"./facet":41,"./layer":42,"./repeat":64,"./unit":87}],20:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var channel_1 = require("../channel");
var fielddef_1 = require("../fielddef");
var scale_1 = require("../scale");
var timeunit_1 = require("../timeunit");
var type_1 = require("../type");
var util_1 = require("../util");
function applyConfig(e, config, // TODO(#1842): consolidate MarkConfig | TextConfig?
propsList) {
for (var _i = 0, propsList_1 = propsList; _i < propsList_1.length; _i++) {
var property = propsList_1[_i];
var value = config[property];
if (value !== undefined) {
e[property] = { value: value };
}
}
return e;
}
exports.applyConfig = applyConfig;
function applyMarkConfig(e, model, propsList) {
for (var _i = 0, propsList_2 = propsList; _i < propsList_2.length; _i++) {
var property = propsList_2[_i];
var value = getMarkConfig(property, model.markDef, model.config);
if (value !== undefined) {
e[property] = { value: value };
}
}
return e;
}
exports.applyMarkConfig = applyMarkConfig;
function getStyles(mark) {
if (mark.style) {
return util_1.isArray(mark.style) ? mark.style : [mark.style];
}
return [mark.type];
}
exports.getStyles = getStyles;
/**
* Return value mark specific config property if exists.
* Otherwise, return general mark specific config.
*/
function getMarkConfig(prop, mark, config) {
// By default, read from mark config first!
var value = config.mark[prop];
// Then read mark specific config, which has higher precedence
var markSpecificConfig = config[mark.type];
if (markSpecificConfig[prop] !== undefined) {
value = markSpecificConfig[prop];
}
var styles = getStyles(mark);
for (var _i = 0, styles_1 = styles; _i < styles_1.length; _i++) {
var style = styles_1[_i];
var styleConfig = config.style[style];
// MarkConfig extends VgMarkConfig so a prop may not be a valid property for style
// However here we also check if it is defined, so it is okay to cast here
var p = prop;
if (styleConfig && styleConfig[p] !== undefined) {
value = styleConfig[p];
}
}
return value;
}
exports.getMarkConfig = getMarkConfig;
function formatSignalRef(fieldDef, specifiedFormat, expr, config) {
var format = numberFormat(fieldDef, specifiedFormat, config);
if (fieldDef.bin) {
var startField = fielddef_1.field(fieldDef, { expr: expr });
var endField = fielddef_1.field(fieldDef, { expr: expr, binSuffix: 'end' });
return {
signal: binFormatExpression(startField, endField, format, config)
};
}
else if (fieldDef.type === 'quantitative') {
return {
signal: "" + formatExpr(fielddef_1.field(fieldDef, { expr: expr }), format)
};
}
else if (fielddef_1.isTimeFieldDef(fieldDef)) {
var isUTCScale = fielddef_1.isScaleFieldDef(fieldDef) && fieldDef['scale'] && fieldDef['scale'].type === scale_1.ScaleType.UTC;
return {
signal: timeFormatExpression(fielddef_1.field(fieldDef, { expr: expr }), fieldDef.timeUnit, specifiedFormat, config.text.shortTimeLabels, config.timeFormat, isUTCScale)
};
}
else {
return {
signal: "''+" + fielddef_1.field(fieldDef, { expr: expr })
};
}
}
exports.formatSignalRef = formatSignalRef;
function getSpecifiedOrDefaultValue(specifiedValue, defaultValue) {
if (specifiedValue !== undefined) {
return specifiedValue;
}
return defaultValue;
}
exports.getSpecifiedOrDefaultValue = getSpecifiedOrDefaultValue;
/**
* Returns number format for a fieldDef
*
* @param format explicitly specified format
*/
function numberFormat(fieldDef, specifiedFormat, config) {
if (fieldDef.type === type_1.QUANTITATIVE) {
// add number format for quantitative type only
// Specified format in axis/legend has higher precedence than fieldDef.format
if (specifiedFormat) {
return specifiedFormat;
}
// TODO: need to make this work correctly for numeric ordinal / nominal type
return config.numberFormat;
}
return undefined;
}
exports.numberFormat = numberFormat;
function formatExpr(field, format) {
return "format(" + field + ", \"" + (format || '') + "\")";
}
function numberFormatExpr(field, specifiedFormat, config) {
return formatExpr(field, specifiedFormat || config.numberFormat);
}
exports.numberFormatExpr = numberFormatExpr;
function binFormatExpression(startField, endField, format, config) {
return startField + " === null || isNaN(" + startField + ") ? \"null\" : " + numberFormatExpr(startField, format, config) + " + \" - \" + " + numberFormatExpr(endField, format, config);
}
exports.binFormatExpression = binFormatExpression;
/**
* Returns the time expression used for axis/legend labels or text mark for a temporal field
*/
function timeFormatExpression(field, timeUnit, format, shortTimeLabels, timeFormatConfig, isUTCScale) {
if (!timeUnit || format) {
// If there is not time unit, or if user explicitly specify format for axis/legend/text.
var _format = format || timeFormatConfig; // only use config.timeFormat if there is no timeUnit.
if (isUTCScale) {
return "utcFormat(" + field + ", '" + _format + "')";
}
else {
return "timeFormat(" + field + ", '" + _format + "')";
}
}
else {
return timeunit_1.formatExpression(timeUnit, field, shortTimeLabels, isUTCScale);
}
}
exports.timeFormatExpression = timeFormatExpression;
/**
* Return Vega sort parameters (tuple of field and order).
*/
function sortParams(orderDef, fieldRefOption) {
return (util_1.isArray(orderDef) ? orderDef : [orderDef]).reduce(function (s, orderChannelDef) {
s.field.push(fielddef_1.field(orderChannelDef, fieldRefOption));
s.order.push(orderChannelDef.sort || 'ascending');
return s;
}, { field: [], order: [] });
}
exports.sortParams = sortParams;
function titleMerger(v1, v2) {
return {
explicit: v1.explicit,
value: v1.value === v2.value ?
v1.value :
v1.value + ', ' + v2.value // join title with comma if different
};
}
exports.titleMerger = titleMerger;
/**
* Checks whether a fieldDef for a particular channel requires a computed bin range.
*/
function binRequiresRange(fieldDef, channel) {
if (!fieldDef.bin) {
console.warn('Only use this method with binned field defs');
return false;
}
// We need the range only when the user explicitly forces a binned field to be use discrete scale. In this case, bin range is used in axis and legend labels.
// We could check whether the axis or legend exists (not disabled) but that seems overkill.
return channel_1.isScaleChannel(channel) && util_1.contains(['ordinal', 'nominal'], fieldDef.type);
}
exports.binRequiresRange = binRequiresRange;
},{"../channel":12,"../fielddef":96,"../scale":104,"../timeunit":109,"../type":113,"../util":114}],21:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
/**
* Module for compiling Vega-lite spec into Vega spec.
*/
var config_1 = require("../config");
var log = require("../log");
var spec_1 = require("../spec");
var toplevelprops_1 = require("../toplevelprops");
var buildmodel_1 = require("./buildmodel");
var assemble_1 = require("./data/assemble");
var optimize_1 = require("./data/optimize");
function compile(inputSpec, logger) {
if (logger) {
// set the singleton logger to the provided logger
log.set(logger);
}
try {
// 1. initialize config
var config = config_1.initConfig(inputSpec.config);
// 2. Convert input spec into a normalized form
// (Decompose all extended unit specs into composition of unit spec.)
var spec = spec_1.normalize(inputSpec, config);
// 3. Instantiate the models with default config by doing a top-down traversal.
// This allows us to pass properties that child models derive from their parents via their constructors.
var model = buildmodel_1.buildModel(spec, null, '', undefined, undefined, config);
// 4. Parse parts of each model to produce components that can be merged
// and assembled easily as a part of a model.
// In this phase, we do a bottom-up traversal over the whole tree to
// parse for each type of components once (e.g., data, layout, mark, scale).
// By doing bottom-up traversal, we start parsing components of unit specs and
// then merge child components of parent composite specs.
//
// Please see inside model.parse() for order of different components parsed.
model.parse();
// 5. Optimize the datafow.
optimize_1.optimizeDataflow(model.component.data);
// 6. Assemble a Vega Spec from the parsed components.
return assembleTopLevelModel(model, getTopLevelProperties(inputSpec, config));
}
finally {
// Reset the singleton logger if a logger is provided
if (logger) {
log.reset();
}
}
}
exports.compile = compile;
function getTopLevelProperties(topLevelSpec, config) {
return tslib_1.__assign({}, toplevelprops_1.extractTopLevelProperties(config), toplevelprops_1.extractTopLevelProperties(topLevelSpec));
}
/*
* Assemble the top-level model.
*
* Note: this couldn't be `model.assemble()` since the top-level model
* needs some special treatment to generate top-level properties.
*/
function assembleTopLevelModel(model, topLevelProperties) {
// TODO: change type to become VgSpec
// Config with Vega-Lite only config removed.
var vgConfig = model.config ? config_1.stripAndRedirectConfig(model.config) : undefined;
// autoResize has to be put under autosize
var autoResize = topLevelProperties.autoResize, topLevelProps = tslib_1.__rest(topLevelProperties, ["autoResize"]);
var title = model.assembleTitle();
var style = model.assembleGroupStyle();
var output = tslib_1.__assign({ $schema: 'https://vega.github.io/schema/vega/v3.0.json' }, (model.description ? { description: model.description } : {}), {
// By using Vega layout, we don't support custom autosize
autosize: topLevelProperties.autoResize ? { type: 'pad', resize: true } : 'pad' }, topLevelProps, (title ? { title: title } : {}), (style ? { style: style } : {}), { data: [].concat(model.assembleSelectionData([]),
// only assemble data in the root
assemble_1.assembleRootData(model.component.data)) }, model.assembleGroup(model.assembleLayoutSignals().concat(model.assembleSelectionTopLevelSignals([]))), (vgConfig ? { config: vgConfig } : {}));
return {
spec: output
// TODO: add warning / errors here
};
}
},{"../config":91,"../log":101,"../spec":107,"../toplevelprops":111,"./buildmodel":19,"./data/assemble":24,"./data/optimize":35,"tslib":5}],22:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var spec_1 = require("../spec");
var baseconcat_1 = require("./baseconcat");
var buildmodel_1 = require("./buildmodel");
var parse_1 = require("./layoutsize/parse");
var ConcatModel = /** @class */ (function (_super) {
tslib_1.__extends(ConcatModel, _super);
function ConcatModel(spec, parent, parentGivenName, repeater, config) {
var _this = _super.call(this, spec, parent, parentGivenName, config, spec.resolve) || this;
_this.type = 'concat';
_this.isVConcat = spec_1.isVConcatSpec(spec);
_this.children = (spec_1.isVConcatSpec(spec) ? spec.vconcat : spec.hconcat).map(function (child, i) {
return buildmodel_1.buildModel(child, _this, _this.getName('concat_' + i), undefined, repeater, config);
});
return _this;
}
ConcatModel.prototype.parseLayoutSize = function () {
parse_1.parseConcatLayoutSize(this);
};
ConcatModel.prototype.parseAxisGroup = function () {
return null;
};
ConcatModel.prototype.assembleLayout = function () {
// TODO: allow customization
return tslib_1.__assign({ padding: { row: 10, column: 10 }, offset: 10 }, (this.isVConcat ? { columns: 1 } : {}), { bounds: 'full',
// Use align each so it can work with multiple plots with different size
align: 'each' });
};
return ConcatModel;
}(baseconcat_1.BaseConcatModel));
exports.ConcatModel = ConcatModel;
},{"../spec":107,"./baseconcat":18,"./buildmodel":19,"./layoutsize/parse":45,"tslib":5}],23:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var channel_1 = require("../../channel");
var fielddef_1 = require("../../fielddef");
var log = require("../../log");
var util_1 = require("../../util");
var common_1 = require("../common");
var dataflow_1 = require("./dataflow");
function addDimension(dims, channel, fieldDef) {
if (fieldDef.bin) {
dims[fielddef_1.field(fieldDef, {})] = true;
dims[fielddef_1.field(fieldDef, { binSuffix: 'end' })] = true;
if (common_1.binRequiresRange(fieldDef, channel)) {
dims[fielddef_1.field(fieldDef, { binSuffix: 'range' })] = true;
}
}
else {
dims[fielddef_1.field(fieldDef)] = true;
}
return dims;
}
function mergeMeasures(parentMeasures, childMeasures) {
for (var f in childMeasures) {
if (childMeasures.hasOwnProperty(f)) {
// when we merge a measure, we either have to add an aggregation operator or even a new field
var ops = childMeasures[f];
for (var op in ops) {
if (ops.hasOwnProperty(op)) {
if (f in parentMeasures) {
// add operator to existing measure field
parentMeasures[f][op] = ops[op];
}
else {
parentMeasures[f] = { op: ops[op] };
}
}
}
}
}
}
var AggregateNode = /** @class */ (function (_super) {
tslib_1.__extends(AggregateNode, _super);
/**
* @param dimensions string set for dimensions
* @param measures dictionary mapping field name => dict of aggregation functions and names to use
*/
function AggregateNode(dimensions, measures) {
var _this = _super.call(this) || this;
_this.dimensions = dimensions;
_this.measures = measures;
return _this;
}
AggregateNode.prototype.clone = function () {
return new AggregateNode(tslib_1.__assign({}, this.dimensions), util_1.duplicate(this.measures));
};
AggregateNode.makeFromEncoding = function (model) {
var isAggregate = false;
model.forEachFieldDef(function (fd) {
if (fd.aggregate) {
isAggregate = true;
}
});
var meas = {};
var dims = {};
if (!isAggregate) {
// no need to create this node if the model has no aggregation
return null;
}
model.forEachFieldDef(function (fieldDef, channel) {
if (fieldDef.aggregate) {
if (fieldDef.aggregate === 'count') {
meas['*'] = meas['*'] || {};
meas['*']['count'] = fielddef_1.field(fieldDef, { aggregate: 'count' });
}
else {
meas[fieldDef.field] = meas[fieldDef.field] || {};
meas[fieldDef.field][fieldDef.aggregate] = fielddef_1.field(fieldDef);
// For scale channel with domain === 'unaggregated', add min/max so we can use their union as unaggregated domain
if (channel_1.isScaleChannel(channel) && model.scaleDomain(channel) === 'unaggregated') {
meas[fieldDef.field]['min'] = fielddef_1.field(fieldDef, { aggregate: 'min' });
meas[fieldDef.field]['max'] = fielddef_1.field(fieldDef, { aggregate: 'max' });
}
}
}
else {
addDimension(dims, channel, fieldDef);
}
});
if ((util_1.keys(dims).length + util_1.keys(meas).length) === 0) {
return null;
}
return new AggregateNode(dims, meas);
};
AggregateNode.makeFromTransform = function (t) {
var dims = {};
var meas = {};
for (var _i = 0, _a = t.summarize; _i < _a.length; _i++) {
var s = _a[_i];
if (s.aggregate) {
if (s.aggregate === 'count') {
meas['*'] = meas['*'] || {};
meas['*']['count'] = s.as || fielddef_1.field(s);
}
else {
meas[s.field] = meas[s.field] || {};
meas[s.field][s.aggregate] = s.as || fielddef_1.field(s);
}
}
}
for (var _b = 0, _c = t.groupby; _b < _c.length; _b++) {
var s = _c[_b];
dims[s] = true;
}
if ((util_1.keys(dims).length + util_1.keys(meas).length) === 0) {
return null;
}
return new AggregateNode(dims, meas);
};
AggregateNode.prototype.merge = function (other) {
if (!util_1.differ(this.dimensions, other.dimensions)) {
mergeMeasures(this.measures, other.measures);
other.remove();
}
else {
log.debug('different dimensions, cannot merge');
}
};
AggregateNode.prototype.addDimensions = function (fields) {
var _this = this;
fields.forEach(function (f) { return _this.dimensions[f] = true; });
};
AggregateNode.prototype.dependentFields = function () {
var out = {};
util_1.keys(this.dimensions).forEach(function (f) { return out[f] = true; });
util_1.keys(this.measures).forEach(function (m) { return out[m] = true; });
return out;
};
AggregateNode.prototype.producedFields = function () {
var _this = this;
var out = {};
util_1.keys(this.measures).forEach(function (field) {
util_1.keys(_this.measures[field]).forEach(function (op) {
out[op + "_" + field] = true;
});
});
return out;
};
AggregateNode.prototype.assemble = function () {
var _this = this;
var ops = [];
var fields = [];
var as = [];
util_1.keys(this.measures).forEach(function (field) {
util_1.keys(_this.measures[field]).forEach(function (op) {
as.push(_this.measures[field][op]);
ops.push(op);
fields.push(field);
});
});
var result = {
type: 'aggregate',
groupby: util_1.keys(this.dimensions),
ops: ops,
fields: fields,
as: as
};
return result;
};
return AggregateNode;
}(dataflow_1.DataFlowNode));
exports.AggregateNode = AggregateNode;
},{"../../channel":12,"../../fielddef":96,"../../log":101,"../../util":114,"../common":20,"./dataflow":27,"tslib":5}],24:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var data_1 = require("../../data");
var util_1 = require("../../util");
var aggregate_1 = require("./aggregate");
var bin_1 = require("./bin");
var calculate_1 = require("./calculate");
var dataflow_1 = require("./dataflow");
var facet_1 = require("./facet");
var filter_1 = require("./filter");
var formatparse_1 = require("./formatparse");
var indentifier_1 = require("./indentifier");
var lookup_1 = require("./lookup");
var nonpositivefilter_1 = require("./nonpositivefilter");
var nullfilter_1 = require("./nullfilter");
var source_1 = require("./source");
var stack_1 = require("./stack");
var timeunit_1 = require("./timeunit");
/**
* Print debug information for dataflow tree.
*/
// tslint:disable-next-line
function debug(node) {
console.log("" + node.constructor.name + (node.debugName ? " (" + node.debugName + ")" : '') + " -> " + (node.children.map(function (c) {
return "" + c.constructor.name + (c.debugName ? " (" + c.debugName + ")" : '');
})));
console.log(node);
node.children.forEach(debug);
}
function makeWalkTree(data) {
// to name datasources
var datasetIndex = 0;
/**
* Recursively walk down the tree.
*/
function walkTree(node, dataSource) {
if (node instanceof source_1.SourceNode) {
// If the source is a named data source or a data source with values, we need
// to put it in a different data source. Otherwise, Vega may override the data.
if (!data_1.isUrlData(node.data)) {
data.push(dataSource);
var newData = {
name: null,
source: dataSource.name,
transform: []
};
dataSource = newData;
}
}
if (node instanceof formatparse_1.ParseNode) {
if (node.parent instanceof source_1.SourceNode && !dataSource.source) {
// If node's parent is a root source and the data source does not refer to another data source, use normal format parse
dataSource.format = tslib_1.__assign({}, dataSource.format || {}, { parse: node.assembleFormatParse() });
}
else {
// Otherwise use Vega expression to parse
dataSource.transform = dataSource.transform.concat(node.assembleTransforms());
}
}
if (node instanceof facet_1.FacetNode) {
if (!dataSource.name) {
dataSource.name = "data_" + datasetIndex++;
}
if (!dataSource.source || dataSource.transform.length > 0) {
data.push(dataSource);
node.data = dataSource.name;
}
else {
node.data = dataSource.source;
}
node.assemble().forEach(function (d) { return data.push(d); });
// break here because the rest of the tree has to be taken care of by the facet.
return;
}
if (node instanceof filter_1.FilterNode ||
node instanceof nullfilter_1.NullFilterNode ||
node instanceof calculate_1.CalculateNode ||
node instanceof aggregate_1.AggregateNode ||
node instanceof lookup_1.LookupNode ||
node instanceof indentifier_1.IdentifierNode) {
dataSource.transform.push(node.assemble());
}
if (node instanceof nonpositivefilter_1.NonPositiveFilterNode ||
node instanceof bin_1.BinNode ||
node instanceof timeunit_1.TimeUnitNode ||
node instanceof stack_1.StackNode) {
dataSource.transform = dataSource.transform.concat(node.assemble());
}
if (node instanceof aggregate_1.AggregateNode) {
if (!dataSource.name) {
dataSource.name = "data_" + datasetIndex++;
}
}
if (node instanceof dataflow_1.OutputNode) {
if (dataSource.source && dataSource.transform.length === 0) {
node.setSource(dataSource.source);
}
else if (node.parent instanceof dataflow_1.OutputNode) {
// Note that an output node may be required but we still do not assemble a
// separate data source for it.
node.setSource(dataSource.name);
}
else {
if (!dataSource.name) {
dataSource.name = "data_" + datasetIndex++;
}
// Here we set the name of the datasource we generated. From now on
// other assemblers can use it.
node.setSource(dataSource.name);
// if this node has more than one child, we will add a datasource automatically
if (node.numChildren() === 1) {
data.push(dataSource);
var newData = {
name: null,
source: dataSource.name,
transform: []
};
dataSource = newData;
}
}
}
switch (node.numChildren()) {
case 0:
// done
if (node instanceof dataflow_1.OutputNode && (!dataSource.source || dataSource.transform.length > 0)) {
// do not push empty datasources that are simply references
data.push(dataSource);
}
break;
case 1:
walkTree(node.children[0], dataSource);
break;
default:
if (!dataSource.name) {
dataSource.name = "data_" + datasetIndex++;
}
var source_2 = dataSource.name;
if (!dataSource.source || dataSource.transform.length > 0) {
data.push(dataSource);
}
else {
source_2 = dataSource.source;
}
node.children.forEach(function (child) {
var newData = {
name: null,
source: source_2,
transform: []
};
walkTree(child, newData);
});
break;
}
}
return walkTree;
}
/**
* Assemble data sources that are derived from faceted data.
*/
function assembleFacetData(root) {
var data = [];
var walkTree = makeWalkTree(data);
root.children.forEach(function (child) { return walkTree(child, {
source: root.name,
name: null,
transform: []
}); });
return data;
}
exports.assembleFacetData = assembleFacetData;
/**
* Create Vega Data array from a given compiled model and append all of them to the given array
*
* @param model
* @param data array
* @return modified data array
*/
function assembleRootData(dataComponent) {
var roots = util_1.vals(dataComponent.sources);
var data = [];
// roots.forEach(debug);
var walkTree = makeWalkTree(data);
var sourceIndex = 0;
roots.forEach(function (root) {
// assign a name if the source does not have a name yet
if (!root.hasName()) {
root.dataName = "source_" + sourceIndex++;
}
var newData = root.assemble();
walkTree(root, newData);
});
// remove empty transform arrays for cleaner output
data.forEach(function (d) {
if (d.transform.length === 0) {
delete d.transform;
}
});
// move sources without transforms (the ones that are potentially used in lookups) to the beginning
data.sort(function (a, b) { return (a.transform || []).length === 0 ? -1 : ((b.transform || []).length === 0 ? 1 : 0); });
// now fix the from references in lookup transforms
for (var _i = 0, data_2 = data; _i < data_2.length; _i++) {
var d = data_2[_i];
for (var _a = 0, _b = d.transform || []; _a < _b.length; _a++) {
var t = _b[_a];
if (t.type === 'lookup') {
t.from = dataComponent.outputNodes[t.from].getSource();
}
}
}
return data;
}
exports.assembleRootData = assembleRootData;
},{"../../data":92,"../../util":114,"./aggregate":23,"./bin":25,"./calculate":26,"./dataflow":27,"./facet":28,"./filter":29,"./formatparse":30,"./indentifier":31,"./lookup":32,"./nonpositivefilter":33,"./nullfilter":34,"./source":38,"./stack":39,"./timeunit":40,"tslib":5}],25:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var bin_1 = require("../../bin");
var fielddef_1 = require("../../fielddef");
var util_1 = require("../../util");
var common_1 = require("../common");
var model_1 = require("../model");
var dataflow_1 = require("./dataflow");
function rangeFormula(model, fieldDef, channel, config) {
if (common_1.binRequiresRange(fieldDef, channel)) {
// read format from axis or legend, if there is no format then use config.numberFormat
var guide = model_1.isUnitModel(model) ? (model.axis(channel) || model.legend(channel) || {}) : {};
var startField = fielddef_1.field(fieldDef, { expr: 'datum', });
var endField = fielddef_1.field(fieldDef, { expr: 'datum', binSuffix: 'end' });
return {
formulaAs: fielddef_1.field(fieldDef, { binSuffix: 'range' }),
formula: common_1.binFormatExpression(startField, endField, guide.format, config)
};
}
return {};
}
function binKey(bin, field) {
return bin_1.binToString(bin) + "_" + field;
}
function isModelParams(p) {
return !!p['model'];
}
function getSignalsFromParams(params, key) {
if (isModelParams(params)) {
var model = params.model;
return {
signal: model.getName(key + "_bins"),
extentSignal: model.getName(key + "_extent")
};
}
return params;
}
function createBinComponent(t, params) {
var bin = fielddef_1.normalizeBin(t.bin, undefined) || {};
var key = binKey(bin, t.field);
var _a = getSignalsFromParams(params, key), signal = _a.signal, extentSignal = _a.extentSignal;
var binComponent = tslib_1.__assign({ bin: bin, field: t.field, as: [fielddef_1.field(t, {}), fielddef_1.field(t, { binSuffix: 'end' })] }, signal ? { signal: signal } : {}, extentSignal ? { extentSignal: extentSignal } : {});
return { key: key, binComponent: binComponent };
}
var BinNode = /** @class */ (function (_super) {
tslib_1.__extends(BinNode, _super);
function BinNode(bins) {
var _this = _super.call(this) || this;
_this.bins = bins;
return _this;
}
BinNode.prototype.clone = function () {
return new BinNode(util_1.duplicate(this.bins));
};
BinNode.makeBinFromEncoding = function (model) {
var bins = model.reduceFieldDef(function (binComponentIndex, fieldDef, channel) {
if (fieldDef.bin) {
var _a = createBinComponent(fieldDef, { model: model }), key = _a.key, binComponent = _a.binComponent;
binComponentIndex[key] = tslib_1.__assign({}, binComponent, binComponentIndex[key], rangeFormula(model, fieldDef, channel, model.config));
}
return binComponentIndex;
}, {});
if (util_1.keys(bins).length === 0) {
return null;
}
return new BinNode(bins);
};
/**
* Creates a bin node from BinTransform.
* The optional parameter should provide
*/
BinNode.makeFromTransform = function (t, params) {
var _a = createBinComponent(t, params), key = _a.key, binComponent = _a.binComponent;
return new BinNode((_b = {},
_b[key] = binComponent,
_b));
var _b;
};
BinNode.prototype.merge = function (other) {
this.bins = tslib_1.__assign({}, this.bins, other.bins);
other.remove();
};
BinNode.prototype.producedFields = function () {
var out = {};
util_1.vals(this.bins).forEach(function (c) {
c.as.forEach(function (f) { return out[f] = true; });
});
return out;
};
BinNode.prototype.dependentFields = function () {
var out = {};
util_1.vals(this.bins).forEach(function (c) {
out[c.field] = true;
});
return out;
};
BinNode.prototype.assemble = function () {
return util_1.flatten(util_1.vals(this.bins).map(function (bin) {
var transform = [];
var binTrans = tslib_1.__assign({ type: 'bin', field: bin.field, as: bin.as, signal: bin.signal }, bin.bin);
if (!bin.bin.extent && bin.extentSignal) {
transform.push({
type: 'extent',
field: bin.field,
signal: bin.extentSignal
});
binTrans.extent = { signal: bin.extentSignal };
}
transform.push(binTrans);
if (bin.formula) {
transform.push({
type: 'formula',
expr: bin.formula,
as: bin.formulaAs
});
}
return transform;
}));
};
return BinNode;
}(dataflow_1.DataFlowNode));
exports.BinNode = BinNode;
},{"../../bin":11,"../../fielddef":96,"../../util":114,"../common":20,"../model":63,"./dataflow":27,"tslib":5}],26:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var util_1 = require("../../util");
var dataflow_1 = require("./dataflow");
/**
* We don't know what a calculate node depends on so we should never move it beyond anything that produces fields.
*/
var CalculateNode = /** @class */ (function (_super) {
tslib_1.__extends(CalculateNode, _super);
function CalculateNode(transform) {
var _this = _super.call(this) || this;
_this.transform = transform;
return _this;
}
CalculateNode.prototype.clone = function () {
return new CalculateNode(util_1.duplicate(this.transform));
};
CalculateNode.prototype.producedFields = function () {
var out = {};
out[this.transform.as] = true;
return out;
};
CalculateNode.prototype.assemble = function () {
return {
type: 'formula',
expr: this.transform.calculate,
as: this.transform.as
};
};
return CalculateNode;
}(dataflow_1.DataFlowNode));
exports.CalculateNode = CalculateNode;
},{"../../util":114,"./dataflow":27,"tslib":5}],27:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
/**
* A node in the dataflow tree.
*/
var DataFlowNode = /** @class */ (function () {
function DataFlowNode(debugName) {
this.debugName = debugName;
this._children = [];
this._parent = null;
}
/**
* Clone this node with a deep copy but don't clone links to children or parents.
*/
DataFlowNode.prototype.clone = function () {
throw new Error('Cannot clone node');
};
/**
* Set of fields that are being created by this node.
*/
DataFlowNode.prototype.producedFields = function () {
return {};
};
DataFlowNode.prototype.dependentFields = function () {
return {};
};
Object.defineProperty(DataFlowNode.prototype, "parent", {
get: function () {
return this._parent;
},
/**
* Set the parent of the node and also add this not to the parent's children.
*/
set: function (parent) {
this._parent = parent;
parent.addChild(this);
},
enumerable: true,
configurable: true
});
Object.defineProperty(DataFlowNode.prototype, "children", {
get: function () {
return this._children;
},
enumerable: true,
configurable: true
});
DataFlowNode.prototype.numChildren = function () {
return this._children.length;
};
DataFlowNode.prototype.addChild = function (child) {
this._children.push(child);
};
DataFlowNode.prototype.removeChild = function (oldChild) {
this._children.splice(this._children.indexOf(oldChild), 1);
};
/**
* Remove node from the dataflow.
*/
DataFlowNode.prototype.remove = function () {
for (var _i = 0, _a = this._children; _i < _a.length; _i++) {
var child = _a[_i];
child.parent = this._parent;
}
this._parent.removeChild(this);
};
/**
* Insert another node as a parent of this node.
*/
DataFlowNode.prototype.insertAsParentOf = function (other) {
var parent = other.parent;
parent.removeChild(this);
this.parent = parent;
other.parent = this;
};
DataFlowNode.prototype.swapWithParent = function () {
var parent = this._parent;
var newParent = parent.parent;
// reconnect the children
for (var _i = 0, _a = this._children; _i < _a.length; _i++) {
var child = _a[_i];
child.parent = parent;
}
// remove old links
this._children = []; // equivalent to removing every child link one by one
parent.removeChild(this);
parent.parent.removeChild(parent);
// swap two nodes
this.parent = newParent;
parent.parent = this;
};
return DataFlowNode;
}());
exports.DataFlowNode = DataFlowNode;
var OutputNode = /** @class */ (function (_super) {
tslib_1.__extends(OutputNode, _super);
/**
* @param source The name of the source. Will change in assemble.
* @param type The type of the output node.
* @param refCounts A global ref counter map.
*/
function OutputNode(source, type, refCounts) {
var _this = _super.call(this, source) || this;
_this.type = type;
_this.refCounts = refCounts;
_this._source = _this._name = source;
if (_this.refCounts && !(_this._name in _this.refCounts)) {
_this.refCounts[_this._name] = 0;
}
return _this;
}
OutputNode.prototype.clone = function () {
var cloneObj = new this.constructor;
cloneObj.debugName = 'clone_' + this.debugName;
cloneObj._source = this._source;
cloneObj._name = 'clone_' + this._name;
cloneObj.type = this.type;
cloneObj.refCounts = this.refCounts;
cloneObj.refCounts[cloneObj._name] = 0;
return cloneObj;
};
/**
* Request the datasource name and increase the ref counter.
*
* During the parsing phase, this will return the simple name such as 'main' or 'raw'.
* It is crucial to request the name from an output node to mark it as a required node.
* If nobody ever requests the name, this datasource will not be instantiated in the assemble phase.
*
* In the assemble phase, this will return the correct name.
*/
OutputNode.prototype.getSource = function () {
this.refCounts[this._name]++;
return this._source;
};
OutputNode.prototype.isRequired = function () {
return !!this.refCounts[this._name];
};
OutputNode.prototype.setSource = function (source) {
this._source = source;
};
return OutputNode;
}(DataFlowNode));
exports.OutputNode = OutputNode;
},{"tslib":5}],28:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var channel_1 = require("../../channel");
var log = require("../../log");
var scale_1 = require("../../scale");
var vega_schema_1 = require("../../vega.schema");
var domain_1 = require("../scale/domain");
var dataflow_1 = require("./dataflow");
/**
* A node that helps us track what fields we are faceting by.
*/
var FacetNode = /** @class */ (function (_super) {
tslib_1.__extends(FacetNode, _super);
/**
* @param model The facet model.
* @param name The name that this facet source will have.
* @param data The source data for this facet data.
*/
function FacetNode(model, name, data) {
var _this = _super.call(this) || this;
_this.model = model;
_this.name = name;
_this.data = data;
if (model.facet.column) {
_this.columnFields = [model.field(channel_1.COLUMN)];
_this.columnName = model.getName('column_domain');
if (model.fieldDef(channel_1.COLUMN).bin) {
_this.columnFields.push(model.field(channel_1.COLUMN, { binSuffix: 'end' }));
}
}
if (model.facet.row) {
_this.rowFields = [model.field(channel_1.ROW)];
_this.rowName = model.getName('row_domain');
if (model.fieldDef(channel_1.ROW).bin) {
_this.rowFields.push(model.field(channel_1.ROW, { binSuffix: 'end' }));
}
}
_this.childModel = model.child;
return _this;
}
Object.defineProperty(FacetNode.prototype, "fields", {
get: function () {
var fields = [];
if (this.columnFields) {
fields = fields.concat(this.columnFields);
}
if (this.rowFields) {
fields = fields.concat(this.rowFields);
}
return fields;
},
enumerable: true,
configurable: true
});
/**
* The name to reference this source is its name.
*/
FacetNode.prototype.getSource = function () {
return this.name;
};
FacetNode.prototype.getChildIndependentFieldsWithStep = function () {
var childIndependentFieldsWithStep = {};
for (var _i = 0, _a = ['x', 'y']; _i < _a.length; _i++) {
var channel = _a[_i];
var childScaleComponent = this.childModel.component.scales[channel];
if (childScaleComponent && !childScaleComponent.merged) {
var type = childScaleComponent.get('type');
var range = childScaleComponent.get('range');
if (scale_1.hasDiscreteDomain(type) && vega_schema_1.isVgRangeStep(range)) {
var domain = domain_1.assembleDomain(this.childModel, channel);
var field = domain_1.getFieldFromDomain(domain);
if (field) {
childIndependentFieldsWithStep[channel] = field;
}
else {
log.warn('Unknown field for ${channel}. Cannot calculate view size.');
}
}
}
}
return childIndependentFieldsWithStep;
};
FacetNode.prototype.assembleRowColumnData = function (channel, crossedDataName, childIndependentFieldsWithStep) {
var aggregateChildField = {};
var childChannel = channel === 'row' ? 'y' : 'x';
if (childIndependentFieldsWithStep[childChannel]) {
if (crossedDataName) {
aggregateChildField = {
// If there is a crossed data, calculate max
fields: ["distinct_" + childIndependentFieldsWithStep[childChannel]],
ops: ['max'],
// Although it is technically a max, just name it distinct so it's easier to refer to it
as: ["distinct_" + childIndependentFieldsWithStep[childChannel]]
};
}
else {
aggregateChildField = {
// If there is no crossed data, just calculate distinct
fields: [childIndependentFieldsWithStep[childChannel]],
ops: ['distinct']
};
}
}
return {
name: channel === 'row' ? this.rowName : this.columnName,
// Use data from the crossed one if it exist
source: crossedDataName || this.data,
transform: [tslib_1.__assign({ type: 'aggregate', groupby: channel === 'row' ? this.rowFields : this.columnFields }, aggregateChildField)]
};
};
FacetNode.prototype.assemble = function () {
var data = [];
var crossedDataName = null;
var childIndependentFieldsWithStep = this.getChildIndependentFieldsWithStep();
if (this.columnName && this.rowName && (childIndependentFieldsWithStep.x || childIndependentFieldsWithStep.y)) {
// Need to create a cross dataset to correctly calculate cardinality
crossedDataName = "cross_" + this.columnName + "_" + this.rowName;
var fields = [].concat(childIndependentFieldsWithStep.x ? [childIndependentFieldsWithStep.x] : [], childIndependentFieldsWithStep.y ? [childIndependentFieldsWithStep.y] : []);
var ops = fields.map(function () { return 'distinct'; });
data.push({
name: crossedDataName,
source: this.data,
transform: [{
type: 'aggregate',
groupby: this.columnFields.concat(this.rowFields),
fields: fields,
ops: ops
}]
});
}
if (this.columnName) {
data.push(this.assembleRowColumnData('column', crossedDataName, childIndependentFieldsWithStep));
}
if (this.rowName) {
data.push(this.assembleRowColumnData('row', crossedDataName, childIndependentFieldsWithStep));
}
return data;
};
return FacetNode;
}(dataflow_1.DataFlowNode));
exports.FacetNode = FacetNode;
},{"../../channel":12,"../../log":101,"../../scale":104,"../../vega.schema":116,"../scale/domain":69,"./dataflow":27,"tslib":5}],29:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var filter_1 = require("../../filter");
var util_1 = require("../../util");
var dataflow_1 = require("./dataflow");
var FilterNode = /** @class */ (function (_super) {
tslib_1.__extends(FilterNode, _super);
function FilterNode(model, filter) {
var _this = _super.call(this) || this;
_this.model = model;
_this.filter = filter;
_this.expr = filter_1.expression(_this.model, _this.filter, _this);
return _this;
}
FilterNode.prototype.clone = function () {
return new FilterNode(this.model, util_1.duplicate(this.filter));
};
FilterNode.prototype.assemble = function () {
return {
type: 'filter',
expr: this.expr
};
};
return FilterNode;
}(dataflow_1.DataFlowNode));
exports.FilterNode = FilterNode;
},{"../../filter":97,"../../util":114,"./dataflow":27,"tslib":5}],30:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var aggregate_1 = require("../../aggregate");
var fielddef_1 = require("../../fielddef");
var filter_1 = require("../../filter");
var log = require("../../log");
var logical_1 = require("../../logical");
var transform_1 = require("../../transform");
var util_1 = require("../../util");
var model_1 = require("../model");
var dataflow_1 = require("./dataflow");
function parseExpression(field, parse) {
var f = "datum[" + util_1.stringValue(field) + "]";
if (parse === 'number') {
return "toNumber(" + f + ")";
}
else if (parse === 'boolean') {
return "toBoolean(" + f + ")";
}
else if (parse === 'string') {
return "toString(" + f + ")";
}
else if (parse === 'date') {
return "toDate(" + f + ")";
}
else if (parse.indexOf('date:') === 0) {
var specifier = parse.slice(5, parse.length);
return "timeParse(" + f + "," + specifier + ")";
}
else if (parse.indexOf('utc:') === 0) {
var specifier = parse.slice(4, parse.length);
return "utcParse(" + f + "," + specifier + ")";
}
else {
log.warn(log.message.unrecognizedParse(parse));
return null;
}
}
var ParseNode = /** @class */ (function (_super) {
tslib_1.__extends(ParseNode, _super);
function ParseNode(parse) {
var _this = _super.call(this) || this;
_this._parse = {};
_this._parse = parse;
return _this;
}
ParseNode.prototype.clone = function () {
return new ParseNode(util_1.duplicate(this.parse));
};
ParseNode.make = function (model) {
var parse = {};
var calcFieldMap = {};
(model.transforms || []).forEach(function (transform) {
if (transform_1.isCalculate(transform)) {
calcFieldMap[transform.as] = true;
}
else if (transform_1.isFilter(transform)) {
logical_1.forEachLeave(transform.filter, function (filter) {
if (filter_1.isEqualFilter(filter) || filter_1.isRangeFilter(filter) || filter_1.isOneOfFilter(filter)) {
if (filter.timeUnit) {
parse[filter.field] = 'date';
}
}
});
}
}, {});
if (model_1.isUnitModel(model) || model_1.isFacetModel(model)) {
// Parse encoded fields
model.forEachFieldDef(function (fieldDef) {
if (fielddef_1.isTimeFieldDef(fieldDef)) {
parse[fieldDef.field] = 'date';
}
else if (fielddef_1.isNumberFieldDef(fieldDef)) {
if (calcFieldMap[fieldDef.field] || aggregate_1.isCountingAggregateOp(fieldDef.aggregate)) {
return;
}
parse[fieldDef.field] = 'number';
}
});
}
// Custom parse should override inferred parse
var data = model.data;
if (data && data.format && data.format.parse) {
var p_1 = data.format.parse;
util_1.keys(p_1).forEach(function (field) {
parse[field] = p_1[field];
});
}
// We should not parse what has already been parsed in a parent
var modelParse = model.component.data.ancestorParse;
util_1.keys(modelParse).forEach(function (field) {
if (parse[field] !== modelParse[field]) {
log.warn(log.message.differentParse(field, parse[field], modelParse[field]));
}
else {
delete parse[field];
}
});
if (util_1.keys(parse).length === 0) {
return null;
}
return new ParseNode(parse);
};
Object.defineProperty(ParseNode.prototype, "parse", {
get: function () {
return this._parse;
},
enumerable: true,
configurable: true
});
ParseNode.prototype.merge = function (other) {
this._parse = tslib_1.__assign({}, this._parse, other.parse);
other.remove();
};
ParseNode.prototype.assembleFormatParse = function () {
return this._parse;
};
// format parse depends and produces all fields in its parse
ParseNode.prototype.producedFields = function () {
return util_1.toSet(util_1.keys(this.parse));
};
ParseNode.prototype.dependentFields = function () {
return util_1.toSet(util_1.keys(this.parse));
};
ParseNode.prototype.assembleTransforms = function () {
var _this = this;
return util_1.keys(this._parse).map(function (field) {
var expr = parseExpression(field, _this._parse[field]);
if (!expr) {
return null;
}
var formula = {
type: 'formula',
expr: expr,
as: field
};
return formula;
}).filter(function (t) { return t !== null; });
};
return ParseNode;
}(dataflow_1.DataFlowNode));
exports.ParseNode = ParseNode;
},{"../../aggregate":9,"../../fielddef":96,"../../filter":97,"../../log":101,"../../logical":102,"../../transform":112,"../../util":114,"../model":63,"./dataflow":27,"tslib":5}],31:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var selection_1 = require("../../selection");
var dataflow_1 = require("./dataflow");
var IdentifierNode = /** @class */ (function (_super) {
tslib_1.__extends(IdentifierNode, _super);
function IdentifierNode() {
return _super.call(this) || this;
}
IdentifierNode.prototype.clone = function () {
return new IdentifierNode();
};
IdentifierNode.prototype.producedFields = function () {
return _a = {}, _a[selection_1.SELECTION_ID] = true, _a;
var _a;
};
IdentifierNode.prototype.assemble = function () {
return { type: 'identifier', as: selection_1.SELECTION_ID };
};
return IdentifierNode;
}(dataflow_1.DataFlowNode));
exports.IdentifierNode = IdentifierNode;
},{"../../selection":105,"./dataflow":27,"tslib":5}],32:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var vega_util_1 = require("vega-util");
var log = require("../../log");
var dataflow_1 = require("./dataflow");
var source_1 = require("./source");
var LookupNode = /** @class */ (function (_super) {
tslib_1.__extends(LookupNode, _super);
function LookupNode(transform, secondary) {
var _this = _super.call(this) || this;
_this.transform = transform;
_this.secondary = secondary;
return _this;
}
LookupNode.make = function (model, transform, counter) {
var sources = model.component.data.sources;
var s = new source_1.SourceNode(transform.from.data);
var fromSource = sources[s.hash()];
if (!fromSource) {
sources[s.hash()] = s;
fromSource = s;
}
var fromOutputName = model.getName("lookup_" + counter);
var fromOutputNode = new dataflow_1.OutputNode(fromOutputName, 'lookup', model.component.data.outputNodeRefCounts);
fromOutputNode.parent = fromSource;
model.component.data.outputNodes[fromOutputName] = fromOutputNode;
return new LookupNode(transform, fromOutputNode.getSource());
};
LookupNode.prototype.producedFields = function () {
return vega_util_1.toSet(this.transform.from.fields || ((this.transform.as instanceof Array) ? this.transform.as : [this.transform.as]));
};
LookupNode.prototype.assemble = function () {
var foreign;
if (this.transform.from.fields) {
// lookup a few fields and add create a flat output
foreign = tslib_1.__assign({ values: this.transform.from.fields }, this.transform.as ? { as: ((this.transform.as instanceof Array) ? this.transform.as : [this.transform.as]) } : {});
}
else {
// lookup full record and nest it
var asName = this.transform.as;
if (!vega_util_1.isString(asName)) {
log.warn(log.message.NO_FIELDS_NEEDS_AS);
asName = '_lookup';
}
foreign = {
as: [asName]
};
}
return tslib_1.__assign({ type: 'lookup', from: this.secondary, key: this.transform.from.key, fields: [this.transform.lookup] }, foreign, (this.transform.default ? { default: this.transform.default } : {}));
};
return LookupNode;
}(dataflow_1.DataFlowNode));
exports.LookupNode = LookupNode;
},{"../../log":101,"./dataflow":27,"./source":38,"tslib":5,"vega-util":7}],33:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var channel_1 = require("../../channel");
var scale_1 = require("../../scale");
var util_1 = require("../../util");
var dataflow_1 = require("./dataflow");
var NonPositiveFilterNode = /** @class */ (function (_super) {
tslib_1.__extends(NonPositiveFilterNode, _super);
function NonPositiveFilterNode(filter) {
var _this = _super.call(this) || this;
_this._filter = filter;
return _this;
}
NonPositiveFilterNode.prototype.clone = function () {
return new NonPositiveFilterNode(tslib_1.__assign({}, this._filter));
};
NonPositiveFilterNode.make = function (model) {
var filter = channel_1.SCALE_CHANNELS.reduce(function (nonPositiveComponent, channel) {
var scale = model.getScaleComponent(channel);
if (!scale || !model.field(channel)) {
// don't set anything
return nonPositiveComponent;
}
nonPositiveComponent[model.field(channel)] = scale.get('type') === scale_1.ScaleType.LOG;
return nonPositiveComponent;
}, {});
if (!util_1.keys(filter).length) {
return null;
}
return new NonPositiveFilterNode(filter);
};
Object.defineProperty(NonPositiveFilterNode.prototype, "filter", {
get: function () {
return this._filter;
},
enumerable: true,
configurable: true
});
NonPositiveFilterNode.prototype.assemble = function () {
var _this = this;
return util_1.keys(this._filter).filter(function (field) {
// Only filter fields (keys) with value = true
return _this._filter[field];
}).map(function (field) {
return {
type: 'filter',
expr: "datum[" + util_1.stringValue(field) + "] > 0"
};
});
};
return NonPositiveFilterNode;
}(dataflow_1.DataFlowNode));
exports.NonPositiveFilterNode = NonPositiveFilterNode;
},{"../../channel":12,"../../scale":104,"../../util":114,"./dataflow":27,"tslib":5}],34:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var channel_1 = require("../../channel");
var scale_1 = require("../../scale");
var type_1 = require("../../type");
var util_1 = require("../../util");
var dataflow_1 = require("./dataflow");
var NullFilterNode = /** @class */ (function (_super) {
tslib_1.__extends(NullFilterNode, _super);
function NullFilterNode(fields) {
var _this = _super.call(this) || this;
_this._filteredFields = fields;
return _this;
}
NullFilterNode.prototype.clone = function () {
return new NullFilterNode(util_1.duplicate(this._filteredFields));
};
NullFilterNode.make = function (model) {
var fields = model.reduceFieldDef(function (aggregator, fieldDef, channel) {
if (model.config.invalidValues === 'filter' && !fieldDef.aggregate && fieldDef.field) {
// Vega's aggregate operator already handle invalid values, so we only have to consider non-aggregate field here.
var scaleComponent = channel_1.isScaleChannel(channel) && model.getScaleComponent(channel);
if (scaleComponent) {
var scaleType = scaleComponent.get('type');
// only automatically filter null for continuous domain since discrete domain scales can handle invalid values.
if (scale_1.hasContinuousDomain(scaleType)) {
aggregator[fieldDef.field] = fieldDef;
}
}
}
return aggregator;
}, {});
if (util_1.keys(fields).length === 0) {
return null;
}
return new NullFilterNode(fields);
};
Object.defineProperty(NullFilterNode.prototype, "filteredFields", {
get: function () {
return this._filteredFields;
},
enumerable: true,
configurable: true
});
NullFilterNode.prototype.merge = function (other) {
var _this = this;
var t = util_1.keys(this._filteredFields).map(function (k) { return k + ' ' + util_1.hash(_this._filteredFields[k]); });
var o = util_1.keys(other.filteredFields).map(function (k) { return k + ' ' + util_1.hash(other.filteredFields[k]); });
if (!util_1.differArray(t, o)) {
this._filteredFields = tslib_1.__assign({}, this._filteredFields, other._filteredFields);
other.remove();
}
};
NullFilterNode.prototype.assemble = function () {
var _this = this;
var filters = util_1.keys(this._filteredFields).reduce(function (_filters, field) {
var fieldDef = _this._filteredFields[field];
if (fieldDef !== null) {
_filters.push("datum[" + util_1.stringValue(fieldDef.field) + "] !== null");
if (util_1.contains([type_1.QUANTITATIVE, type_1.TEMPORAL], fieldDef.type)) {
// TODO(https://github.com/vega/vega-lite/issues/1436):
// We can be even smarter and add NaN filter for N,O that are numbers
// based on the `parse` property once we have it.
_filters.push("!isNaN(datum[" + util_1.stringValue(fieldDef.field) + "])");
}
}
return _filters;
}, []);
return filters.length > 0 ?
{
type: 'filter',
expr: filters.join(' && ')
} : null;
};
return NullFilterNode;
}(dataflow_1.DataFlowNode));
exports.NullFilterNode = NullFilterNode;
},{"../../channel":12,"../../scale":104,"../../type":113,"../../util":114,"./dataflow":27,"tslib":5}],35:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var data_1 = require("../../data");
var util_1 = require("../../util");
var aggregate_1 = require("./aggregate");
var dataflow_1 = require("./dataflow");
var facet_1 = require("./facet");
var nonpositivefilter_1 = require("./nonpositivefilter");
var nullfilter_1 = require("./nullfilter");
var optimizers = require("./optimizers");
var stack_1 = require("./stack");
exports.FACET_SCALE_PREFIX = 'scale_';
/**
* Clones the subtree and ignores output nodes except for the leafs, which are renamed.
*/
function cloneSubtree(facet) {
function clone(node) {
if (!(node instanceof facet_1.FacetNode)) {
var copy_1 = node.clone();
if (copy_1 instanceof dataflow_1.OutputNode) {
var newName = exports.FACET_SCALE_PREFIX + copy_1.getSource();
copy_1.setSource(newName);
facet.model.component.data.outputNodes[newName] = copy_1;
}
else if (copy_1 instanceof aggregate_1.AggregateNode || copy_1 instanceof stack_1.StackNode) {
copy_1.addDimensions(facet.fields);
}
util_1.flatten(node.children.map(clone)).forEach(function (n) { return n.parent = copy_1; });
return [copy_1];
}
return util_1.flatten(node.children.map(clone));
}
return clone;
}
/**
* Move facet nodes down to the next fork or output node. Also pull the main output with the facet node.
* After moving down the facet node, make a copy of the subtree and make it a child of the main output.
*/
function moveFacetDown(node) {
if (node instanceof facet_1.FacetNode) {
if (node.numChildren() === 1 && !(node.children[0] instanceof dataflow_1.OutputNode)) {
// move down until we hit a fork or output node
var child = node.children[0];
if (child instanceof aggregate_1.AggregateNode || child instanceof stack_1.StackNode) {
child.addDimensions(node.fields);
}
child.swapWithParent();
moveFacetDown(node);
}
else {
// move main to facet
moveMainDownToFacet(node.model.component.data.main);
// replicate the subtree and place it before the facet's main node
var copy = util_1.flatten(node.children.map(cloneSubtree(node)));
copy.forEach(function (c) { return c.parent = node.model.component.data.main; });
}
}
else {
node.children.forEach(moveFacetDown);
}
}
function moveMainDownToFacet(node) {
if (node instanceof dataflow_1.OutputNode && node.type === data_1.MAIN) {
if (node.numChildren() === 1) {
var child = node.children[0];
if (!(child instanceof facet_1.FacetNode)) {
child.swapWithParent();
moveMainDownToFacet(node);
}
}
}
}
/**
* Start optimization path from the root. Useful for removing nodes.
*/
function removeUnnecessaryNodes(node) {
// remove empty non positive filter
if (node instanceof nonpositivefilter_1.NonPositiveFilterNode && util_1.every(util_1.vals(node.filter), function (b) { return b === false; })) {
node.remove();
}
// remove empty null filter nodes
if (node instanceof nullfilter_1.NullFilterNode && util_1.every(util_1.vals(node.filteredFields), function (f) { return f === null; })) {
node.remove();
}
// remove output nodes that are not required
if (node instanceof dataflow_1.OutputNode && !node.isRequired()) {
node.remove();
}
node.children.forEach(removeUnnecessaryNodes);
}
/**
* Return all leaf nodes.
*/
function getLeaves(roots) {
var leaves = [];
function append(node) {
if (node.numChildren() === 0) {
leaves.push(node);
}
else {
node.children.forEach(append);
}
}
roots.forEach(append);
return leaves;
}
/**
* Optimizes the dataflow of the passed in data component.
*/
function optimizeDataflow(dataComponent) {
var roots = util_1.vals(dataComponent.sources);
roots.forEach(removeUnnecessaryNodes);
// remove source nodes that don't have any children because they also don't have output nodes
roots = roots.filter(function (r) { return r.numChildren() > 0; });
getLeaves(roots).forEach(optimizers.iterateFromLeaves(optimizers.removeUnusedSubtrees));
roots = roots.filter(function (r) { return r.numChildren() > 0; });
getLeaves(roots).forEach(optimizers.iterateFromLeaves(optimizers.moveParseUp));
getLeaves(roots).forEach(optimizers.removeDuplicateTimeUnits);
roots.forEach(moveFacetDown);
util_1.keys(dataComponent.sources).forEach(function (s) {
if (dataComponent.sources[s].numChildren() === 0) {
delete dataComponent.sources[s];
}
});
}
exports.optimizeDataflow = optimizeDataflow;
},{"../../data":92,"../../util":114,"./aggregate":23,"./dataflow":27,"./facet":28,"./nonpositivefilter":33,"./nullfilter":34,"./optimizers":36,"./stack":39}],36:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var util_1 = require("../../util");
var dataflow_1 = require("./dataflow");
var formatparse_1 = require("./formatparse");
var source_1 = require("./source");
var timeunit_1 = require("./timeunit");
/**
* Start optimization path at the leaves. Useful for merging up or removing things.
*
* If the callback returns true, the recursion continues.
*/
function iterateFromLeaves(f) {
function optimizeNextFromLeaves(node) {
if (node instanceof source_1.SourceNode) {
return;
}
var next = node.parent;
if (f(node)) {
optimizeNextFromLeaves(next);
}
}
return optimizeNextFromLeaves;
}
exports.iterateFromLeaves = iterateFromLeaves;
/**
* Move parse nodes up to forks.
*/
function moveParseUp(node) {
var parent = node.parent;
// move parse up by merging or swapping
if (node instanceof formatparse_1.ParseNode) {
if (parent instanceof source_1.SourceNode) {
return false;
}
if (parent.numChildren() > 1) {
// don't move parse further up but continue with parent.
return true;
}
if (parent instanceof formatparse_1.ParseNode) {
parent.merge(node);
}
else {
// don't swap with nodes that produce something that the parse node depends on (e.g. lookup)
if (util_1.hasIntersection(parent.producedFields(), node.dependentFields())) {
return true;
}
node.swapWithParent();
}
}
return true;
}
exports.moveParseUp = moveParseUp;
/**
* Repeatedly remove leaf nodes that are not output nodes.
* The reason is that we don't need subtrees that don't have any output nodes.
*/
function removeUnusedSubtrees(node) {
if (node instanceof dataflow_1.OutputNode || node.numChildren() > 0) {
// no need to continue with parent because it is output node or will have children (there was a fork)
return false;
}
else {
node.remove();
}
return true;
}
exports.removeUnusedSubtrees = removeUnusedSubtrees;
/**
* Removes duplicate time unit nodes (as determined by the name of the
* output field) that may be generated due to selections projected over
* time units.
*/
function removeDuplicateTimeUnits(leaf) {
var fields = {};
return iterateFromLeaves(function (node) {
if (node instanceof timeunit_1.TimeUnitNode) {
var pfields = node.producedFields();
var dupe = util_1.keys(pfields).every(function (k) { return !!fields[k]; });
if (dupe) {
node.remove();
}
else {
fields = tslib_1.__assign({}, fields, pfields);
}
}
return true;
})(leaf);
}
exports.removeDuplicateTimeUnits = removeDuplicateTimeUnits;
},{"../../util":114,"./dataflow":27,"./formatparse":30,"./source":38,"./timeunit":40,"tslib":5}],37:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var vega_util_1 = require("vega-util");
var data_1 = require("../../data");
var datetime_1 = require("../../datetime");
var filter_1 = require("../../filter");
var log = require("../../log");
var transform_1 = require("../../transform");
var util_1 = require("../../util");
var model_1 = require("../model");
var selection_1 = require("../selection/selection");
var aggregate_1 = require("./aggregate");
var bin_1 = require("./bin");
var calculate_1 = require("./calculate");
var dataflow_1 = require("./dataflow");
var facet_1 = require("./facet");
var filter_2 = require("./filter");
var formatparse_1 = require("./formatparse");
var indentifier_1 = require("./indentifier");
var lookup_1 = require("./lookup");
var nonpositivefilter_1 = require("./nonpositivefilter");
var nullfilter_1 = require("./nullfilter");
var source_1 = require("./source");
var stack_1 = require("./stack");
var timeunit_1 = require("./timeunit");
function parseRoot(model, sources) {
if (model.data || !model.parent) {
// if the model defines a data source or is the root, create a source node
var source = new source_1.SourceNode(model.data);
var hash = source.hash();
if (hash in sources) {
// use a reference if we already have a source
return sources[hash];
}
else {
// otherwise add a new one
sources[hash] = source;
return source;
}
}
else {
// If we don't have a source defined (overriding parent's data), use the parent's facet root or main.
return model.parent.component.data.facetRoot ? model.parent.component.data.facetRoot : model.parent.component.data.main;
}
}
/**
* Parses a transforms array into a chain of connected dataflow nodes.
*/
function parseTransformArray(model) {
var first = null;
var node;
var previous;
var lookupCounter = 0;
function insert(newNode) {
if (!first) {
// A parent may be inserted during node construction
// (e.g., selection FilterNodes may add a TimeUnitNode).
first = newNode.parent || newNode;
}
else if (newNode.parent) {
previous.insertAsParentOf(newNode);
}
else {
newNode.parent = previous;
}
previous = newNode;
}
model.transforms.forEach(function (t) {
if (transform_1.isCalculate(t)) {
node = new calculate_1.CalculateNode(t);
}
else if (transform_1.isFilter(t)) {
// Automatically add a parse node for filters with filter objects
var parse = {};
var filter = t.filter;
var val = null;
// For EqualFilter, just use the equal property.
// For RangeFilter and OneOfFilter, all array members should have
// the same type, so we only use the first one.
if (filter_1.isEqualFilter(filter)) {
val = filter.equal;
}
else if (filter_1.isRangeFilter(filter)) {
val = filter.range[0];
}
else if (filter_1.isOneOfFilter(filter)) {
val = (filter.oneOf || filter['in'])[0];
} // else -- for filter expression, we can't infer anything
if (val) {
if (datetime_1.isDateTime(val)) {
parse[filter['field']] = 'date';
}
else if (vega_util_1.isNumber(val)) {
parse[filter['field']] = 'number';
}
else if (vega_util_1.isString(val)) {
parse[filter['field']] = 'string';
}
}
if (util_1.keys(parse).length > 0) {
var parseNode = new formatparse_1.ParseNode(parse);
insert(parseNode);
}
node = new filter_2.FilterNode(model, t.filter);
}
else if (transform_1.isBin(t)) {
node = bin_1.BinNode.makeFromTransform(t, { model: model });
}
else if (transform_1.isTimeUnit(t)) {
node = timeunit_1.TimeUnitNode.makeFromTransform(t);
}
else if (transform_1.isSummarize(t)) {
node = aggregate_1.AggregateNode.makeFromTransform(t);
if (selection_1.requiresSelectionId(model)) {
insert(node);
node = new indentifier_1.IdentifierNode();
}
}
else if (transform_1.isLookup(t)) {
node = lookup_1.LookupNode.make(model, t, lookupCounter++);
}
else {
log.warn(log.message.invalidTransformIgnored(t));
return;
}
insert(node);
});
var last = node;
return { first: first, last: last };
}
exports.parseTransformArray = parseTransformArray;
/*
Description of the dataflow (http://asciiflow.com/):
+--------+
| Source |
+---+----+
|
v
Transforms
(Filter, Calculate, ...)
|
v
FormatParse
|
v
Null Filter
|
v
Binning
|
v
Timeunit
|
v
+--+--+
| Raw |
+-----+
|
v
Aggregate
|
v
Stack
|
v
>0 Filter
|
v
Path Order
|
v
+----------+
| Main |
+----------+
|
v
+-------+
| Facet |----> "column", "column-layout", and "row"
+-------+
|
v
...Child data...
*/
function parseData(model) {
var root = parseRoot(model, model.component.data.sources);
var outputNodes = model.component.data.outputNodes;
var outputNodeRefCounts = model.component.data.outputNodeRefCounts;
// the current head of the tree that we are appending to
var head = root;
// Default discrete selections require an identifier transform to
// uniquely identify data points as the _id field is volatile. Add
// this transform at the head of our pipeline such that the identifier
// field is available for all subsequent datasets. Additional identifier
// transforms will be necessary when new tuples are constructed
// (e.g., post-aggregation).
if (selection_1.requiresSelectionId(model) && !model.parent) {
var ident = new indentifier_1.IdentifierNode();
ident.parent = head;
head = ident;
}
// HACK: This is equivalent for merging bin extent for union scale.
// FIXME(https://github.com/vega/vega-lite/issues/2270): Correctly merge extent / bin node for shared bin scale
var parentIsLayer = model.parent && model_1.isLayerModel(model.parent);
if (model_1.isUnitModel(model) || model_1.isFacetModel(model)) {
if (parentIsLayer) {
var bin = bin_1.BinNode.makeBinFromEncoding(model);
if (bin) {
bin.parent = head;
head = bin;
}
}
}
if (model.transforms.length > 0) {
var _a = parseTransformArray(model), first = _a.first, last = _a.last;
first.parent = head;
head = last;
}
var parse = formatparse_1.ParseNode.make(model);
if (parse) {
parse.parent = head;
head = parse;
}
if (model_1.isUnitModel(model) || model_1.isFacetModel(model)) {
var nullFilter = nullfilter_1.NullFilterNode.make(model);
if (nullFilter) {
nullFilter.parent = head;
head = nullFilter;
}
if (!parentIsLayer) {
var bin = bin_1.BinNode.makeBinFromEncoding(model);
if (bin) {
bin.parent = head;
head = bin;
}
}
var tu = timeunit_1.TimeUnitNode.makeFromEncoding(model);
if (tu) {
tu.parent = head;
head = tu;
}
}
// add an output node pre aggregation
var rawName = model.getName(data_1.RAW);
var raw = new dataflow_1.OutputNode(rawName, data_1.RAW, outputNodeRefCounts);
outputNodes[rawName] = raw;
raw.parent = head;
head = raw;
if (model_1.isUnitModel(model)) {
var agg = aggregate_1.AggregateNode.makeFromEncoding(model);
if (agg) {
agg.parent = head;
head = agg;
if (selection_1.requiresSelectionId(model)) {
var ident = new indentifier_1.IdentifierNode();
ident.parent = head;
head = ident;
}
}
var stack = stack_1.StackNode.make(model);
if (stack) {
stack.parent = head;
head = stack;
}
var nonPosFilter = nonpositivefilter_1.NonPositiveFilterNode.make(model);
if (nonPosFilter) {
nonPosFilter.parent = head;
head = nonPosFilter;
}
}
// output node for marks
var mainName = model.getName(data_1.MAIN);
var main = new dataflow_1.OutputNode(mainName, data_1.MAIN, outputNodeRefCounts);
outputNodes[mainName] = main;
main.parent = head;
head = main;
// add facet marker
var facetRoot = null;
if (model_1.isFacetModel(model)) {
var facetName = model.getName('facet');
facetRoot = new facet_1.FacetNode(model, facetName, main.getSource());
outputNodes[facetName] = facetRoot;
facetRoot.parent = head;
head = facetRoot;
}
// add the format parse from this model so that children don't parse the same field again
var ancestorParse = tslib_1.__assign({}, model.component.data.ancestorParse, (parse ? parse.parse : {}));
return tslib_1.__assign({}, model.component.data, { outputNodes: outputNodes,
outputNodeRefCounts: outputNodeRefCounts,
raw: raw,
main: main,
facetRoot: facetRoot,
ancestorParse: ancestorParse });
}
exports.parseData = parseData;
},{"../../data":92,"../../datetime":93,"../../filter":97,"../../log":101,"../../transform":112,"../../util":114,"../model":63,"../selection/selection":76,"./aggregate":23,"./bin":25,"./calculate":26,"./dataflow":27,"./facet":28,"./filter":29,"./formatparse":30,"./indentifier":31,"./lookup":32,"./nonpositivefilter":33,"./nullfilter":34,"./source":38,"./stack":39,"./timeunit":40,"tslib":5,"vega-util":7}],38:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var data_1 = require("../../data");
var util_1 = require("../../util");
var dataflow_1 = require("./dataflow");
var counter = 0;
var SourceNode = /** @class */ (function (_super) {
tslib_1.__extends(SourceNode, _super);
function SourceNode(data) {
var _this = _super.call(this) || this;
_this._id = counter++;
data = data || { name: 'source' };
if (data_1.isInlineData(data)) {
_this._data = { values: data.values };
}
else if (data_1.isUrlData(data)) {
_this._data = { url: data.url };
if (!data.format) {
data.format = {};
}
if (!data.format || !data.format.type) {
// Extract extension from URL using snippet from
// http://stackoverflow.com/questions/680929/how-to-extract-extension-from-filename-string-in-javascript
var defaultExtension = /(?:\.([^.]+))?$/.exec(data.url)[1];
if (!util_1.contains(['json', 'csv', 'tsv', 'topojson'], defaultExtension)) {
defaultExtension = 'json';
}
// defaultExtension has type string but we ensure that it is DataFormatType above
data.format.type = defaultExtension;
}
}
else if (data_1.isNamedData(data)) {
_this._name = data.name;
_this._data = {};
}
if (!data_1.isNamedData(data)) {
var _a = tslib_1.__assign({
// https://github.com/vega/vega-parser/pull/60
type: 'json' }, data.format || {}), _b = _a.parse, parse = _b === void 0 ? null : _b, format = tslib_1.__rest(_a, ["parse"]);
_this._data.format = format;
}
return _this;
}
Object.defineProperty(SourceNode.prototype, "data", {
get: function () {
return this._data;
},
enumerable: true,
configurable: true
});
SourceNode.prototype.hasName = function () {
return !!this._name;
};
Object.defineProperty(SourceNode.prototype, "dataName", {
get: function () {
return this._name;
},
set: function (name) {
this._name = name;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SourceNode.prototype, "parent", {
set: function (parent) {
throw new Error('Source nodes have to be roots.');
},
enumerable: true,
configurable: true
});
SourceNode.prototype.remove = function () {
throw new Error('Source nodes are roots and cannot be removed.');
};
/**
* Return a unique identifier for this data source.
*/
SourceNode.prototype.hash = function () {
if (data_1.isInlineData(this._data)) {
// We want to avoid hashes of very large dataset. We will not merge large embedded datasets.
if (this._data.values.length > 1000) {
return util_1.hash([this._data.format, this._id]);
}
return util_1.hash(this._data);
}
else if (data_1.isUrlData(this._data)) {
return util_1.hash([this._data.url, this._data.format]);
}
else {
return this._name;
}
};
SourceNode.prototype.assemble = function () {
return tslib_1.__assign({ name: this._name }, this._data, { transform: [] });
};
return SourceNode;
}(dataflow_1.DataFlowNode));
exports.SourceNode = SourceNode;
},{"../../data":92,"../../util":114,"./dataflow":27,"tslib":5}],39:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var vega_util_1 = require("vega-util");
var fielddef_1 = require("../../fielddef");
var util_1 = require("../../util");
var common_1 = require("../common");
var dataflow_1 = require("./dataflow");
function getStackByFields(model) {
return model.stack.stackBy.reduce(function (fields, by) {
var fieldDef = by.fieldDef;
var _field = fielddef_1.field(fieldDef);
if (_field) {
fields.push(_field);
}
return fields;
}, []);
}
var StackNode = /** @class */ (function (_super) {
tslib_1.__extends(StackNode, _super);
function StackNode(stack) {
var _this = _super.call(this) || this;
_this._stack = stack;
return _this;
}
StackNode.prototype.clone = function () {
return new StackNode(util_1.duplicate(this._stack));
};
StackNode.make = function (model) {
var stackProperties = model.stack;
if (!stackProperties) {
return null;
}
var dimensionFieldDef;
if (stackProperties.groupbyChannel) {
dimensionFieldDef = model.fieldDef(stackProperties.groupbyChannel);
}
var stackby = getStackByFields(model);
var orderDef = model.encoding.order;
var sort;
if (orderDef) {
sort = common_1.sortParams(orderDef);
}
else {
// default = descending by stackFields
// FIXME is the default here correct for binned fields?
sort = stackby.reduce(function (s, field) {
s.field.push(field);
s.order.push('descending');
return s;
}, { field: [], order: [] });
}
return new StackNode({
dimensionFieldDef: dimensionFieldDef,
field: model.field(stackProperties.fieldChannel),
facetby: [],
stackby: stackby,
sort: sort,
offset: stackProperties.offset,
impute: stackProperties.impute,
});
};
Object.defineProperty(StackNode.prototype, "stack", {
get: function () {
return this._stack;
},
enumerable: true,
configurable: true
});
StackNode.prototype.addDimensions = function (fields) {
this._stack.facetby = this._stack.facetby.concat(fields);
};
StackNode.prototype.dependentFields = function () {
var out = {};
out[this._stack.field] = true;
this.getGroupbyFields().forEach(function (f) { return out[f] = true; });
this._stack.facetby.forEach(function (f) { return out[f] = true; });
var field = this._stack.sort.field;
vega_util_1.isArray(field) ? field.forEach(function (f) { return out[f] = true; }) : out[field] = true;
return out;
};
StackNode.prototype.producedFields = function () {
var out = {};
out[this._stack.field + '_start'] = true;
out[this._stack.field + '_end'] = true;
return out;
};
StackNode.prototype.getGroupbyFields = function () {
var _a = this._stack, dimensionFieldDef = _a.dimensionFieldDef, impute = _a.impute;
if (dimensionFieldDef) {
if (dimensionFieldDef.bin) {
if (impute) {
// For binned group by field with impute, we calculate bin_mid
// as we cannot impute two fields simultaneously
return [fielddef_1.field(dimensionFieldDef, { binSuffix: 'mid' })];
}
return [
// For binned group by field without impute, we need both bin (start) and bin_end
fielddef_1.field(dimensionFieldDef, {}),
fielddef_1.field(dimensionFieldDef, { binSuffix: 'end' })
];
}
return [fielddef_1.field(dimensionFieldDef)];
}
return [];
};
StackNode.prototype.assemble = function () {
var transform = [];
var _a = this._stack, facetby = _a.facetby, stackField = _a.field, dimensionFieldDef = _a.dimensionFieldDef, impute = _a.impute, offset = _a.offset, sort = _a.sort, stackby = _a.stackby;
// Impute
if (impute && dimensionFieldDef) {
var dimensionField = dimensionFieldDef ? fielddef_1.field(dimensionFieldDef, { binSuffix: 'mid' }) : undefined;
if (dimensionFieldDef.bin) {
// As we can only impute one field at a time, we need to calculate
// mid point for a binned field
transform.push({
type: 'formula',
expr: '(' +
fielddef_1.field(dimensionFieldDef, { expr: 'datum' }) +
'+' +
fielddef_1.field(dimensionFieldDef, { expr: 'datum', binSuffix: 'end' }) +
')/2',
as: dimensionField
});
}
transform.push({
type: 'impute',
field: stackField,
groupby: stackby,
key: dimensionField,
method: 'value',
value: 0
});
}
// Stack
transform.push({
type: 'stack',
groupby: this.getGroupbyFields().concat(facetby),
field: stackField,
sort: sort,
as: [
stackField + '_start',
stackField + '_end'
],
offset: offset
});
return transform;
};
return StackNode;
}(dataflow_1.DataFlowNode));
exports.StackNode = StackNode;
},{"../../fielddef":96,"../../util":114,"../common":20,"./dataflow":27,"tslib":5,"vega-util":7}],40:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var fielddef_1 = require("../../fielddef");
var timeunit_1 = require("../../timeunit");
var util_1 = require("../../util");
var dataflow_1 = require("./dataflow");
var TimeUnitNode = /** @class */ (function (_super) {
tslib_1.__extends(TimeUnitNode, _super);
function TimeUnitNode(formula) {
var _this = _super.call(this) || this;
_this.formula = formula;
return _this;
}
TimeUnitNode.prototype.clone = function () {
return new TimeUnitNode(util_1.duplicate(this.formula));
};
TimeUnitNode.makeFromEncoding = function (model) {
var formula = model.reduceFieldDef(function (timeUnitComponent, fieldDef) {
if (fieldDef.timeUnit) {
var f = fielddef_1.field(fieldDef);
timeUnitComponent[f] = {
as: f,
timeUnit: fieldDef.timeUnit,
field: fieldDef.field
};
}
return timeUnitComponent;
}, {});
if (util_1.keys(formula).length === 0) {
return null;
}
return new TimeUnitNode(formula);
};
TimeUnitNode.makeFromTransform = function (t) {
return new TimeUnitNode((_a = {},
_a[t.field] = {
as: t.as,
timeUnit: t.timeUnit,
field: t.field
},
_a));
var _a;
};
TimeUnitNode.prototype.merge = function (other) {
this.formula = tslib_1.__assign({}, this.formula, other.formula);
other.remove();
};
TimeUnitNode.prototype.producedFields = function () {
var out = {};
util_1.vals(this.formula).forEach(function (f) {
out[f.as] = true;
});
return out;
};
TimeUnitNode.prototype.dependentFields = function () {
var out = {};
util_1.vals(this.formula).forEach(function (f) {
out[f.field] = true;
});
return out;
};
TimeUnitNode.prototype.assemble = function () {
return util_1.vals(this.formula).map(function (c) {
return {
type: 'formula',
as: c.as,
expr: timeunit_1.fieldExpr(c.timeUnit, c.field)
};
});
};
return TimeUnitNode;
}(dataflow_1.DataFlowNode));
exports.TimeUnitNode = TimeUnitNode;
},{"../../fielddef":96,"../../timeunit":109,"../../util":114,"./dataflow":27,"tslib":5}],41:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var channel_1 = require("../channel");
var encoding_1 = require("../encoding");
var fielddef_1 = require("../fielddef");
var log = require("../log");
var scale_1 = require("../scale");
var util_1 = require("../util");
var vega_schema_1 = require("../vega.schema");
var buildmodel_1 = require("./buildmodel");
var assemble_1 = require("./data/assemble");
var parse_1 = require("./data/parse");
var header_1 = require("./layout/header");
var parse_2 = require("./layoutsize/parse");
var model_1 = require("./model");
var repeater_1 = require("./repeater");
var resolve_1 = require("./resolve");
var domain_1 = require("./scale/domain");
var FacetModel = /** @class */ (function (_super) {
tslib_1.__extends(FacetModel, _super);
function FacetModel(spec, parent, parentGivenName, repeater, config) {
var _this = _super.call(this, spec, parent, parentGivenName, config, spec.resolve) || this;
_this.type = 'facet';
_this.child = buildmodel_1.buildModel(spec.spec, _this, _this.getName('child'), undefined, repeater, config);
_this.children = [_this.child];
var facet = repeater_1.replaceRepeaterInFacet(spec.facet, repeater);
_this.facet = _this.initFacet(facet);
return _this;
}
FacetModel.prototype.initFacet = function (facet) {
// clone to prevent side effect to the original spec
return encoding_1.reduce(facet, function (normalizedFacet, fieldDef, channel) {
if (!util_1.contains([channel_1.ROW, channel_1.COLUMN], channel)) {
// Drop unsupported channel
log.warn(log.message.incompatibleChannel(channel, 'facet'));
return normalizedFacet;
}
if (fieldDef.field === undefined) {
log.warn(log.message.emptyFieldDef(fieldDef, channel));
return normalizedFacet;
}
// Convert type to full, lowercase type, or augment the fieldDef with a default type if missing.
normalizedFacet[channel] = fielddef_1.normalize(fieldDef, channel);
return normalizedFacet;
}, {});
};
FacetModel.prototype.channelHasField = function (channel) {
return !!this.facet[channel];
};
FacetModel.prototype.fieldDef = function (channel) {
return this.facet[channel];
};
FacetModel.prototype.parseData = function () {
this.component.data = parse_1.parseData(this);
this.child.parseData();
};
FacetModel.prototype.parseLayoutSize = function () {
parse_2.parseChildrenLayoutSize(this);
};
FacetModel.prototype.parseSelection = function () {
// As a facet has a single child, the selection components are the same.
// The child maintains its selections to assemble signals, which remain
// within its unit.
this.child.parseSelection();
this.component.selection = this.child.component.selection;
};
FacetModel.prototype.parseMarkGroup = function () {
this.child.parseMarkGroup();
};
FacetModel.prototype.parseAxisAndHeader = function () {
this.child.parseAxisAndHeader();
this.parseHeader('column');
this.parseHeader('row');
this.mergeChildAxis('x');
this.mergeChildAxis('y');
};
FacetModel.prototype.parseHeader = function (channel) {
if (this.channelHasField(channel)) {
var fieldDef = this.facet[channel];
var header = fieldDef.header || {};
var title = header.title !== undefined ? header.title : fielddef_1.title(fieldDef, this.config);
if (this.child.component.layoutHeaders[channel].title) {
// merge title with child to produce "Title / Subtitle / Sub-subtitle"
title += ' / ' + this.child.component.layoutHeaders[channel].title;
this.child.component.layoutHeaders[channel].title = null;
}
this.component.layoutHeaders[channel] = {
title: title,
facetFieldDef: fieldDef,
// TODO: support adding label to footer as well
header: [this.makeHeaderComponent(channel, true)]
};
}
};
FacetModel.prototype.makeHeaderComponent = function (channel, labels) {
var sizeType = channel === 'row' ? 'height' : 'width';
return {
labels: labels,
sizeSignal: this.child.component.layoutSize.get(sizeType) ? this.child.getSizeSignalRef(sizeType) : undefined,
axes: []
};
};
FacetModel.prototype.mergeChildAxis = function (channel) {
var child = this.child;
if (child.component.axes[channel]) {
var _a = this.component, layoutHeaders = _a.layoutHeaders, resolve = _a.resolve;
resolve.axis[channel] = resolve_1.parseGuideResolve(resolve, channel);
if (resolve.axis[channel] === 'shared') {
// For shared axis, move the axes to facet's header or footer
var headerChannel = channel === 'x' ? 'column' : 'row';
var layoutHeader = layoutHeaders[headerChannel];
for (var _i = 0, _b = child.component.axes[channel]; _i < _b.length; _i++) {
var axisComponent = _b[_i];
var mainAxis = axisComponent.main;
var headerType = header_1.getHeaderType(mainAxis.get('orient'));
layoutHeader[headerType] = layoutHeader[headerType] ||
[this.makeHeaderComponent(headerChannel, false)];
// LayoutHeader no longer keep track of property precedence, thus let's combine.
layoutHeader[headerType][0].axes.push(mainAxis.combine());
delete axisComponent.main;
}
}
else {
// Otherwise do nothing for independent axes
}
}
};
FacetModel.prototype.assembleSelectionTopLevelSignals = function (signals) {
return this.child.assembleSelectionTopLevelSignals(signals);
};
FacetModel.prototype.assembleSelectionSignals = function () {
this.child.assembleSelectionSignals();
return [];
};
FacetModel.prototype.assembleSelectionData = function (data) {
return this.child.assembleSelectionData(data);
};
FacetModel.prototype.getLayoutBandMixins = function (headerType) {
var bandMixins = {};
var bandType = headerType === 'header' ? 'headerBand' : 'footerBand';
for (var _i = 0, _a = ['row', 'column']; _i < _a.length; _i++) {
var channel = _a[_i];
var layoutHeaderComponent = this.component.layoutHeaders[channel];
var headerComponent = layoutHeaderComponent[headerType];
if (headerComponent && headerComponent[0]) {
var sizeType = channel === 'row' ? 'height' : 'width';
if (!this.child.component.layoutSize.get(sizeType)) {
// If facet child does not have size signal, then apply headerBand
bandMixins[bandType] = bandMixins[bandType] || {};
bandMixins[bandType][channel] = 0.5;
}
}
}
return bandMixins;
};
FacetModel.prototype.assembleLayout = function () {
var columns = this.channelHasField('column') ? this.columnDistinctSignal() : 1;
// TODO: determine default align based on shared / independent scales
return tslib_1.__assign({ padding: { row: 10, column: 10 } }, this.getLayoutBandMixins('header'), this.getLayoutBandMixins('footer'), {
// TODO: support offset for rowHeader/rowFooter/rowTitle/columnHeader/columnFooter/columnTitle
offset: 10, columns: columns, bounds: 'full', align: 'all' });
};
FacetModel.prototype.assembleLayoutSignals = function () {
// FIXME(https://github.com/vega/vega-lite/issues/1193): this can be incorrect if we have independent scales.
return this.child.assembleLayoutSignals();
};
FacetModel.prototype.columnDistinctSignal = function () {
if (this.parent && (this.parent instanceof FacetModel)) {
// For nested facet, we will add columns to group mark instead
// See discussion in https://github.com/vega/vega/issues/952
// and https://github.com/vega/vega-view/releases/tag/v1.2.6
return undefined;
}
else {
// In facetNode.assemble(), the name is always this.getName('column') + '_layout'.
var facetLayoutDataName = this.getName('column_domain');
return { signal: "length(data('" + facetLayoutDataName + "'))" };
}
};
FacetModel.prototype.assembleGroup = function (signals) {
if (this.parent && (this.parent instanceof FacetModel)) {
// Provide number of columns for layout.
// See discussion in https://github.com/vega/vega/issues/952
// and https://github.com/vega/vega-view/releases/tag/v1.2.6
return tslib_1.__assign({}, (this.channelHasField('column') ? {
encode: {
update: {
// TODO(https://github.com/vega/vega-lite/issues/2759):
// Correct the signal for facet of concat of facet_column
columns: { field: fielddef_1.field(this.facet.column, { prefix: 'distinct' }) }
}
}
} : {}), _super.prototype.assembleGroup.call(this, signals));
}
return _super.prototype.assembleGroup.call(this, signals);
};
/**
* Aggregate cardinality for calculating size
*/
FacetModel.prototype.getCardinalityAggregateForChild = function () {
var fields = [];
var ops = [];
if (this.child instanceof FacetModel) {
if (this.child.channelHasField('column')) {
fields.push(fielddef_1.field(this.child.facet.column));
ops.push('distinct');
}
}
else {
for (var _i = 0, _a = ['x', 'y']; _i < _a.length; _i++) {
var channel = _a[_i];
var childScaleComponent = this.child.component.scales[channel];
if (childScaleComponent && !childScaleComponent.merged) {
var type = childScaleComponent.get('type');
var range = childScaleComponent.get('range');
if (scale_1.hasDiscreteDomain(type) && vega_schema_1.isVgRangeStep(range)) {
var domain = domain_1.assembleDomain(this.child, channel);
var field_1 = domain_1.getFieldFromDomain(domain);
if (field_1) {
fields.push(field_1);
ops.push('distinct');
}
else {
log.warn('Unknown field for ${channel}. Cannot calculate view size.');
}
}
}
}
}
return fields.length ? { fields: fields, ops: ops } : undefined;
};
FacetModel.prototype.assembleMarks = function () {
var _a = this, child = _a.child, facet = _a.facet;
var facetRoot = this.component.data.facetRoot;
var data = assemble_1.assembleFacetData(facetRoot);
// If we facet by two dimensions, we need to add a cross operator to the aggregation
// so that we create all groups
var hasRow = this.channelHasField(channel_1.ROW);
var hasColumn = this.channelHasField(channel_1.COLUMN);
var layoutSizeEncodeEntry = child.assembleLayoutSize();
var aggregateMixins = {};
if (hasRow && hasColumn) {
aggregateMixins.aggregate = { cross: true };
}
var cardinalityAggregateForChild = this.getCardinalityAggregateForChild();
if (cardinalityAggregateForChild) {
aggregateMixins.aggregate = tslib_1.__assign({}, aggregateMixins.aggregate, cardinalityAggregateForChild);
}
var title = child.assembleTitle();
var style = child.assembleGroupStyle();
var markGroup = tslib_1.__assign({ name: this.getName('cell'), type: 'group' }, (title ? { title: title } : {}), (style ? { style: style } : {}), { from: {
facet: tslib_1.__assign({ name: facetRoot.name, data: facetRoot.data, groupby: [].concat(hasRow ? [this.field(channel_1.ROW)] : [], hasColumn ? [this.field(channel_1.COLUMN)] : []) }, aggregateMixins)
}, sort: {
field: [].concat(hasRow ? [this.field(channel_1.ROW, { expr: 'datum', })] : [], hasColumn ? [this.field(channel_1.COLUMN, { expr: 'datum' })] : []),
order: [].concat(hasRow ? [(facet.row.sort) || 'ascending'] : [], hasColumn ? [(facet.column.sort) || 'ascending'] : [])
} }, (data.length > 0 ? { data: data } : {}), (layoutSizeEncodeEntry ? { encode: { update: layoutSizeEncodeEntry } } : {}), child.assembleGroup());
return [markGroup];
};
FacetModel.prototype.getMapping = function () {
return this.facet;
};
return FacetModel;
}(model_1.ModelWithField));
exports.FacetModel = FacetModel;
},{"../channel":12,"../encoding":94,"../fielddef":96,"../log":101,"../scale":104,"../util":114,"../vega.schema":116,"./buildmodel":19,"./data/assemble":24,"./data/parse":37,"./layout/header":43,"./layoutsize/parse":45,"./model":63,"./repeater":65,"./resolve":66,"./scale/domain":69,"tslib":5}],42:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var log = require("../log");
var spec_1 = require("../spec");
var util_1 = require("../util");
var parse_1 = require("./axis/parse");
var parse_2 = require("./data/parse");
var assemble_1 = require("./layoutsize/assemble");
var parse_3 = require("./layoutsize/parse");
var assemble_2 = require("./legend/assemble");
var model_1 = require("./model");
var selection_1 = require("./selection/selection");
var unit_1 = require("./unit");
var LayerModel = /** @class */ (function (_super) {
tslib_1.__extends(LayerModel, _super);
function LayerModel(spec, parent, parentGivenName, parentGivenSize, repeater, config) {
var _this = _super.call(this, spec, parent, parentGivenName, config, spec.resolve) || this;
_this.type = 'layer';
var layoutSize = tslib_1.__assign({}, parentGivenSize, (spec.width ? { width: spec.width } : {}), (spec.height ? { height: spec.height } : {}));
_this.initSize(layoutSize);
_this.children = spec.layer.map(function (layer, i) {
if (spec_1.isLayerSpec(layer)) {
return new LayerModel(layer, _this, _this.getName('layer_' + i), layoutSize, repeater, config);
}
if (spec_1.isUnitSpec(layer)) {
return new unit_1.UnitModel(layer, _this, _this.getName('layer_' + i), layoutSize, repeater, config);
}
throw new Error(log.message.INVALID_SPEC);
});
return _this;
}
LayerModel.prototype.parseData = function () {
this.component.data = parse_2.parseData(this);
for (var _i = 0, _a = this.children; _i < _a.length; _i++) {
var child = _a[_i];
child.parseData();
}
};
LayerModel.prototype.parseLayoutSize = function () {
parse_3.parseLayerLayoutSize(this);
};
LayerModel.prototype.parseSelection = function () {
var _this = this;
// Merge selections up the hierarchy so that they may be referenced
// across unit specs. Persist their definitions within each child
// to assemble signals which remain within output Vega unit groups.
this.component.selection = {};
var _loop_1 = function (child) {
child.parseSelection();
util_1.keys(child.component.selection).forEach(function (key) {
_this.component.selection[key] = child.component.selection[key];
});
};
for (var _i = 0, _a = this.children; _i < _a.length; _i++) {
var child = _a[_i];
_loop_1(child);
}
};
LayerModel.prototype.parseMarkGroup = function () {
for (var _i = 0, _a = this.children; _i < _a.length; _i++) {
var child = _a[_i];
child.parseMarkGroup();
}
};
LayerModel.prototype.parseAxisAndHeader = function () {
parse_1.parseLayerAxis(this);
};
LayerModel.prototype.assembleSelectionTopLevelSignals = function (signals) {
return this.children.reduce(function (sg, child) { return child.assembleSelectionTopLevelSignals(sg); }, signals);
};
// TODO: Support same named selections across children.
LayerModel.prototype.assembleSelectionSignals = function () {
return this.children.reduce(function (signals, child) {
return signals.concat(child.assembleSelectionSignals());
}, []);
};
LayerModel.prototype.assembleLayoutSignals = function () {
return this.children.reduce(function (signals, child) {
return signals.concat(child.assembleLayoutSignals());
}, assemble_1.assembleLayoutSignals(this));
};
LayerModel.prototype.assembleSelectionData = function (data) {
return this.children.reduce(function (db, child) { return child.assembleSelectionData(db); }, []);
};
LayerModel.prototype.assembleTitle = function () {
var title = _super.prototype.assembleTitle.call(this);
if (title) {
return title;
}
// If title does not provide layer, look into children
for (var _i = 0, _a = this.children; _i < _a.length; _i++) {
var child = _a[_i];
title = child.assembleTitle();
if (title) {
return title;
}
}
return undefined;
};
LayerModel.prototype.assembleLayout = function () {
return null;
};
LayerModel.prototype.assembleMarks = function () {
return selection_1.assembleLayerSelectionMarks(this, util_1.flatten(this.children.map(function (child) {
return child.assembleMarks();
})));
};
LayerModel.prototype.assembleLegends = function () {
return this.children.reduce(function (legends, child) {
return legends.concat(child.assembleLegends());
}, assemble_2.assembleLegends(this));
};
return LayerModel;
}(model_1.Model));
exports.LayerModel = LayerModel;
},{"../log":101,"../spec":107,"../util":114,"./axis/parse":16,"./data/parse":37,"./layoutsize/assemble":44,"./layoutsize/parse":45,"./legend/assemble":46,"./model":63,"./selection/selection":76,"./unit":87,"tslib":5}],43:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var fielddef_1 = require("../../fielddef");
var common_1 = require("../common");
exports.HEADER_CHANNELS = ['row', 'column'];
exports.HEADER_TYPES = ['header', 'footer'];
function getHeaderType(orient) {
if (orient === 'top' || orient === 'left') {
return 'header';
}
return 'footer';
}
exports.getHeaderType = getHeaderType;
function getTitleGroup(model, channel) {
var title = model.component.layoutHeaders[channel].title;
var textOrient = channel === 'row' ? 'vertical' : undefined;
return {
name: model.getName(channel + "_title"),
role: channel + "-title",
type: 'group',
marks: [{
type: 'text',
role: channel + "-title-text",
style: 'guide-title',
encode: {
update: tslib_1.__assign({
// TODO: add title align
align: { value: 'center' }, text: { value: title } }, (textOrient === 'vertical' ? { angle: { value: 270 } } : {}))
}
}]
};
}
exports.getTitleGroup = getTitleGroup;
function getHeaderGroup(model, channel, headerType, layoutHeader, header) {
if (header) {
var title = null;
if (layoutHeader.facetFieldDef && header.labels) {
var facetFieldDef = layoutHeader.facetFieldDef;
var format = facetFieldDef.header ? facetFieldDef.header.format : undefined;
title = {
text: common_1.formatSignalRef(facetFieldDef, format, 'parent', model.config),
offset: 10,
orient: channel === 'row' ? 'left' : 'top',
style: 'guide-label',
encode: {
update: tslib_1.__assign({ fontWeight: { value: 'normal' }, angle: { value: 0 }, fontSize: { value: 10 } }, (channel === 'row' ? {
align: { value: 'right' },
baseline: { value: 'middle' }
} : {}))
}
};
}
var axes = header.axes;
var hasAxes = axes && axes.length > 0;
if (title || hasAxes) {
var sizeChannel = channel === 'row' ? 'height' : 'width';
return tslib_1.__assign({ name: model.getName(channel + "_" + headerType), type: 'group', role: channel + "-" + headerType }, (layoutHeader.facetFieldDef ? {
from: { data: model.getName(channel + '_domain') },
sort: {
field: fielddef_1.field(layoutHeader.facetFieldDef, { expr: 'datum' }),
order: (layoutHeader.facetFieldDef.header && layoutHeader.facetFieldDef.sort) || 'ascending'
}
} : {}), (title ? { title: title } : {}), (header.sizeSignal ? {
encode: {
update: (_a = {},
_a[sizeChannel] = header.sizeSignal,
_a)
}
} : {}), (hasAxes ? { axes: axes } : {}));
}
}
return null;
var _a;
}
exports.getHeaderGroup = getHeaderGroup;
},{"../../fielddef":96,"../common":20,"tslib":5}],44:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var scale_1 = require("../../scale");
var vega_schema_1 = require("../../vega.schema");
var model_1 = require("../model");
function assembleLayoutSignals(model) {
return [].concat(sizeSignals(model, 'width'), sizeSignals(model, 'height'));
}
exports.assembleLayoutSignals = assembleLayoutSignals;
function sizeSignals(model, sizeType) {
var channel = sizeType === 'width' ? 'x' : 'y';
var size = model.component.layoutSize.get(sizeType);
if (!size || size === 'merged') {
return [];
}
// Read size signal name from name map, just in case it is the top-level size signal that got renamed.
var name = model.getSizeSignalRef(sizeType).signal;
if (size === 'range-step') {
var scaleComponent = model.getScaleComponent(channel);
if (scaleComponent) {
var type = scaleComponent.get('type');
var range = scaleComponent.get('range');
if (scale_1.hasDiscreteDomain(type) && vega_schema_1.isVgRangeStep(range)) {
var scaleName = model.scaleName(channel);
if (model_1.isFacetModel(model.parent)) {
// If parent is facet and this is an independent scale, return only signal signal
// as the width/height will be calculated using the cardinality from
// facet's aggregate rather than reading from scale domain
var parentResolve = model.parent.component.resolve;
if (parentResolve.scale[channel] === 'independent') {
return [stepSignal(scaleName, range)];
}
}
return [
stepSignal(scaleName, range),
{
name: name,
update: sizeExpr(scaleName, scaleComponent, "domain('" + scaleName + "').length")
}
];
}
}
/* istanbul ignore next: Condition should not happen -- only for warning in development. */
throw new Error('layout size is range step although there is no rangeStep.');
}
else {
return [{
name: name,
update: "" + size
}];
}
}
exports.sizeSignals = sizeSignals;
function stepSignal(scaleName, range) {
return {
name: scaleName + '_step',
value: range.step,
};
}
function sizeExpr(scaleName, scaleComponent, cardinality) {
var type = scaleComponent.get('type');
var padding = scaleComponent.get('padding');
var paddingOuter = scaleComponent.get('paddingOuter');
paddingOuter = paddingOuter !== undefined ? paddingOuter : padding;
var paddingInner = scaleComponent.get('paddingInner');
paddingInner = type === 'band' ?
// only band has real paddingInner
(paddingInner !== undefined ? paddingInner : padding) :
// For point, as calculated in https://github.com/vega/vega-scale/blob/master/src/band.js#L128,
// it's equivalent to have paddingInner = 1 since there is only n-1 steps between n points.
1;
return "bandspace(" + cardinality + ", " + paddingInner + ", " + paddingOuter + ") * " + scaleName + "_step";
}
exports.sizeExpr = sizeExpr;
},{"../../scale":104,"../../vega.schema":116,"../model":63}],45:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var scale_1 = require("../../scale");
var vega_schema_1 = require("../../vega.schema");
var split_1 = require("../split");
function parseLayerLayoutSize(model) {
parseChildrenLayoutSize(model);
var layoutSizeCmpt = model.component.layoutSize;
layoutSizeCmpt.setWithExplicit('width', parseNonUnitLayoutSizeForChannel(model, 'width'));
layoutSizeCmpt.setWithExplicit('height', parseNonUnitLayoutSizeForChannel(model, 'height'));
}
exports.parseLayerLayoutSize = parseLayerLayoutSize;
exports.parseRepeatLayoutSize = parseLayerLayoutSize;
function parseConcatLayoutSize(model) {
parseChildrenLayoutSize(model);
var layoutSizeCmpt = model.component.layoutSize;
var sizeTypeToMerge = model.isVConcat ? 'width' : 'height';
layoutSizeCmpt.setWithExplicit(sizeTypeToMerge, parseNonUnitLayoutSizeForChannel(model, sizeTypeToMerge));
}
exports.parseConcatLayoutSize = parseConcatLayoutSize;
function parseChildrenLayoutSize(model) {
for (var _i = 0, _a = model.children; _i < _a.length; _i++) {
var child = _a[_i];
child.parseLayoutSize();
}
}
exports.parseChildrenLayoutSize = parseChildrenLayoutSize;
function parseNonUnitLayoutSizeForChannel(model, sizeType) {
var channel = sizeType === 'width' ? 'x' : 'y';
var resolve = model.component.resolve;
var mergedSize;
// Try to merge layout size
for (var _i = 0, _a = model.children; _i < _a.length; _i++) {
var child = _a[_i];
var childSize = child.component.layoutSize.getWithExplicit(sizeType);
var scaleResolve = resolve.scale[channel];
if (scaleResolve === 'independent' && childSize.value === 'range-step') {
// Do not merge independent scales with range-step as their size depends
// on the scale domains, which can be different between scales.
mergedSize = undefined;
break;
}
if (mergedSize) {
if (scaleResolve === 'independent' && mergedSize.value !== childSize.value) {
// For independent scale, only merge if all the sizes are the same.
// If the values are different, abandon the merge!
mergedSize = undefined;
break;
}
mergedSize = split_1.mergeValuesWithExplicit(mergedSize, childSize, sizeType, '', split_1.defaultTieBreaker);
}
else {
mergedSize = childSize;
}
}
if (mergedSize) {
// If merged, rename size and set size of all children.
for (var _b = 0, _c = model.children; _b < _c.length; _b++) {
var child = _c[_b];
model.renameLayoutSize(child.getName(sizeType), model.getName(sizeType));
child.component.layoutSize.set(sizeType, 'merged', false);
}
return mergedSize;
}
else {
// Otherwise, there is no merged size.
return {
explicit: false,
value: undefined
};
}
}
function parseUnitLayoutSize(model) {
var layoutSizeComponent = model.component.layoutSize;
if (!layoutSizeComponent.explicit.width) {
var width = defaultUnitSize(model, 'width');
layoutSizeComponent.set('width', width, false);
}
if (!layoutSizeComponent.explicit.height) {
var height = defaultUnitSize(model, 'height');
layoutSizeComponent.set('height', height, false);
}
}
exports.parseUnitLayoutSize = parseUnitLayoutSize;
function defaultUnitSize(model, sizeType) {
var channel = sizeType === 'width' ? 'x' : 'y';
var config = model.config;
var scaleComponent = model.getScaleComponent(channel);
if (scaleComponent) {
var scaleType = scaleComponent.get('type');
var range = scaleComponent.get('range');
if (scale_1.hasDiscreteDomain(scaleType) && vega_schema_1.isVgRangeStep(range)) {
// For discrete domain with range.step, use dynamic width/height
return 'range-step';
}
else {
return config.view[sizeType];
}
}
else {
// No scale - set default size
if (sizeType === 'width' && model.mark() === 'text') {
// width for text mark without x-field is a bit wider than typical range step
return config.scale.textXRangeStep;
}
// Set width/height equal to rangeStep config or if rangeStep is null, use value from default scale config.
return config.scale.rangeStep || scale_1.defaultScaleConfig.rangeStep;
}
}
},{"../../scale":104,"../../vega.schema":116,"../split":86}],46:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var stringify = require("json-stable-stringify");
var util_1 = require("../../util");
var parse_1 = require("./parse");
function assembleLegends(model) {
var legendComponentIndex = model.component.legends;
var legendByDomain = {};
util_1.keys(legendComponentIndex).forEach(function (channel) {
var scaleComponent = model.getScaleComponent(channel);
var domainHash = stringify(scaleComponent.domains);
if (legendByDomain[domainHash]) {
for (var _i = 0, _a = legendByDomain[domainHash]; _i < _a.length; _i++) {
var mergedLegendComponent = _a[_i];
var merged = parse_1.mergeLegendComponent(mergedLegendComponent, legendComponentIndex[channel]);
if (!merged) {
// If cannot merge, need to add this legend separately
legendByDomain[domainHash].push(legendComponentIndex[channel]);
}
}
}
else {
legendByDomain[domainHash] = [legendComponentIndex[channel].clone()];
}
});
return util_1.flatten(util_1.vals(legendByDomain)).map(function (legendCmpt) { return legendCmpt.combine(); });
}
exports.assembleLegends = assembleLegends;
},{"../../util":114,"./parse":49,"json-stable-stringify":1}],47:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var split_1 = require("../split");
var LegendComponent = /** @class */ (function (_super) {
tslib_1.__extends(LegendComponent, _super);
function LegendComponent() {
return _super !== null && _super.apply(this, arguments) || this;
}
return LegendComponent;
}(split_1.Split));
exports.LegendComponent = LegendComponent;
},{"../split":86,"tslib":5}],48:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var channel_1 = require("../../channel");
var fielddef_1 = require("../../fielddef");
var mark_1 = require("../../mark");
var scale_1 = require("../../scale");
var util_1 = require("../../util");
var common_1 = require("../common");
var mixins = require("../mark/mixins");
function symbols(fieldDef, symbolsSpec, model, channel, legendCmpt) {
if (legendCmpt.get('type') === 'gradient') {
return undefined;
}
var symbols = {};
var mark = model.mark();
switch (mark) {
case mark_1.BAR:
case mark_1.TICK:
case mark_1.TEXT:
symbols.shape = { value: 'square' };
break;
case mark_1.CIRCLE:
case mark_1.SQUARE:
symbols.shape = { value: mark };
break;
case mark_1.POINT:
case mark_1.LINE:
case mark_1.AREA:
// use default circle
break;
}
var filled = model.markDef.filled;
var config = channel === channel_1.COLOR ?
/* For color's legend, do not set fill (when filled) or stroke (when unfilled) property from config because the legend's `fill` or `stroke` scale should have precedence */
util_1.without(mark_1.FILL_STROKE_CONFIG, [filled ? 'fill' : 'stroke', 'strokeDash', 'strokeDashOffset']) :
/* For other legend, no need to omit. */
mark_1.FILL_STROKE_CONFIG;
config = util_1.without(config, ['strokeDash', 'strokeDashOffset']);
common_1.applyMarkConfig(symbols, model, config);
if (channel !== channel_1.COLOR) {
var colorMixins = mixins.color(model);
// If there are field for fill or stroke, remove them as we already apply channels.
if (colorMixins.fill && (colorMixins.fill['field'] || colorMixins.fill['value'] === 'transparent')) {
delete colorMixins.fill;
}
if (colorMixins.stroke && (colorMixins.stroke['field'] || colorMixins.stroke['value'] === 'transparent')) {
delete colorMixins.stroke;
}
symbols = tslib_1.__assign({}, symbols, colorMixins);
}
if (channel !== channel_1.SHAPE) {
var shapeDef = model.encoding.shape;
if (fielddef_1.isValueDef(shapeDef)) {
symbols.shape = { value: shapeDef.value };
}
}
if (channel !== channel_1.OPACITY) {
var opacityDef = model.encoding.opacity;
if (fielddef_1.isValueDef(opacityDef)) {
symbols.opacity = { value: opacityDef.value };
}
}
symbols = tslib_1.__assign({}, symbols, symbolsSpec);
return util_1.keys(symbols).length > 0 ? symbols : undefined;
}
exports.symbols = symbols;
function gradient(fieldDef, gradientSpec, model, channel, legendCmpt) {
var gradient = {};
if (legendCmpt.get('type') === 'gradient') {
var opacityDef = model.encoding.opacity;
if (fielddef_1.isValueDef(opacityDef)) {
gradient.opacity = { value: opacityDef.value };
}
}
gradient = tslib_1.__assign({}, gradient, gradientSpec);
return util_1.keys(gradient).length > 0 ? gradient : undefined;
}
exports.gradient = gradient;
function labels(fieldDef, labelsSpec, model, channel, legendCmpt) {
var legend = model.legend(channel);
var config = model.config;
var labels = {};
if (fielddef_1.isTimeFieldDef(fieldDef)) {
var isUTCScale = model.getScaleComponent(channel).get('type') === scale_1.ScaleType.UTC;
labelsSpec = tslib_1.__assign({ text: {
signal: common_1.timeFormatExpression('datum.value', fieldDef.timeUnit, legend.format, config.legend.shortTimeLabels, config.timeFormat, isUTCScale)
} }, labelsSpec);
}
labels = tslib_1.__assign({}, labels, labelsSpec);
return util_1.keys(labels).length > 0 ? labels : undefined;
}
exports.labels = labels;
},{"../../channel":12,"../../fielddef":96,"../../mark":103,"../../scale":104,"../../util":114,"../common":20,"../mark/mixins":56,"tslib":5}],49:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var channel_1 = require("../../channel");
var fielddef_1 = require("../../fielddef");
var legend_1 = require("../../legend");
var util_1 = require("../../util");
var common_1 = require("../common");
var model_1 = require("../model");
var resolve_1 = require("../resolve");
var split_1 = require("../split");
var split_2 = require("../split");
var component_1 = require("./component");
var encode = require("./encode");
var properties = require("./properties");
function parseLegend(model) {
if (model_1.isUnitModel(model)) {
model.component.legends = parseUnitLegend(model);
}
else {
model.component.legends = parseNonUnitLegend(model);
}
}
exports.parseLegend = parseLegend;
function parseUnitLegend(model) {
return [channel_1.COLOR, channel_1.SIZE, channel_1.SHAPE, channel_1.OPACITY].reduce(function (legendComponent, channel) {
if (model.legend(channel)) {
legendComponent[channel] = parseLegendForChannel(model, channel);
}
return legendComponent;
}, {});
}
function getLegendDefWithScale(model, channel) {
// For binned field with continuous scale, use a special scale so we can overrride the mark props and labels
switch (channel) {
case channel_1.COLOR:
var scale = model.scaleName(channel_1.COLOR);
return model.markDef.filled ? { fill: scale } : { stroke: scale };
case channel_1.SIZE:
return { size: model.scaleName(channel_1.SIZE) };
case channel_1.SHAPE:
return { shape: model.scaleName(channel_1.SHAPE) };
case channel_1.OPACITY:
return { opacity: model.scaleName(channel_1.OPACITY) };
}
return null;
}
function parseLegendForChannel(model, channel) {
var fieldDef = model.fieldDef(channel);
var legend = model.legend(channel);
var legendCmpt = new component_1.LegendComponent({}, getLegendDefWithScale(model, channel));
legend_1.LEGEND_PROPERTIES.forEach(function (property) {
var value = getProperty(property, legend, channel, model);
if (value !== undefined) {
var explicit = property === 'values' ?
!!legend.values :
value === legend[property];
legendCmpt.set(property, value, explicit);
}
});
// 2) Add mark property definition groups
var legendEncoding = legend.encoding || {};
var legendEncode = ['labels', 'legend', 'title', 'symbols', 'gradient'].reduce(function (e, part) {
var value = encode[part] ?
encode[part](fieldDef, legendEncoding[part], model, channel, legendCmpt) :
legendEncoding[part]; // no rule -- just default values
if (value !== undefined && util_1.keys(value).length > 0) {
e[part] = { update: value };
}
return e;
}, {});
if (util_1.keys(legendEncode).length > 0) {
legendCmpt.set('encode', legendEncode, !!legend.encoding);
}
return legendCmpt;
}
exports.parseLegendForChannel = parseLegendForChannel;
function getProperty(property, specifiedLegend, channel, model) {
var fieldDef = model.fieldDef(channel);
switch (property) {
case 'format':
// We don't include temporal field here as we apply format in encode block
return common_1.numberFormat(fieldDef, specifiedLegend.format, model.config);
case 'title':
return common_1.getSpecifiedOrDefaultValue(specifiedLegend.title, fielddef_1.title(fieldDef, model.config));
case 'values':
return properties.values(specifiedLegend);
case 'type':
return common_1.getSpecifiedOrDefaultValue(specifiedLegend.type, properties.type(fieldDef.type, channel, model.getScaleComponent(channel).get('type')));
}
// Otherwise, return specified property.
return specifiedLegend[property];
}
function parseNonUnitLegend(model) {
var _a = model.component, legends = _a.legends, resolve = _a.resolve;
var _loop_1 = function (child) {
parseLegend(child);
util_1.keys(child.component.legends).forEach(function (channel) {
resolve.legend[channel] = resolve_1.parseGuideResolve(model.component.resolve, channel);
if (resolve.legend[channel] === 'shared') {
// If the resolve says shared (and has not been overridden)
// We will try to merge and see if there is a conflict
legends[channel] = mergeLegendComponent(legends[channel], child.component.legends[channel]);
if (!legends[channel]) {
// If merge returns nothing, there is a conflict so we cannot make the legend shared.
// Thus, mark legend as independent and remove the legend component.
resolve.legend[channel] = 'independent';
delete legends[channel];
}
}
});
};
for (var _i = 0, _b = model.children; _i < _b.length; _i++) {
var child = _b[_i];
_loop_1(child);
}
util_1.keys(legends).forEach(function (channel) {
for (var _i = 0, _a = model.children; _i < _a.length; _i++) {
var child = _a[_i];
if (!child.component.legends[channel]) {
// skip if the child does not have a particular legend
continue;
}
if (resolve.legend[channel] === 'shared') {
// After merging shared legend, make sure to remove legend from child
delete child.component.legends[channel];
}
}
});
return legends;
}
function mergeLegendComponent(mergedLegend, childLegend) {
if (!mergedLegend) {
return childLegend.clone();
}
var mergedOrient = mergedLegend.getWithExplicit('orient');
var childOrient = childLegend.getWithExplicit('orient');
if (mergedOrient.explicit && childOrient.explicit && mergedOrient.value !== childOrient.value) {
// TODO: throw warning if resolve is explicit (We don't have info about explicit/implicit resolve yet.)
// Cannot merge due to inconsistent orient
return undefined;
}
var typeMerged = false;
var _loop_2 = function (prop) {
var mergedValueWithExplicit = split_2.mergeValuesWithExplicit(mergedLegend.getWithExplicit(prop), childLegend.getWithExplicit(prop), prop, 'legend',
// Tie breaker function
function (v1, v2) {
switch (prop) {
case 'title':
return common_1.titleMerger(v1, v2);
case 'type':
// There are only two types. If we have different types, then prefer symbol over gradient.
typeMerged = true;
return split_1.makeImplicit('symbol');
}
return split_2.defaultTieBreaker(v1, v2, prop, 'legend');
});
mergedLegend.setWithExplicit(prop, mergedValueWithExplicit);
};
// Otherwise, let's merge
for (var _i = 0, VG_LEGEND_PROPERTIES_1 = legend_1.VG_LEGEND_PROPERTIES; _i < VG_LEGEND_PROPERTIES_1.length; _i++) {
var prop = VG_LEGEND_PROPERTIES_1[_i];
_loop_2(prop);
}
if (typeMerged) {
if (((mergedLegend.implicit || {}).encode || {}).gradient) {
util_1.deleteNestedProperty(mergedLegend.implicit, ['encode', 'gradient']);
}
if (((mergedLegend.explicit || {}).encode || {}).gradient) {
util_1.deleteNestedProperty(mergedLegend.explicit, ['encode', 'gradient']);
}
}
return mergedLegend;
}
exports.mergeLegendComponent = mergeLegendComponent;
},{"../../channel":12,"../../fielddef":96,"../../legend":100,"../../util":114,"../common":20,"../model":63,"../resolve":66,"../split":86,"./component":47,"./encode":48,"./properties":50}],50:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var channel_1 = require("../../channel");
var datetime_1 = require("../../datetime");
var scale_1 = require("../../scale");
var util_1 = require("../../util");
function values(legend) {
var vals = legend.values;
if (vals && datetime_1.isDateTime(vals[0])) {
return vals.map(function (dt) {
// normalize = true as end user won't put 0 = January
return { signal: datetime_1.dateTimeExpr(dt, true) };
});
}
return vals;
}
exports.values = values;
function type(type, channel, scaleType) {
if (channel === channel_1.COLOR && ((type === 'quantitative' && !scale_1.isBinScale(scaleType)) ||
(type === 'temporal' && util_1.contains(['time', 'utc'], scaleType)))) {
return 'gradient';
}
return undefined;
}
exports.type = type;
},{"../../channel":12,"../../datetime":93,"../../scale":104,"../../util":114}],51:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var mixins = require("./mixins");
exports.area = {
vgMark: 'area',
encodeEntry: function (model) {
return tslib_1.__assign({}, mixins.pointPosition('x', model, 'zeroOrMin'), mixins.pointPosition('y', model, 'zeroOrMin'), mixins.pointPosition2(model, 'zeroOrMin'), mixins.color(model), mixins.text(model, 'tooltip'), mixins.nonPosition('opacity', model), mixins.markDefProperties(model.markDef, ['orient', 'interpolate', 'tension']));
}
};
},{"./mixins":56,"tslib":5}],52:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var vega_util_1 = require("vega-util");
var channel_1 = require("../../channel");
var fielddef_1 = require("../../fielddef");
var log = require("../../log");
var scale_1 = require("../../scale");
var vega_schema_1 = require("../../vega.schema");
var mixins = require("./mixins");
var ref = require("./valueref");
exports.bar = {
vgMark: 'rect',
encodeEntry: function (model) {
var stack = model.stack;
return tslib_1.__assign({}, x(model, stack), y(model, stack), mixins.color(model), mixins.text(model, 'tooltip'), mixins.nonPosition('opacity', model));
}
};
function x(model, stack) {
var config = model.config, width = model.width;
var orient = model.markDef.orient;
var sizeDef = model.encoding.size;
var xDef = model.encoding.x;
var xScaleName = model.scaleName(channel_1.X);
var xScale = model.getScaleComponent(channel_1.X);
// x, x2, and width -- we must specify two of these in all conditions
if (orient === 'horizontal') {
return tslib_1.__assign({}, mixins.pointPosition('x', model, 'zeroOrMin'), mixins.pointPosition2(model, 'zeroOrMin'));
}
else {
if (fielddef_1.isFieldDef(xDef)) {
var xScaleType = xScale.get('type');
if (xDef.bin && !sizeDef && !scale_1.hasDiscreteDomain(xScaleType)) {
return mixins.binnedPosition(xDef, 'x', model.scaleName('x'), config.bar.binSpacing, xScale.get('reverse'));
}
else {
if (xScaleType === scale_1.ScaleType.BAND) {
return mixins.bandPosition(xDef, 'x', model);
}
}
}
// sized bin, normal point-ordinal axis, quantitative x-axis, or no x
return mixins.centeredBandPosition('x', model, tslib_1.__assign({}, ref.mid(width)), defaultSizeRef(xScaleName, xScale, config));
}
}
function y(model, stack) {
var config = model.config, encoding = model.encoding, height = model.height;
var orient = model.markDef.orient;
var sizeDef = encoding.size;
var yDef = encoding.y;
var yScaleName = model.scaleName(channel_1.Y);
var yScale = model.getScaleComponent(channel_1.Y);
// y, y2 & height -- we must specify two of these in all conditions
if (orient === 'vertical') {
return tslib_1.__assign({}, mixins.pointPosition('y', model, 'zeroOrMin'), mixins.pointPosition2(model, 'zeroOrMin'));
}
else {
if (fielddef_1.isFieldDef(yDef)) {
var yScaleType = yScale.get('type');
if (yDef.bin && !sizeDef && !scale_1.hasDiscreteDomain(yScaleType)) {
return mixins.binnedPosition(yDef, 'y', model.scaleName('y'), config.bar.binSpacing, yScale.get('reverse'));
}
else if (yScaleType === scale_1.ScaleType.BAND) {
return mixins.bandPosition(yDef, 'y', model);
}
}
return mixins.centeredBandPosition('y', model, ref.mid(height), defaultSizeRef(yScaleName, yScale, config));
}
}
function defaultSizeRef(scaleName, scale, config) {
if (config.bar.discreteBandSize) {
return { value: config.bar.discreteBandSize };
}
if (scale) {
var scaleType = scale.get('type');
if (scaleType === scale_1.ScaleType.POINT) {
var scaleRange = scale.get('range');
if (vega_schema_1.isVgRangeStep(scaleRange) && vega_util_1.isNumber(scaleRange.step)) {
return { value: scaleRange.step - 1 };
}
log.warn(log.message.BAR_WITH_POINT_SCALE_AND_RANGESTEP_NULL);
}
else if (scaleType === scale_1.ScaleType.BAND) {
return ref.band(scaleName);
}
else {
return { value: config.bar.continuousBandSize };
}
}
if (config.scale.rangeStep && config.scale.rangeStep !== null) {
return { value: config.scale.rangeStep - 1 };
}
return { value: 20 };
}
},{"../../channel":12,"../../fielddef":96,"../../log":101,"../../scale":104,"../../vega.schema":116,"./mixins":56,"./valueref":62,"tslib":5,"vega-util":7}],53:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var encoding_1 = require("../../encoding");
var fielddef_1 = require("../../fielddef");
var log = require("../../log");
var mark_1 = require("../../mark");
var scale_1 = require("../../scale");
var type_1 = require("../../type");
var util_1 = require("../../util");
var common_1 = require("../common");
function normalizeMarkDef(markDef, encoding, scales, config) {
var specifiedOrient = markDef.orient || common_1.getMarkConfig('orient', markDef, config);
markDef.orient = orient(markDef.type, encoding, scales, specifiedOrient);
if (specifiedOrient !== undefined && specifiedOrient !== markDef.orient) {
log.warn(log.message.orientOverridden(markDef.orient, specifiedOrient));
}
var specifiedFilled = markDef.filled;
if (specifiedFilled === undefined) {
markDef.filled = filled(markDef, config);
}
}
exports.normalizeMarkDef = normalizeMarkDef;
/**
* Initialize encoding's value with some special default values
*/
function initEncoding(mark, encoding, stacked, config) {
var opacityConfig = common_1.getMarkConfig('opacity', mark, config);
if (!encoding.opacity && opacityConfig === undefined) {
var opacity = defaultOpacity(mark.type, encoding, stacked);
if (opacity !== undefined) {
encoding.opacity = { value: opacity };
}
}
return encoding;
}
exports.initEncoding = initEncoding;
function defaultOpacity(mark, encoding, stacked) {
if (util_1.contains([mark_1.POINT, mark_1.TICK, mark_1.CIRCLE, mark_1.SQUARE], mark)) {
// point-based marks
if (!encoding_1.isAggregate(encoding)) {
return 0.7;
}
}
return undefined;
}
function filled(markDef, config) {
var filledConfig = common_1.getMarkConfig('filled', markDef, config);
var mark = markDef.type;
return filledConfig !== undefined ? filledConfig : mark !== mark_1.POINT && mark !== mark_1.LINE && mark !== mark_1.RULE;
}
function orient(mark, encoding, scales, specifiedOrient) {
switch (mark) {
case mark_1.POINT:
case mark_1.CIRCLE:
case mark_1.SQUARE:
case mark_1.TEXT:
case mark_1.RECT:
// orient is meaningless for these marks.
return undefined;
}
var yIsRange = encoding.y && encoding.y2;
var xIsRange = encoding.x && encoding.x2;
switch (mark) {
case mark_1.TICK:
var xScaleType = scales.x ? scales.x.get('type') : null;
var yScaleType = scales.y ? scales.y.get('type') : null;
// Tick is opposite to bar, line, area and never have ranged mark.
if (!scale_1.hasDiscreteDomain(xScaleType) && (!encoding.y ||
scale_1.hasDiscreteDomain(yScaleType) ||
(fielddef_1.isFieldDef(encoding.y) && encoding.y.bin))) {
return 'vertical';
}
// y:Q or Ambiguous case, return horizontal
return 'horizontal';
case mark_1.RULE:
case mark_1.BAR:
case mark_1.AREA:
// If there are range for both x and y, y (vertical) has higher precedence.
if (yIsRange) {
return 'vertical';
}
else if (xIsRange) {
return 'horizontal';
}
else if (mark === mark_1.RULE) {
if (encoding.x && !encoding.y) {
return 'vertical';
}
else if (encoding.y && !encoding.x) {
return 'horizontal';
}
}
/* tslint:disable */
case mark_1.LINE:// intentional fall through
/* tslint:enable */
var xIsContinuous = fielddef_1.isFieldDef(encoding.x) && fielddef_1.isContinuous(encoding.x);
var yIsContinuous = fielddef_1.isFieldDef(encoding.y) && fielddef_1.isContinuous(encoding.y);
if (xIsContinuous && !yIsContinuous) {
return 'horizontal';
}
else if (!xIsContinuous && yIsContinuous) {
return 'vertical';
}
else if (xIsContinuous && yIsContinuous) {
var xDef = encoding.x; // we can cast here since they are surely fieldDef
var yDef = encoding.y;
var xIsTemporal = xDef.type === type_1.TEMPORAL;
var yIsTemporal = yDef.type === type_1.TEMPORAL;
// temporal without timeUnit is considered continuous, but better serves as dimension
if (xIsTemporal && !yIsTemporal) {
return 'vertical';
}
else if (!xIsTemporal && yIsTemporal) {
return 'horizontal';
}
if (!xDef.aggregate && yDef.aggregate) {
return 'vertical';
}
else if (xDef.aggregate && !yDef.aggregate) {
return 'horizontal';
}
if (specifiedOrient) {
// When ambiguous, use user specified one.
return specifiedOrient;
}
if (!(mark === mark_1.LINE && encoding.order)) {
// Except for connected scatterplot, we should log warning for unclear orientation of QxQ plots.
log.warn(log.message.unclearOrientContinuous(mark));
}
return 'vertical';
}
else {
// For Discrete x Discrete case, return undefined.
log.warn(log.message.unclearOrientDiscreteOrEmpty(mark));
return undefined;
}
}
return 'vertical';
}
},{"../../encoding":94,"../../fielddef":96,"../../log":101,"../../mark":103,"../../scale":104,"../../type":113,"../../util":114,"../common":20}],54:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var mixins = require("./mixins");
var ref = require("./valueref");
exports.line = {
vgMark: 'line',
encodeEntry: function (model) {
var width = model.width, height = model.height;
return tslib_1.__assign({}, mixins.pointPosition('x', model, ref.mid(width)), mixins.pointPosition('y', model, ref.mid(height)), mixins.color(model), mixins.text(model, 'tooltip'), mixins.nonPosition('opacity', model), mixins.nonPosition('size', model, {
vgChannel: 'strokeWidth' // VL's line size is strokeWidth
}), mixins.markDefProperties(model.markDef, ['interpolate', 'tension']));
}
};
},{"./mixins":56,"./valueref":62,"tslib":5}],55:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var vega_util_1 = require("vega-util");
var channel_1 = require("../../channel");
var data_1 = require("../../data");
var encoding_1 = require("../../encoding");
var fielddef_1 = require("../../fielddef");
var mark_1 = require("../../mark");
var sort_1 = require("../../sort");
var util_1 = require("../../util");
var common_1 = require("../common");
var model_1 = require("../model");
var area_1 = require("./area");
var bar_1 = require("./bar");
var init_1 = require("./init");
var line_1 = require("./line");
var point_1 = require("./point");
var rect_1 = require("./rect");
var rule_1 = require("./rule");
var text_1 = require("./text");
var tick_1 = require("./tick");
var markCompiler = {
area: area_1.area,
bar: bar_1.bar,
line: line_1.line,
point: point_1.point,
text: text_1.text,
tick: tick_1.tick,
rect: rect_1.rect,
rule: rule_1.rule,
circle: point_1.circle,
square: point_1.square
};
function parseMarkDef(model) {
if (model_1.isUnitModel(model)) {
init_1.normalizeMarkDef(model.markDef, model.encoding, model.component.scales, model.config);
}
else {
for (var _i = 0, _a = model.children; _i < _a.length; _i++) {
var child = _a[_i];
parseMarkDef(child);
}
}
}
exports.parseMarkDef = parseMarkDef;
function parseMarkGroup(model) {
if (util_1.contains([mark_1.LINE, mark_1.AREA], model.mark())) {
return parsePathMark(model);
}
else {
return parseNonPathMark(model);
}
}
exports.parseMarkGroup = parseMarkGroup;
var FACETED_PATH_PREFIX = 'faceted_path_';
function parsePathMark(model) {
var mark = model.mark();
// FIXME: replace this with more general case for composition
var details = detailFields(model);
var clip = model.markDef.clip !== undefined ? !!model.markDef.clip : scaleClip(model);
var style = common_1.getStyles(model.markDef);
var sort = getPathSort(model);
var pathMarks = [
tslib_1.__assign({ name: model.getName('marks'), type: markCompiler[mark].vgMark }, (clip ? { clip: true } : {}), (style ? { style: style } : {}), (sort ? { sort: sort } : {}), {
// If has subfacet for line/area group, need to use faceted data from below.
// FIXME: support sorting path order (in connected scatterplot)
from: { data: (details.length > 0 ? FACETED_PATH_PREFIX : '') + model.requestDataName(data_1.MAIN) }, encode: { update: markCompiler[mark].encodeEntry(model) } })
];
if (details.length > 0) {
// TODO: for non-stacked plot, map order to zindex. (Maybe rename order for layer to zindex?)
return [{
name: model.getName('pathgroup'),
type: 'group',
from: {
facet: {
name: FACETED_PATH_PREFIX + model.requestDataName(data_1.MAIN),
data: model.requestDataName(data_1.MAIN),
groupby: details,
}
},
encode: {
update: {
width: { field: { group: 'width' } },
height: { field: { group: 'height' } }
}
},
marks: pathMarks
}];
}
else {
return pathMarks;
}
}
function getPathSort(model) {
if (model.mark() === 'line' && model.channelHasField('order')) {
// For only line, sort by the order field if it is specified.
return common_1.sortParams(model.encoding.order, { expr: 'datum' });
}
else {
// For both line and area, we sort values based on dimension by default
var dimensionChannel = model.markDef.orient === 'horizontal' ? 'y' : 'x';
var s = model.sort(dimensionChannel);
var sortField = sort_1.isSortField(s) ?
fielddef_1.field({
// FIXME: this op might not already exist?
// FIXME: what if dimensionChannel (x or y) contains custom domain?
aggregate: encoding_1.isAggregate(model.encoding) ? s.op : undefined,
field: s.field
}, { expr: 'datum' }) :
model.field(dimensionChannel, {
// For stack with imputation, we only have bin_mid
binSuffix: model.stack && model.stack.impute ? 'mid' : undefined,
expr: 'datum'
});
return sortField ?
{
field: sortField,
order: 'descending'
} :
undefined;
}
}
exports.getPathSort = getPathSort;
function parseNonPathMark(model) {
var mark = model.mark();
var style = common_1.getStyles(model.markDef);
var clip = model.markDef.clip !== undefined ? !!model.markDef.clip : scaleClip(model);
var marks = []; // TODO: vgMarks
// TODO: for non-stacked plot, map order to zindex. (Maybe rename order for layer to zindex?)
marks.push(tslib_1.__assign({ name: model.getName('marks'), type: markCompiler[mark].vgMark }, (clip ? { clip: true } : {}), (style ? { style: style } : {}), { from: { data: model.requestDataName(data_1.MAIN) }, encode: { update: markCompiler[mark].encodeEntry(model) } }));
return marks;
}
/**
* Returns list of detail (group-by) fields
* that the model's spec contains.
*/
function detailFields(model) {
return channel_1.NONSPATIAL_CHANNELS.reduce(function (details, channel) {
var encoding = model.encoding;
if (channel === 'order') {
return details;
}
if (channel === 'detail') {
var channelDef = encoding[channel];
if (channelDef) {
(vega_util_1.isArray(channelDef) ? channelDef : [channelDef]).forEach(function (fieldDef) {
if (!fieldDef.aggregate) {
details.push(fielddef_1.field(fieldDef, {}));
}
});
}
}
else {
var fieldDef = fielddef_1.getFieldDef(encoding[channel]);
if (fieldDef && !fieldDef.aggregate) {
details.push(fielddef_1.field(fieldDef, {}));
}
}
return details;
}, []);
}
/**
* If scales are bound to interval selections, we want to automatically clip
* marks to account for panning/zooming interactions. We identify bound scales
* by the domainRaw property, which gets added during scale parsing.
*/
function scaleClip(model) {
var xScale = model.getScaleComponent('x');
var yScale = model.getScaleComponent('y');
return (xScale && xScale.get('domainRaw')) ||
(yScale && yScale.get('domainRaw')) ? true : false;
}
},{"../../channel":12,"../../data":92,"../../encoding":94,"../../fielddef":96,"../../mark":103,"../../sort":106,"../../util":114,"../common":20,"../model":63,"./area":51,"./bar":52,"./init":53,"./line":54,"./point":57,"./rect":58,"./rule":59,"./text":60,"./tick":61,"tslib":5,"vega-util":7}],56:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var fielddef_1 = require("../../fielddef");
var log = require("../../log");
var util = require("../../util");
var common_1 = require("../common");
var selection_1 = require("../selection/selection");
var ref = require("./valueref");
function color(model) {
var config = model.config;
var filled = model.markDef.filled;
var vgChannel = filled ? 'fill' : 'stroke';
var e = nonPosition('color', model, {
vgChannel: vgChannel,
// fill/stroke has higher precedence than color
defaultValue: common_1.getMarkConfig(vgChannel, model.markDef, config) ||
common_1.getMarkConfig('color', model.markDef, config)
});
// If there is no fill, always fill symbols
// with transparent fills https://github.com/vega/vega-lite/issues/1316
if (!e.fill && util.contains(['bar', 'point', 'circle', 'square'], model.mark())) {
e.fill = { value: 'transparent' };
}
return e;
}
exports.color = color;
function markDefProperties(mark, props) {
return props.reduce(function (m, prop) {
if (mark[prop]) {
m[prop] = { value: mark[prop] };
}
return m;
}, {});
}
exports.markDefProperties = markDefProperties;
function valueIfDefined(prop, value) {
if (value !== undefined) {
return _a = {}, _a[prop] = { value: value }, _a;
}
return undefined;
var _a;
}
exports.valueIfDefined = valueIfDefined;
/**
* Return mixins for non-positional channels with scales. (Text doesn't have scale.)
*/
function nonPosition(channel, model, opt) {
// TODO: refactor how we refer to scale as discussed in https://github.com/vega/vega-lite/pull/1613
if (opt === void 0) { opt = {}; }
var defaultValue = opt.defaultValue, vgChannel = opt.vgChannel;
var defaultRef = opt.defaultRef || (defaultValue !== undefined ? { value: defaultValue } : undefined);
var channelDef = model.encoding[channel];
return wrapCondition(model, channelDef, vgChannel || channel, function (cDef) {
return ref.midPoint(channel, cDef, model.scaleName(channel), model.getScaleComponent(channel), null, // No need to provide stack for non-position as it does not affect mid point
defaultRef);
});
}
exports.nonPosition = nonPosition;
/**
* Return a mixin that include a Vega production rule for a Vega-Lite conditional channel definition.
* or a simple mixin if channel def has no condition.
*/
function wrapCondition(model, channelDef, vgChannel, refFn) {
var condition = channelDef && channelDef.condition;
var valueRef = refFn(channelDef);
if (condition) {
var conditionValueRef = refFn(condition);
return _a = {},
_a[vgChannel] = [
tslib_1.__assign({ test: selection_1.predicate(model, condition.selection) }, conditionValueRef)
].concat((valueRef !== undefined ? [valueRef] : [])),
_a;
}
else {
return valueRef !== undefined ? (_b = {}, _b[vgChannel] = valueRef, _b) : {};
}
var _a, _b;
}
function text(model, channel) {
if (channel === void 0) { channel = 'text'; }
var channelDef = model.encoding[channel];
return wrapCondition(model, channelDef, channel, function (cDef) { return ref.text(cDef, model.config); });
}
exports.text = text;
function bandPosition(fieldDef, channel, model) {
var scaleName = model.scaleName(channel);
var sizeChannel = channel === 'x' ? 'width' : 'height';
if (model.encoding.size) {
var orient = model.markDef.orient;
if (orient) {
var centeredBandPositionMixins = (_a = {},
// Use xc/yc and place the mark at the middle of the band
// This way we never have to deal with size's condition for x/y position.
_a[channel + 'c'] = ref.fieldRef(fieldDef, scaleName, {}, { band: 0.5 }),
_a);
if (fielddef_1.getFieldDef(model.encoding.size)) {
log.warn(log.message.cannotUseSizeFieldWithBandSize(channel));
// TODO: apply size to band and set scale range to some values between 0-1.
// return {
// ...centeredBandPositionMixins,
// ...bandSize('size', model, {vgChannel: sizeChannel})
// };
}
else if (fielddef_1.isValueDef(model.encoding.size)) {
return tslib_1.__assign({}, centeredBandPositionMixins, nonPosition('size', model, { vgChannel: sizeChannel }));
}
}
else {
log.warn(log.message.cannotApplySizeToNonOrientedMark(model.markDef.type));
}
}
return _b = {},
_b[channel] = ref.fieldRef(fieldDef, scaleName, { binSuffix: 'range' }),
_b[sizeChannel] = ref.band(scaleName),
_b;
var _a, _b;
}
exports.bandPosition = bandPosition;
function centeredBandPosition(channel, model, defaultPosRef, defaultSizeRef) {
var centerChannel = channel === 'x' ? 'xc' : 'yc';
var sizeChannel = channel === 'x' ? 'width' : 'height';
return tslib_1.__assign({}, pointPosition(channel, model, defaultPosRef, centerChannel), nonPosition('size', model, { defaultRef: defaultSizeRef, vgChannel: sizeChannel }));
}
exports.centeredBandPosition = centeredBandPosition;
function binnedPosition(fieldDef, channel, scaleName, spacing, reverse) {
if (channel === 'x') {
return {
x2: ref.bin(fieldDef, scaleName, 'start', reverse ? 0 : spacing),
x: ref.bin(fieldDef, scaleName, 'end', reverse ? spacing : 0)
};
}
else {
return {
y2: ref.bin(fieldDef, scaleName, 'start', reverse ? spacing : 0),
y: ref.bin(fieldDef, scaleName, 'end', reverse ? 0 : spacing)
};
}
}
exports.binnedPosition = binnedPosition;
/**
* Return mixins for point (non-band) position channels.
*/
function pointPosition(channel, model, defaultRef, vgChannel) {
// TODO: refactor how refer to scale as discussed in https://github.com/vega/vega-lite/pull/1613
var encoding = model.encoding, stack = model.stack;
var valueRef = ref.stackable(channel, encoding[channel], model.scaleName(channel), model.getScaleComponent(channel), stack, defaultRef);
return _a = {},
_a[vgChannel || channel] = valueRef,
_a;
var _a;
}
exports.pointPosition = pointPosition;
/**
* Return mixins for x2, y2.
* If channel is not specified, return one channel based on orientation.
*/
function pointPosition2(model, defaultRef, channel) {
var encoding = model.encoding, markDef = model.markDef, stack = model.stack;
channel = channel || (markDef.orient === 'horizontal' ? 'x2' : 'y2');
var baseChannel = channel === 'x2' ? 'x' : 'y';
var valueRef = ref.stackable2(channel, encoding[baseChannel], encoding[channel], model.scaleName(baseChannel), model.getScaleComponent(baseChannel), stack, defaultRef);
return _a = {}, _a[channel] = valueRef, _a;
var _a;
}
exports.pointPosition2 = pointPosition2;
},{"../../fielddef":96,"../../log":101,"../../util":114,"../common":20,"../selection/selection":76,"./valueref":62,"tslib":5}],57:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var common_1 = require("../common");
var mixins = require("./mixins");
var ref = require("./valueref");
function encodeEntry(model, fixedShape) {
var config = model.config, width = model.width, height = model.height;
return tslib_1.__assign({}, mixins.pointPosition('x', model, ref.mid(width)), mixins.pointPosition('y', model, ref.mid(height)), mixins.color(model), mixins.text(model, 'tooltip'), mixins.nonPosition('size', model), shapeMixins(model, config, fixedShape), mixins.nonPosition('opacity', model));
}
function shapeMixins(model, config, fixedShape) {
if (fixedShape) {
return { shape: { value: fixedShape } };
}
return mixins.nonPosition('shape', model, { defaultValue: common_1.getMarkConfig('shape', model.markDef, config) });
}
exports.shapeMixins = shapeMixins;
exports.point = {
vgMark: 'symbol',
encodeEntry: function (model) {
return encodeEntry(model);
}
};
exports.circle = {
vgMark: 'symbol',
encodeEntry: function (model) {
return encodeEntry(model, 'circle');
}
};
exports.square = {
vgMark: 'symbol',
encodeEntry: function (model) {
return encodeEntry(model, 'square');
}
};
},{"../common":20,"./mixins":56,"./valueref":62,"tslib":5}],58:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var channel_1 = require("../../channel");
var fielddef_1 = require("../../fielddef");
var log = require("../../log");
var mark_1 = require("../../mark");
var scale_1 = require("../../scale");
var mixins = require("./mixins");
exports.rect = {
vgMark: 'rect',
encodeEntry: function (model) {
return tslib_1.__assign({}, x(model), y(model), mixins.color(model), mixins.text(model, 'tooltip'), mixins.nonPosition('opacity', model));
}
};
function x(model) {
var xDef = model.encoding.x;
var x2Def = model.encoding.x2;
var xScale = model.getScaleComponent(channel_1.X);
var xScaleType = xScale ? xScale.get('type') : undefined;
if (fielddef_1.isFieldDef(xDef) && xDef.bin && !x2Def) {
return mixins.binnedPosition(xDef, 'x', model.scaleName('x'), 0, xScale.get('reverse'));
}
else if (fielddef_1.isFieldDef(xDef) && xScale && scale_1.hasDiscreteDomain(xScaleType)) {
/* istanbul ignore else */
if (xScaleType === scale_1.ScaleType.BAND) {
return mixins.bandPosition(xDef, 'x', model);
}
else {
// We don't support rect mark with point/ordinal scale
throw new Error(log.message.scaleTypeNotWorkWithMark(mark_1.RECT, xScaleType));
}
}
else {
return tslib_1.__assign({}, mixins.pointPosition('x', model, 'zeroOrMax'), mixins.pointPosition2(model, 'zeroOrMin', 'x2'));
}
}
function y(model) {
var yDef = model.encoding.y;
var y2Def = model.encoding.y2;
var yScale = model.getScaleComponent(channel_1.Y);
var yScaleType = yScale ? yScale.get('type') : undefined;
if (fielddef_1.isFieldDef(yDef) && yDef.bin && !y2Def) {
return mixins.binnedPosition(yDef, 'y', model.scaleName('y'), 0, yScale.get('reverse'));
}
else if (fielddef_1.isFieldDef(yDef) && yScale && scale_1.hasDiscreteDomain(yScaleType)) {
/* istanbul ignore else */
if (yScaleType === scale_1.ScaleType.BAND) {
return mixins.bandPosition(yDef, 'y', model);
}
else {
// We don't support rect mark with point/ordinal scale
throw new Error(log.message.scaleTypeNotWorkWithMark(mark_1.RECT, yScaleType));
}
}
else {
return tslib_1.__assign({}, mixins.pointPosition('y', model, 'zeroOrMax'), mixins.pointPosition2(model, 'zeroOrMin', 'y2'));
}
}
},{"../../channel":12,"../../fielddef":96,"../../log":101,"../../mark":103,"../../scale":104,"./mixins":56,"tslib":5}],59:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var mixins = require("./mixins");
var ref = require("./valueref");
exports.rule = {
vgMark: 'rule',
encodeEntry: function (model) {
var _config = model.config, markDef = model.markDef, width = model.width, height = model.height;
var orient = markDef.orient;
return tslib_1.__assign({}, mixins.pointPosition('x', model, orient === 'horizontal' ? 'zeroOrMin' : ref.mid(width)), mixins.pointPosition('y', model, orient === 'vertical' ? 'zeroOrMin' : ref.mid(height)), mixins.pointPosition2(model, 'zeroOrMax'), mixins.color(model), mixins.text(model, 'tooltip'), mixins.nonPosition('opacity', model), mixins.nonPosition('size', model, {
vgChannel: 'strokeWidth' // VL's rule size is strokeWidth
}));
}
};
},{"./mixins":56,"./valueref":62,"tslib":5}],60:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var channel_1 = require("../../channel");
var encoding_1 = require("../../encoding");
var fielddef_1 = require("../../fielddef");
var type_1 = require("../../type");
var common_1 = require("../common");
var mixins = require("./mixins");
var ref = require("./valueref");
exports.text = {
vgMark: 'text',
encodeEntry: function (model) {
var config = model.config, encoding = model.encoding, height = model.height;
var textDef = encoding.text;
return tslib_1.__assign({}, mixins.pointPosition('x', model, xDefault(config, textDef)), mixins.pointPosition('y', model, ref.mid(height)), mixins.text(model), mixins.color(model), mixins.text(model, 'tooltip'), mixins.nonPosition('opacity', model), mixins.nonPosition('size', model, {
vgChannel: 'fontSize' // VL's text size is fontSize
}), mixins.valueIfDefined('align', align(model.markDef, encoding, config)));
}
};
function xDefault(config, textDef) {
if (fielddef_1.isFieldDef(textDef) && textDef.type === type_1.QUANTITATIVE) {
return { field: { group: 'width' }, offset: -5 };
}
// TODO: allow this to fit (Be consistent with ref.midX())
return { value: config.scale.textXRangeStep / 2 };
}
function align(markDef, encoding, config) {
var alignConfig = common_1.getMarkConfig('align', markDef, config);
if (alignConfig === undefined) {
return encoding_1.channelHasField(encoding, channel_1.X) ? 'center' : 'right';
}
// If there is a config, Vega-parser will process this already.
return undefined;
}
},{"../../channel":12,"../../encoding":94,"../../fielddef":96,"../../type":113,"../common":20,"./mixins":56,"./valueref":62,"tslib":5}],61:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var vega_schema_1 = require("../../vega.schema");
var mixins = require("./mixins");
var ref = require("./valueref");
exports.tick = {
vgMark: 'rect',
encodeEntry: function (model) {
var config = model.config, markDef = model.markDef, width = model.width, height = model.height;
var orient = markDef.orient;
var vgSizeChannel = orient === 'horizontal' ? 'width' : 'height';
var vgThicknessChannel = orient === 'horizontal' ? 'height' : 'width';
return tslib_1.__assign({}, mixins.pointPosition('x', model, ref.mid(width), 'xc'), mixins.pointPosition('y', model, ref.mid(height), 'yc'), mixins.nonPosition('size', model, {
defaultValue: defaultSize(model),
vgChannel: vgSizeChannel
}), (_a = {}, _a[vgThicknessChannel] = { value: config.tick.thickness }, _a), mixins.color(model), mixins.nonPosition('opacity', model));
var _a;
}
};
function defaultSize(model) {
var config = model.config;
var orient = model.markDef.orient;
var scale = model.getScaleComponent(orient === 'horizontal' ? 'x' : 'y');
if (config.tick.bandSize !== undefined) {
return config.tick.bandSize;
}
else {
var scaleRange = scale ? scale.get('range') : undefined;
var rangeStep = scaleRange && vega_schema_1.isVgRangeStep(scaleRange) ?
scaleRange.step :
config.scale.rangeStep;
if (typeof rangeStep !== 'number') {
// FIXME consolidate this log
throw new Error('Function does not handle non-numeric rangeStep');
}
return rangeStep / 1.5;
}
}
},{"../../vega.schema":116,"./mixins":56,"./valueref":62,"tslib":5}],62:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
/**
* Utility files for producing Vega ValueRef for marks
*/
var channel_1 = require("../../channel");
var fielddef_1 = require("../../fielddef");
var scale_1 = require("../../scale");
var util_1 = require("../../util");
var common_1 = require("../common");
// TODO: we need to find a way to refactor these so that scaleName is a part of scale
// but that's complicated. For now, this is a huge step moving forward.
/**
* @return Vega ValueRef for stackable x or y
*/
function stackable(channel, channelDef, scaleName, scale, stack, defaultRef) {
if (fielddef_1.isFieldDef(channelDef) && stack && channel === stack.fieldChannel) {
// x or y use stack_end so that stacked line's point mark use stack_end too.
return fieldRef(channelDef, scaleName, { suffix: 'end' });
}
return midPoint(channel, channelDef, scaleName, scale, stack, defaultRef);
}
exports.stackable = stackable;
/**
* @return Vega ValueRef for stackable x2 or y2
*/
function stackable2(channel, aFieldDef, a2fieldDef, scaleName, scale, stack, defaultRef) {
if (fielddef_1.isFieldDef(aFieldDef) && stack &&
// If fieldChannel is X and channel is X2 (or Y and Y2)
channel.charAt(0) === stack.fieldChannel.charAt(0)) {
return fieldRef(aFieldDef, scaleName, { suffix: 'start' });
}
return midPoint(channel, a2fieldDef, scaleName, scale, stack, defaultRef);
}
exports.stackable2 = stackable2;
/**
* Value Ref for binned fields
*/
function bin(fieldDef, scaleName, side, offset) {
var binSuffix = side === 'start' ? undefined : 'end';
return fieldRef(fieldDef, scaleName, { binSuffix: binSuffix }, offset ? { offset: offset } : {});
}
exports.bin = bin;
function fieldRef(fieldDef, scaleName, opt, mixins) {
var ref = {
scale: scaleName,
field: fielddef_1.field(fieldDef, opt),
};
if (mixins) {
return tslib_1.__assign({}, ref, mixins);
}
return ref;
}
exports.fieldRef = fieldRef;
function band(scaleName, band) {
if (band === void 0) { band = true; }
return {
scale: scaleName,
band: band
};
}
exports.band = band;
/**
* Signal that returns the middle of a bin. Should only be used with x and y.
*/
function binMidSignal(fieldDef, scaleName) {
return {
signal: "(" +
("scale(\"" + scaleName + "\", " + fielddef_1.field(fieldDef, { expr: 'datum' }) + ")") +
" + " +
("scale(\"" + scaleName + "\", " + fielddef_1.field(fieldDef, { binSuffix: 'end', expr: 'datum' }) + ")") +
")/2"
};
}
/**
* @returns {VgValueRef} Value Ref for xc / yc or mid point for other channels.
*/
function midPoint(channel, channelDef, scaleName, scale, stack, defaultRef) {
// TODO: datum support
if (channelDef) {
/* istanbul ignore else */
if (fielddef_1.isFieldDef(channelDef)) {
if (channelDef.bin) {
// Use middle only for x an y to place marks in the center between start and end of the bin range.
// We do not use the mid point for other channels (e.g. size) so that properties of legends and marks match.
if (util_1.contains(['x', 'y'], channel) && channelDef.type === 'quantitative') {
if (stack && stack.impute) {
// For stack, we computed bin_mid so we can impute.
return fieldRef(channelDef, scaleName, { binSuffix: 'mid' });
}
// For non-stack, we can just calculate bin mid on the fly using signal.
return binMidSignal(channelDef, scaleName);
}
return fieldRef(channelDef, scaleName, common_1.binRequiresRange(channelDef, channel) ? { binSuffix: 'range' } : {});
}
var scaleType = scale.get('type');
if (scale_1.hasDiscreteDomain(scaleType)) {
if (scaleType === 'band') {
// For band, to get mid point, need to offset by half of the band
return fieldRef(channelDef, scaleName, { binSuffix: 'range' }, { band: 0.5 });
}
return fieldRef(channelDef, scaleName, { binSuffix: 'range' });
}
else {
return fieldRef(channelDef, scaleName, {}); // no need for bin suffix
}
}
else if (fielddef_1.isValueDef(channelDef)) {
return { value: channelDef.value };
}
else {
throw new Error('FieldDef without field or value.'); // FIXME add this to log.message
}
}
if (defaultRef === 'zeroOrMin') {
/* istanbul ignore else */
if (channel === channel_1.X || channel === channel_1.X2) {
return zeroOrMinX(scaleName, scale);
}
else if (channel === channel_1.Y || channel === channel_1.Y2) {
return zeroOrMinY(scaleName, scale);
}
else {
throw new Error("Unsupported channel " + channel + " for base function"); // FIXME add this to log.message
}
}
else if (defaultRef === 'zeroOrMax') {
/* istanbul ignore else */
if (channel === channel_1.X || channel === channel_1.X2) {
return zeroOrMaxX(scaleName, scale);
}
else if (channel === channel_1.Y || channel === channel_1.Y2) {
return zeroOrMaxY(scaleName, scale);
}
else {
throw new Error("Unsupported channel " + channel + " for base function"); // FIXME add this to log.message
}
}
return defaultRef;
}
exports.midPoint = midPoint;
function text(textDef, config) {
// text
if (textDef) {
if (fielddef_1.isFieldDef(textDef)) {
return common_1.formatSignalRef(textDef, textDef.format, 'datum', config);
}
else if (fielddef_1.isValueDef(textDef)) {
return { value: textDef.value };
}
}
return undefined;
}
exports.text = text;
function mid(sizeRef) {
return tslib_1.__assign({}, sizeRef, { mult: 0.5 });
}
exports.mid = mid;
function zeroOrMinX(scaleName, scale) {
if (scaleName) {
// Log / Time / UTC scale do not support zero
if (!util_1.contains([scale_1.ScaleType.LOG, scale_1.ScaleType.TIME, scale_1.ScaleType.UTC], scale.get('type')) &&
scale.get('zero') !== false) {
return {
scale: scaleName,
value: 0
};
}
}
// Put the mark on the x-axis
return { value: 0 };
}
/**
* @returns {VgValueRef} base value if scale exists and return max value if scale does not exist
*/
function zeroOrMaxX(scaleName, scale) {
if (scaleName) {
// Log / Time / UTC scale do not support zero
if (!util_1.contains([scale_1.ScaleType.LOG, scale_1.ScaleType.TIME, scale_1.ScaleType.UTC], scale.get('type')) &&
scale.get('zero') !== false) {
return {
scale: scaleName,
value: 0
};
}
}
return { field: { group: 'width' } };
}
function zeroOrMinY(scaleName, scale) {
if (scaleName) {
// Log / Time / UTC scale do not support zero
if (!util_1.contains([scale_1.ScaleType.LOG, scale_1.ScaleType.TIME, scale_1.ScaleType.UTC], scale.get('type')) &&
scale.get('zero') !== false) {
return {
scale: scaleName,
value: 0
};
}
}
// Put the mark on the y-axis
return { field: { group: 'height' } };
}
/**
* @returns {VgValueRef} base value if scale exists and return max value if scale does not exist
*/
function zeroOrMaxY(scaleName, scale) {
if (scaleName) {
// Log / Time / UTC scale do not support zero
if (!util_1.contains([scale_1.ScaleType.LOG, scale_1.ScaleType.TIME, scale_1.ScaleType.UTC], scale.get('type')) &&
scale.get('zero') !== false) {
return {
scale: scaleName,
value: 0
};
}
}
// Put the mark on the y-axis
return { value: 0 };
}
},{"../../channel":12,"../../fielddef":96,"../../scale":104,"../../util":114,"../common":20,"tslib":5}],63:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var vega_util_1 = require("vega-util");
var channel_1 = require("../channel");
var encoding_1 = require("../encoding");
var fielddef_1 = require("../fielddef");
var log = require("../log");
var scale_1 = require("../scale");
var title_1 = require("../title");
var transform_1 = require("../transform");
var util_1 = require("../util");
var vega_schema_1 = require("../vega.schema");
var assemble_1 = require("./axis/assemble");
var header_1 = require("./layout/header");
var assemble_2 = require("./layoutsize/assemble");
var assemble_3 = require("./legend/assemble");
var parse_1 = require("./legend/parse");
var mark_1 = require("./mark/mark");
var assemble_4 = require("./scale/assemble");
var domain_1 = require("./scale/domain");
var parse_2 = require("./scale/parse");
var split_1 = require("./split");
var NameMap = /** @class */ (function () {
function NameMap() {
this.nameMap = {};
}
NameMap.prototype.rename = function (oldName, newName) {
this.nameMap[oldName] = newName;
};
NameMap.prototype.has = function (name) {
return this.nameMap[name] !== undefined;
};
NameMap.prototype.get = function (name) {
// If the name appears in the _nameMap, we need to read its new name.
// We have to loop over the dict just in case the new name also gets renamed.
while (this.nameMap[name] && name !== this.nameMap[name]) {
name = this.nameMap[name];
}
return name;
};
return NameMap;
}());
exports.NameMap = NameMap;
/*
We use type guards instead of `instanceof` as `instanceof` makes
different parts of the compiler depend on the actual implementation of
the model classes, which in turn depend on different parts of the compiler.
Thus, `instanceof` leads to circular dependency problems.
On the other hand, type guards only make different parts of the compiler
depend on the type of the model classes, but not the actual implementation.
*/
function isUnitModel(model) {
return model && model.type === 'unit';
}
exports.isUnitModel = isUnitModel;
function isFacetModel(model) {
return model && model.type === 'facet';
}
exports.isFacetModel = isFacetModel;
function isRepeatModel(model) {
return model && model.type === 'repeat';
}
exports.isRepeatModel = isRepeatModel;
function isConcatModel(model) {
return model && model.type === 'concat';
}
exports.isConcatModel = isConcatModel;
function isLayerModel(model) {
return model && model.type === 'layer';
}
exports.isLayerModel = isLayerModel;
var Model = /** @class */ (function () {
function Model(spec, parent, parentGivenName, config, resolve) {
var _this = this;
this.children = [];
/**
* Corrects the data references in marks after assemble.
*/
this.correctDataNames = function (mark) {
// TODO: make this correct
// for normal data references
if (mark.from && mark.from.data) {
mark.from.data = _this.lookupDataSource(mark.from.data);
}
// for access to facet data
if (mark.from && mark.from.facet && mark.from.facet.data) {
mark.from.facet.data = _this.lookupDataSource(mark.from.facet.data);
}
return mark;
};
this.parent = parent;
this.config = config;
// If name is not provided, always use parent's givenName to avoid name conflicts.
this.name = spec.name || parentGivenName;
this.title = vega_util_1.isString(spec.title) ? { text: spec.title } : spec.title;
// Shared name maps
this.scaleNameMap = parent ? parent.scaleNameMap : new NameMap();
this.layoutSizeNameMap = parent ? parent.layoutSizeNameMap : new NameMap();
this.data = spec.data;
this.description = spec.description;
this.transforms = transform_1.normalizeTransform(spec.transform || []);
this.component = {
data: {
sources: parent ? parent.component.data.sources : {},
outputNodes: parent ? parent.component.data.outputNodes : {},
outputNodeRefCounts: parent ? parent.component.data.outputNodeRefCounts : {},
ancestorParse: parent ? tslib_1.__assign({}, parent.component.data.ancestorParse) : {}
},
layoutSize: new split_1.Split(),
layoutHeaders: { row: {}, column: {} },
mark: null,
resolve: tslib_1.__assign({ scale: {}, axis: {}, legend: {} }, (resolve || {})),
selection: null,
scales: null,
axes: {},
legends: {},
};
}
Object.defineProperty(Model.prototype, "width", {
get: function () {
return this.getSizeSignalRef('width');
},
enumerable: true,
configurable: true
});
Object.defineProperty(Model.prototype, "height", {
get: function () {
return this.getSizeSignalRef('height');
},
enumerable: true,
configurable: true
});
Model.prototype.initSize = function (size) {
var width = size.width, height = size.height;
if (width) {
this.component.layoutSize.set('width', width, true);
}
if (height) {
this.component.layoutSize.set('height', height, true);
}
};
Model.prototype.parse = function () {
this.parseScale();
this.parseMarkDef();
this.parseLayoutSize(); // depends on scale
this.renameTopLevelLayoutSize();
this.parseSelection();
this.parseData(); // (pathorder) depends on markDef; selection filters depend on parsed selections.
this.parseAxisAndHeader(); // depends on scale and layout size
this.parseLegend(); // depends on scale, markDef
this.parseMarkGroup(); // depends on data name, scale, layout size, axisGroup, and children's scale, axis, legend and mark.
};
Model.prototype.parseScale = function () {
parse_2.parseScale(this);
};
/**
* Rename top-level spec's size to be just width / height, ignoring model name.
* This essentially merges the top-level spec's width/height signals with the width/height signals
* to help us reduce redundant signals declaration.
*/
Model.prototype.renameTopLevelLayoutSize = function () {
if (this.getName('width') !== 'width') {
this.renameLayoutSize(this.getName('width'), 'width');
}
if (this.getName('height') !== 'height') {
this.renameLayoutSize(this.getName('height'), 'height');
}
};
Model.prototype.parseMarkDef = function () {
mark_1.parseMarkDef(this);
};
Model.prototype.parseLegend = function () {
parse_1.parseLegend(this);
};
Model.prototype.assembleGroupStyle = function () {
if (this.type === 'unit' || this.type === 'layer') {
return 'cell';
}
return undefined;
};
Model.prototype.assembleLayoutSize = function () {
if (this.type === 'unit' || this.type === 'layer') {
return {
width: this.getSizeSignalRef('width'),
height: this.getSizeSignalRef('height')
};
}
return undefined;
};
Model.prototype.assembleHeaderMarks = function () {
var layoutHeaders = this.component.layoutHeaders;
var headerMarks = [];
for (var _i = 0, HEADER_CHANNELS_1 = header_1.HEADER_CHANNELS; _i < HEADER_CHANNELS_1.length; _i++) {
var channel = HEADER_CHANNELS_1[_i];
if (layoutHeaders[channel].title) {
headerMarks.push(header_1.getTitleGroup(this, channel));
}
}
for (var _a = 0, HEADER_CHANNELS_2 = header_1.HEADER_CHANNELS; _a < HEADER_CHANNELS_2.length; _a++) {
var channel = HEADER_CHANNELS_2[_a];
var layoutHeader = layoutHeaders[channel];
for (var _b = 0, HEADER_TYPES_1 = header_1.HEADER_TYPES; _b < HEADER_TYPES_1.length; _b++) {
var headerType = HEADER_TYPES_1[_b];
if (layoutHeader[headerType]) {
for (var _c = 0, _d = layoutHeader[headerType]; _c < _d.length; _c++) {
var header = _d[_c];
var headerGroup = header_1.getHeaderGroup(this, channel, headerType, layoutHeader, header);
if (headerGroup) {
headerMarks.push(headerGroup);
}
}
}
}
}
return headerMarks;
};
Model.prototype.assembleAxes = function () {
return assemble_1.assembleAxes(this.component.axes);
};
Model.prototype.assembleLegends = function () {
return assemble_3.assembleLegends(this);
};
Model.prototype.assembleTitle = function () {
var title = tslib_1.__assign({}, title_1.extractTitleConfig(this.config.title).nonMark, this.title);
if (title.text) {
if (!util_1.contains(['unit', 'layer'], this.type)) {
// As described in https://github.com/vega/vega-lite/issues/2875:
// Due to vega/vega#960 (comment), we only support title's anchor for unit and layered spec for now.
if (title.anchor && title.anchor !== 'start') {
log.warn(log.message.cannotSetTitleAnchor(this.type));
}
title.anchor = 'start';
}
return util_1.keys(title).length > 0 ? title : undefined;
}
return undefined;
};
/**
* Assemble the mark group for this model. We accept optional `signals` so that we can include concat top-level signals with the top-level model's local signals.
*/
Model.prototype.assembleGroup = function (signals) {
if (signals === void 0) { signals = []; }
var group = {};
signals = signals.concat(this.assembleSelectionSignals());
if (signals.length > 0) {
group.signals = signals;
}
var layout = this.assembleLayout();
if (layout) {
group.layout = layout;
}
group.marks = [].concat(this.assembleHeaderMarks(), this.assembleMarks());
// Only include scales if this spec is top-level or if parent is facet.
// (Otherwise, it will be merged with upper-level's scope.)
var scales = (!this.parent || isFacetModel(this.parent)) ? assemble_4.assembleScales(this) : [];
if (scales.length > 0) {
group.scales = scales;
}
var axes = this.assembleAxes();
if (axes.length > 0) {
group.axes = axes;
}
var legends = this.assembleLegends();
if (legends.length > 0) {
group.legends = legends;
}
return group;
};
Model.prototype.hasDescendantWithFieldOnChannel = function (channel) {
for (var _i = 0, _a = this.children; _i < _a.length; _i++) {
var child = _a[_i];
if (isUnitModel(child)) {
if (child.channelHasField(channel)) {
return true;
}
}
else {
if (child.hasDescendantWithFieldOnChannel(channel)) {
return true;
}
}
}
return false;
};
Model.prototype.getName = function (text) {
return util_1.varName((this.name ? this.name + '_' : '') + text);
};
/**
* Request a data source name for the given data source type and mark that data source as required. This method should be called in parse, so that all used data source can be correctly instantiated in assembleData().
*/
Model.prototype.requestDataName = function (name) {
var fullName = this.getName(name);
// Increase ref count. This is critical because otherwise we won't create a data source.
// We also increase the ref counts on OutputNode.getSource() calls.
var refCounts = this.component.data.outputNodeRefCounts;
refCounts[fullName] = (refCounts[fullName] || 0) + 1;
return fullName;
};
Model.prototype.getSizeSignalRef = function (sizeType) {
if (isFacetModel(this.parent)) {
var channel = sizeType === 'width' ? 'x' : 'y';
var scaleComponent = this.component.scales[channel];
if (scaleComponent && !scaleComponent.merged) {
var type = scaleComponent.get('type');
var range = scaleComponent.get('range');
if (scale_1.hasDiscreteDomain(type) && vega_schema_1.isVgRangeStep(range)) {
var scaleName = scaleComponent.get('name');
var domain = domain_1.assembleDomain(this, channel);
var fieldName = domain_1.getFieldFromDomain(domain);
if (fieldName) {
var fieldRef = fielddef_1.field({ aggregate: 'distinct', field: fieldName }, { expr: 'datum' });
return {
signal: assemble_2.sizeExpr(scaleName, scaleComponent, fieldRef)
};
}
else {
log.warn('Unknown field for ${channel}. Cannot calculate view size.');
return null;
}
}
}
}
return {
signal: this.layoutSizeNameMap.get(this.getName(sizeType))
};
};
/**
* Lookup the name of the datasource for an output node. You probably want to call this in assemble.
*/
Model.prototype.lookupDataSource = function (name) {
var node = this.component.data.outputNodes[name];
if (!node) {
// Name not found in map so let's just return what we got.
// This can happen if we already have the correct name.
return name;
}
return node.getSource();
};
Model.prototype.getSizeName = function (oldSizeName) {
return this.layoutSizeNameMap.get(oldSizeName);
};
Model.prototype.renameLayoutSize = function (oldName, newName) {
this.layoutSizeNameMap.rename(oldName, newName);
};
Model.prototype.renameScale = function (oldName, newName) {
this.scaleNameMap.rename(oldName, newName);
};
/**
* @return scale name for a given channel after the scale has been parsed and named.
*/
Model.prototype.scaleName = function (originalScaleName, parse) {
if (parse) {
// During the parse phase always return a value
// No need to refer to rename map because a scale can't be renamed
// before it has the original name.
return this.getName(originalScaleName);
}
// If there is a scale for the channel, it should either
// be in the scale component or exist in the name map
if (
// If there is a scale for the channel, there should be a local scale component for it
(channel_1.isChannel(originalScaleName) && channel_1.isScaleChannel(originalScaleName) && this.component.scales[originalScaleName]) ||
// in the scale name map (the the scale get merged by its parent)
this.scaleNameMap.has(this.getName(originalScaleName))) {
return this.scaleNameMap.get(this.getName(originalScaleName));
}
return undefined;
};
/**
* Traverse a model's hierarchy to get the scale component for a particular channel.
*/
Model.prototype.getScaleComponent = function (channel) {
/* istanbul ignore next: This is warning for debugging test */
if (!this.component.scales) {
throw new Error('getScaleComponent cannot be called before parseScale(). Make sure you have called parseScale or use parseUnitModelWithScale().');
}
var localScaleComponent = this.component.scales[channel];
if (localScaleComponent && !localScaleComponent.merged) {
return localScaleComponent;
}
return (this.parent ? this.parent.getScaleComponent(channel) : undefined);
};
/**
* Traverse a model's hierarchy to get a particular selection component.
*/
Model.prototype.getSelectionComponent = function (varName, origName) {
var sel = this.component.selection[varName];
if (!sel && this.parent) {
sel = this.parent.getSelectionComponent(varName, origName);
}
if (!sel) {
throw new Error(log.message.selectionNotFound(origName));
}
return sel;
};
return Model;
}());
exports.Model = Model;
/** Abstract class for UnitModel and FacetModel. Both of which can contain fieldDefs as a part of its own specification. */
var ModelWithField = /** @class */ (function (_super) {
tslib_1.__extends(ModelWithField, _super);
function ModelWithField() {
return _super !== null && _super.apply(this, arguments) || this;
}
/** Get "field" reference for vega */
ModelWithField.prototype.field = function (channel, opt) {
if (opt === void 0) { opt = {}; }
var fieldDef = this.fieldDef(channel);
if (!fieldDef) {
return undefined;
}
return fielddef_1.field(fieldDef, opt);
};
ModelWithField.prototype.reduceFieldDef = function (f, init, t) {
return encoding_1.reduce(this.getMapping(), function (acc, cd, c) {
var fieldDef = fielddef_1.getFieldDef(cd);
if (fieldDef) {
return f(acc, fieldDef, c);
}
return acc;
}, init, t);
};
ModelWithField.prototype.forEachFieldDef = function (f, t) {
encoding_1.forEach(this.getMapping(), function (cd, c) {
var fieldDef = fielddef_1.getFieldDef(cd);
if (fieldDef) {
f(fieldDef, c);
}
}, t);
};
return ModelWithField;
}(Model));
exports.ModelWithField = ModelWithField;
},{"../channel":12,"../encoding":94,"../fielddef":96,"../log":101,"../scale":104,"../title":110,"../transform":112,"../util":114,"../vega.schema":116,"./axis/assemble":13,"./layout/header":43,"./layoutsize/assemble":44,"./legend/assemble":46,"./legend/parse":49,"./mark/mark":55,"./scale/assemble":67,"./scale/domain":69,"./scale/parse":70,"./split":86,"tslib":5,"vega-util":7}],64:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var baseconcat_1 = require("./baseconcat");
var buildmodel_1 = require("./buildmodel");
var parse_1 = require("./layoutsize/parse");
var RepeatModel = /** @class */ (function (_super) {
tslib_1.__extends(RepeatModel, _super);
function RepeatModel(spec, parent, parentGivenName, repeatValues, config) {
var _this = _super.call(this, spec, parent, parentGivenName, config, spec.resolve) || this;
_this.type = 'repeat';
_this.repeat = spec.repeat;
_this.children = _this._initChildren(spec, _this.repeat, repeatValues, config);
return _this;
}
RepeatModel.prototype._initChildren = function (spec, repeat, repeater, config) {
var children = [];
var row = repeat.row || [repeater ? repeater.row : null];
var column = repeat.column || [repeater ? repeater.column : null];
// cross product
for (var _i = 0, row_1 = row; _i < row_1.length; _i++) {
var rowField = row_1[_i];
for (var _a = 0, column_1 = column; _a < column_1.length; _a++) {
var columnField = column_1[_a];
var name_1 = (rowField ? '_' + rowField : '') + (columnField ? '_' + columnField : '');
var childRepeat = {
row: rowField,
column: columnField
};
children.push(buildmodel_1.buildModel(spec.spec, this, this.getName('child' + name_1), undefined, childRepeat, config));
}
}
return children;
};
RepeatModel.prototype.parseLayoutSize = function () {
parse_1.parseRepeatLayoutSize(this);
};
RepeatModel.prototype.assembleLayout = function () {
// TODO: allow customization
return {
padding: { row: 10, column: 10 },
offset: 10,
columns: this.repeat && this.repeat.column ? this.repeat.column.length : 1,
bounds: 'full',
align: 'all'
};
};
return RepeatModel;
}(baseconcat_1.BaseConcatModel));
exports.RepeatModel = RepeatModel;
},{"./baseconcat":18,"./buildmodel":19,"./layoutsize/parse":45,"tslib":5}],65:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var vega_util_1 = require("vega-util");
var fielddef_1 = require("../fielddef");
var log = require("../log");
function replaceRepeaterInFacet(facet, repeater) {
return replaceRepeater(facet, repeater);
}
exports.replaceRepeaterInFacet = replaceRepeaterInFacet;
function replaceRepeaterInEncoding(encoding, repeater) {
return replaceRepeater(encoding, repeater);
}
exports.replaceRepeaterInEncoding = replaceRepeaterInEncoding;
/**
* Replace repeater values in a field def with the concrete field name.
*/
function replaceRepeaterInFieldDef(fieldDef, repeater) {
var field = fieldDef.field;
if (fielddef_1.isRepeatRef(field)) {
if (field.repeat in repeater) {
return tslib_1.__assign({}, fieldDef, { field: repeater[field.repeat] });
}
else {
log.warn(log.message.noSuchRepeatedValue(field.repeat));
return null;
}
}
else {
// field is not a repeat ref so we can just return the field def
return fieldDef;
}
}
function replaceRepeater(mapping, repeater) {
var out = {};
for (var channel in mapping) {
if (mapping.hasOwnProperty(channel)) {
var fieldDef = mapping[channel];
if (vega_util_1.isArray(fieldDef)) {
out[channel] = fieldDef.map(function (fd) { return replaceRepeaterInFieldDef(fd, repeater); })
.filter(function (fd) { return fd !== null; });
}
else {
var fd = replaceRepeaterInFieldDef(fieldDef, repeater);
if (fd !== null) {
out[channel] = fd;
}
}
}
}
return out;
}
},{"../fielddef":96,"../log":101,"tslib":5,"vega-util":7}],66:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var channel_1 = require("../channel");
var log = require("../log");
var util_1 = require("../util");
var model_1 = require("./model");
function defaultScaleResolve(channel, model) {
if (model_1.isLayerModel(model) || model_1.isFacetModel(model)) {
return 'shared';
}
else if (model_1.isConcatModel(model) || model_1.isRepeatModel(model)) {
return util_1.contains(channel_1.SPATIAL_SCALE_CHANNELS, channel) ? 'independent' : 'shared';
}
/* istanbul ignore next: should never reach here. */
throw new Error('invalid model type for resolve');
}
exports.defaultScaleResolve = defaultScaleResolve;
function parseGuideResolve(resolve, channel) {
var channelScaleResolve = resolve.scale[channel];
var guide = util_1.contains(channel_1.SPATIAL_SCALE_CHANNELS, channel) ? 'axis' : 'legend';
if (channelScaleResolve === 'independent') {
if (resolve[guide][channel] === 'shared') {
log.warn(log.message.independentScaleMeansIndependentGuide(channel));
}
return 'independent';
}
return resolve[guide][channel] || 'shared';
}
exports.parseGuideResolve = parseGuideResolve;
},{"../channel":12,"../log":101,"../util":114,"./model":63}],67:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var vega_util_1 = require("vega-util");
var util_1 = require("../../util");
var vega_schema_1 = require("../../vega.schema");
var model_1 = require("../model");
var selection_1 = require("../selection/selection");
var domain_1 = require("./domain");
function assembleScales(model) {
if (model_1.isLayerModel(model) || model_1.isConcatModel(model) || model_1.isRepeatModel(model)) {
// For concat / layer / repeat, include scales of children too
return model.children.reduce(function (scales, child) {
return scales.concat(assembleScales(child));
}, assembleScalesForModel(model));
}
else {
// For facet, child scales would not be included in the parent's scope.
// For unit, there is no child.
return assembleScalesForModel(model);
}
}
exports.assembleScales = assembleScales;
function assembleScalesForModel(model) {
return util_1.keys(model.component.scales).reduce(function (scales, channel) {
var scaleComponent = model.component.scales[channel];
if (scaleComponent.merged) {
// Skipped merged scales
return scales;
}
var scale = scaleComponent.combine();
// need to separate const and non const object destruction
var domainRaw = scale.domainRaw, range = scale.range;
var name = scale.name, type = scale.type, _d = scale.domainRaw, _r = scale.range, otherScaleProps = tslib_1.__rest(scale, ["name", "type", "domainRaw", "range"]);
range = assembleScaleRange(range, name, model, channel);
// As scale parsing occurs before selection parsing, a temporary signal
// is used for domainRaw. Here, we detect if this temporary signal
// is set, and replace it with the correct domainRaw signal.
// For more information, see isRawSelectionDomain in selection.ts.
if (domainRaw && selection_1.isRawSelectionDomain(domainRaw)) {
domainRaw = selection_1.selectionScaleDomain(model, domainRaw);
}
scales.push(tslib_1.__assign({ name: name,
type: type, domain: domain_1.assembleDomain(model, channel) }, (domainRaw ? { domainRaw: domainRaw } : {}), { range: range }, otherScaleProps));
return scales;
}, []);
}
exports.assembleScalesForModel = assembleScalesForModel;
function assembleScaleRange(scaleRange, scaleName, model, channel) {
// add signals to x/y range
if (channel === 'x' || channel === 'y') {
if (vega_schema_1.isVgRangeStep(scaleRange)) {
// For x/y range step, use a signal created in layout assemble instead of a constant range step.
return {
step: { signal: scaleName + '_step' }
};
}
else if (vega_util_1.isArray(scaleRange) && scaleRange.length === 2) {
var r0 = scaleRange[0];
var r1 = scaleRange[1];
if (r0 === 0 && vega_schema_1.isVgSignalRef(r1)) {
// Replace width signal just in case it is renamed.
return [0, { signal: model.getSizeName(r1.signal) }];
}
else if (vega_schema_1.isVgSignalRef(r0) && r1 === 0) {
// Replace height signal just in case it is renamed.
return [{ signal: model.getSizeName(r0.signal) }, 0];
}
}
}
return scaleRange;
}
exports.assembleScaleRange = assembleScaleRange;
},{"../../util":114,"../../vega.schema":116,"../model":63,"../selection/selection":76,"./domain":69,"tslib":5,"vega-util":7}],68:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var split_1 = require("../split");
var ScaleComponent = /** @class */ (function (_super) {
tslib_1.__extends(ScaleComponent, _super);
function ScaleComponent(name, typeWithExplicit) {
var _this = _super.call(this, {}, // no initial explicit property
{ name: name } // name as initial implicit property
) || this;
_this.merged = false;
_this.domains = [];
_this.setWithExplicit('type', typeWithExplicit);
return _this;
}
return ScaleComponent;
}(split_1.Split));
exports.ScaleComponent = ScaleComponent;
},{"../split":86,"tslib":5}],69:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var vega_util_1 = require("vega-util");
var aggregate_1 = require("../../aggregate");
var bin_1 = require("../../bin");
var channel_1 = require("../../channel");
var data_1 = require("../../data");
var datetime_1 = require("../../datetime");
var log = require("../../log");
var scale_1 = require("../../scale");
var sort_1 = require("../../sort");
var util = require("../../util");
var vega_schema_1 = require("../../vega.schema");
var vega_schema_2 = require("../../vega.schema");
var common_1 = require("../common");
var optimize_1 = require("../data/optimize");
var model_1 = require("../model");
var selection_1 = require("../selection/selection");
function parseScaleDomain(model) {
if (model_1.isUnitModel(model)) {
parseUnitScaleDomain(model);
}
else {
parseNonUnitScaleDomain(model);
}
}
exports.parseScaleDomain = parseScaleDomain;
function parseUnitScaleDomain(model) {
var scales = model.specifiedScales;
var localScaleComponents = model.component.scales;
util.keys(localScaleComponents).forEach(function (channel) {
var specifiedScale = scales[channel];
var specifiedDomain = specifiedScale ? specifiedScale.domain : undefined;
var domains = parseDomainForChannel(model, channel);
var localScaleCmpt = localScaleComponents[channel];
localScaleCmpt.domains = domains;
if (scale_1.isSelectionDomain(specifiedDomain)) {
// As scale parsing occurs before selection parsing, we use a temporary
// signal here and append the scale.domain definition. This is replaced
// with the correct domainRaw signal during scale assembly.
// For more information, see isRawSelectionDomain in selection.ts.
// FIXME: replace this with a special property in the scaleComponent
localScaleCmpt.set('domainRaw', {
signal: selection_1.SELECTION_DOMAIN + JSON.stringify(specifiedDomain)
}, true);
}
});
}
function parseNonUnitScaleDomain(model) {
for (var _i = 0, _a = model.children; _i < _a.length; _i++) {
var child = _a[_i];
parseScaleDomain(child);
}
var localScaleComponents = model.component.scales;
util.keys(localScaleComponents).forEach(function (channel) {
// FIXME: Arvind -- Please revise logic for merging selectionDomain / domainRaw
var domains;
for (var _i = 0, _a = model.children; _i < _a.length; _i++) {
var child = _a[_i];
var childComponent = child.component.scales[channel];
if (childComponent) {
if (domains === undefined) {
domains = childComponent.domains;
}
else {
domains = domains.concat(childComponent.domains);
}
}
}
if (model_1.isFacetModel(model)) {
domains.forEach(function (domain) {
// Replace the scale domain with data output from a cloned subtree after the facet.
if (vega_schema_1.isDataRefDomain(domain)) {
// use data from cloned subtree (which is the same as data but with a prefix added once)
domain.data = optimize_1.FACET_SCALE_PREFIX + domain.data.replace(optimize_1.FACET_SCALE_PREFIX, '');
}
});
}
localScaleComponents[channel].domains = domains;
});
}
/**
* Remove unaggregated domain if it is not applicable
* Add unaggregated domain if domain is not specified and config.scale.useUnaggregatedDomain is true.
*/
function normalizeUnaggregatedDomain(domain, fieldDef, scaleType, scaleConfig) {
if (domain === 'unaggregated') {
var _a = canUseUnaggregatedDomain(fieldDef, scaleType), valid = _a.valid, reason = _a.reason;
if (!valid) {
log.warn(reason);
return undefined;
}
}
else if (domain === undefined && scaleConfig.useUnaggregatedDomain) {
// Apply config if domain is not specified.
var valid = canUseUnaggregatedDomain(fieldDef, scaleType).valid;
if (valid) {
return 'unaggregated';
}
}
return domain;
}
function parseDomainForChannel(model, channel) {
var scaleType = model.getScaleComponent(channel).get('type');
var domain = normalizeUnaggregatedDomain(model.scaleDomain(channel), model.fieldDef(channel), scaleType, model.config.scale);
if (domain !== model.scaleDomain(channel)) {
model.specifiedScales[channel] = tslib_1.__assign({}, model.specifiedScales[channel], { domain: domain });
}
// If channel is either X or Y then union them with X2 & Y2 if they exist
if (channel === 'x' && model.channelHasField('x2')) {
if (model.channelHasField('x')) {
return parseSingleChannelDomain(scaleType, domain, model, 'x').concat(parseSingleChannelDomain(scaleType, domain, model, 'x2'));
}
else {
return parseSingleChannelDomain(scaleType, domain, model, 'x2');
}
}
else if (channel === 'y' && model.channelHasField('y2')) {
if (model.channelHasField('y')) {
return parseSingleChannelDomain(scaleType, domain, model, 'y').concat(parseSingleChannelDomain(scaleType, domain, model, 'y2'));
}
else {
return parseSingleChannelDomain(scaleType, domain, model, 'y2');
}
}
return parseSingleChannelDomain(scaleType, domain, model, channel);
}
exports.parseDomainForChannel = parseDomainForChannel;
function parseSingleChannelDomain(scaleType, domain, model, channel) {
var fieldDef = model.fieldDef(channel);
if (domain && domain !== 'unaggregated' && !scale_1.isSelectionDomain(domain)) {
if (fieldDef.bin) {
log.warn(log.message.conflictedDomain(channel));
}
else {
if (datetime_1.isDateTime(domain[0])) {
return domain.map(function (dt) {
return { signal: "{data: " + datetime_1.dateTimeExpr(dt, true) + "}" };
});
}
return [domain];
}
}
var stack = model.stack;
if (stack && channel === stack.fieldChannel) {
if (stack.offset === 'normalize') {
return [[0, 1]];
}
var data = model.requestDataName(data_1.MAIN);
return [{
data: data,
field: model.field(channel, { suffix: 'start' })
}, {
data: data,
field: model.field(channel, { suffix: 'end' })
}];
}
var sort = channel_1.isScaleChannel(channel) ? domainSort(model, channel, scaleType) : undefined;
if (domain === 'unaggregated') {
var data = model.requestDataName(data_1.MAIN);
return [{
data: data,
field: model.field(channel, { aggregate: 'min' })
}, {
data: data,
field: model.field(channel, { aggregate: 'max' })
}];
}
else if (fieldDef.bin) {
if (scale_1.isBinScale(scaleType)) {
var signal = model.getName(bin_1.binToString(fieldDef.bin) + "_" + fieldDef.field + "_bins");
return [{ signal: "sequence(" + signal + ".start, " + signal + ".stop + " + signal + ".step, " + signal + ".step)" }];
}
if (scale_1.hasDiscreteDomain(scaleType)) {
// ordinal bin scale takes domain from bin_range, ordered by bin start
// This is useful for both axis-based scale (x/y) and legend-based scale (other channels).
return [{
// If sort by aggregation of a specified sort field, we need to use RAW table,
// so we can aggregate values for the scale independently from the main aggregation.
data: util.isBoolean(sort) ? model.requestDataName(data_1.MAIN) : model.requestDataName(data_1.RAW),
// Use range if we added it and the scale does not support computing a range as a signal.
field: model.field(channel, common_1.binRequiresRange(fieldDef, channel) ? { binSuffix: 'range' } : {}),
// we have to use a sort object if sort = true to make the sort correct by bin start
sort: sort === true || !sort_1.isSortField(sort) ? {
field: model.field(channel, {}),
op: 'min' // min or max doesn't matter since we sort by the start of the bin range
} : sort
}];
}
else {
if (channel === 'x' || channel === 'y') {
// X/Y position have to include start and end for non-ordinal scale
var data = model.requestDataName(data_1.MAIN);
return [{
data: data,
field: model.field(channel, {})
}, {
data: data,
field: model.field(channel, { binSuffix: 'end' })
}];
}
else {
// TODO: use bin_mid
return [{
data: model.requestDataName(data_1.MAIN),
field: model.field(channel, {})
}];
}
}
}
else if (sort) {
return [{
// If sort by aggregation of a specified sort field, we need to use RAW table,
// so we can aggregate values for the scale independently from the main aggregation.
data: util.isBoolean(sort) ? model.requestDataName(data_1.MAIN) : model.requestDataName(data_1.RAW),
field: model.field(channel),
sort: sort
}];
}
else {
return [{
data: model.requestDataName(data_1.MAIN),
field: model.field(channel)
}];
}
}
function domainSort(model, channel, scaleType) {
if (!scale_1.hasDiscreteDomain(scaleType)) {
return undefined;
}
var sort = model.sort(channel);
// Sorted based on an aggregate calculation over a specified sort field (only for ordinal scale)
if (sort_1.isSortField(sort)) {
return sort;
}
if (sort === 'descending') {
return {
op: 'min',
field: model.field(channel),
order: 'descending'
};
}
if (util.contains(['ascending', undefined /* default =ascending*/], sort)) {
return true;
}
// sort === 'none'
return undefined;
}
exports.domainSort = domainSort;
/**
* Determine if a scale can use unaggregated domain.
* @return {Boolean} Returns true if all of the following conditons applies:
* 1. `scale.domain` is `unaggregated`
* 2. Aggregation function is not `count` or `sum`
* 3. The scale is quantitative or time scale.
*/
function canUseUnaggregatedDomain(fieldDef, scaleType) {
if (!fieldDef.aggregate) {
return {
valid: false,
reason: log.message.unaggregateDomainHasNoEffectForRawField(fieldDef)
};
}
if (!aggregate_1.SHARED_DOMAIN_OP_INDEX[fieldDef.aggregate]) {
return {
valid: false,
reason: log.message.unaggregateDomainWithNonSharedDomainOp(fieldDef.aggregate)
};
}
if (fieldDef.type === 'quantitative') {
if (scaleType === 'log') {
return {
valid: false,
reason: log.message.unaggregatedDomainWithLogScale(fieldDef)
};
}
}
return { valid: true };
}
exports.canUseUnaggregatedDomain = canUseUnaggregatedDomain;
/**
* Converts an array of domains to a single Vega scale domain.
*/
function mergeDomains(domains) {
var uniqueDomains = util.unique(domains.map(function (domain) {
// ignore sort property when computing the unique domains
if (vega_schema_1.isDataRefDomain(domain)) {
var _s = domain.sort, domainWithoutSort = tslib_1.__rest(domain, ["sort"]);
return domainWithoutSort;
}
return domain;
}), util.hash);
var sorts = util.unique(domains.map(function (d) {
if (vega_schema_1.isDataRefDomain(d)) {
var s = d.sort;
if (s !== undefined && !util.isBoolean(s)) {
if (s.op === 'count') {
// let's make sure that if op is count, we don't use a field
delete s.field;
}
if (s.order === 'ascending') {
// drop order: ascending as it is the default
delete s.order;
}
}
return s;
}
return undefined;
}).filter(function (s) { return s !== undefined; }), util.hash);
if (uniqueDomains.length === 1) {
var domain = domains[0];
if (vega_schema_1.isDataRefDomain(domain) && sorts.length > 0) {
var sort_2 = sorts[0];
if (sorts.length > 1) {
log.warn(log.message.MORE_THAN_ONE_SORT);
sort_2 = true;
}
return tslib_1.__assign({}, domain, { sort: sort_2 });
}
return domain;
}
// only keep simple sort properties that work with unioned domains
var onlySimpleSorts = sorts.filter(function (s) {
if (util.isBoolean(s)) {
return true;
}
if (s.op === 'count') {
return true;
}
log.warn(log.message.domainSortDropped(s));
return false;
});
var sort = true;
if (onlySimpleSorts.length === 1) {
sort = onlySimpleSorts[0];
}
else if (onlySimpleSorts.length > 1) {
// ignore sort = false if we have another sort property
var filteredSorts = onlySimpleSorts.filter(function (s) { return s !== false; });
if (filteredSorts.length > 1) {
log.warn(log.message.MORE_THAN_ONE_SORT);
sort = true;
}
else {
sort = filteredSorts[0];
}
}
var allData = util.unique(domains.map(function (d) {
if (vega_schema_1.isDataRefDomain(d)) {
return d.data;
}
return null;
}), function (x) { return x; });
if (allData.length === 1 && allData[0] !== null) {
// create a union domain of different fields with a single data source
var domain = {
data: allData[0],
fields: uniqueDomains.map(function (d) { return d.field; }),
sort: sort
};
return domain;
}
return { fields: uniqueDomains, sort: sort };
}
exports.mergeDomains = mergeDomains;
/**
* Return a field if a scale single field.
* Return `undefined` otherwise.
*
*/
function getFieldFromDomain(domain) {
if (vega_schema_1.isDataRefDomain(domain) && vega_util_1.isString(domain.field)) {
return domain.field;
}
else if (vega_schema_2.isDataRefUnionedDomain(domain)) {
var field = void 0;
for (var _i = 0, _a = domain.fields; _i < _a.length; _i++) {
var nonUnionDomain = _a[_i];
if (vega_schema_1.isDataRefDomain(nonUnionDomain) && vega_util_1.isString(nonUnionDomain.field)) {
if (!field) {
field = nonUnionDomain.field;
}
else if (field !== nonUnionDomain.field) {
log.warn('Detected faceted independent scales that union domain of multiple fields from different data sources. We will use the first field. The result view size may be incorrect.');
return field;
}
}
}
log.warn('Detected faceted independent scales that union domain of identical fields from different source detected. We will assume that this is the same field from a different fork of the same data source. However, if this is not case, the result view size maybe incorrect.');
return field;
}
else if (vega_schema_2.isFieldRefUnionDomain(domain) && vega_util_1.isString) {
log.warn('Detected faceted independent scales that union domain of multiple fields from the same data source. We will use the first field. The result view size may be incorrect.');
var field = domain.fields[0];
return vega_util_1.isString(field) ? field : undefined;
}
return undefined;
}
exports.getFieldFromDomain = getFieldFromDomain;
function assembleDomain(model, channel) {
var scaleComponent = model.component.scales[channel];
var domains = scaleComponent.domains.map(function (domain) {
// Correct references to data as the original domain's data was determined
// in parseScale, which happens before parseData. Thus the original data
// reference can be incorrect.
if (vega_schema_1.isDataRefDomain(domain)) {
domain.data = model.lookupDataSource(domain.data);
}
return domain;
});
// domains is an array that has to be merged into a single vega domain
return mergeDomains(domains);
}
exports.assembleDomain = assembleDomain;
},{"../../aggregate":9,"../../bin":11,"../../channel":12,"../../data":92,"../../datetime":93,"../../log":101,"../../scale":104,"../../sort":106,"../../util":114,"../../vega.schema":116,"../common":20,"../data/optimize":35,"../model":63,"../selection/selection":76,"tslib":5,"vega-util":7}],70:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var channel_1 = require("../../channel");
var fielddef_1 = require("../../fielddef");
var scale_1 = require("../../scale");
var util_1 = require("../../util");
var model_1 = require("../model");
var resolve_1 = require("../resolve");
var split_1 = require("../split");
var component_1 = require("./component");
var domain_1 = require("./domain");
var properties_1 = require("./properties");
var range_1 = require("./range");
var type_1 = require("./type");
function parseScale(model) {
parseScaleCore(model);
domain_1.parseScaleDomain(model);
for (var _i = 0, NON_TYPE_DOMAIN_RANGE_VEGA_SCALE_PROPERTIES_1 = scale_1.NON_TYPE_DOMAIN_RANGE_VEGA_SCALE_PROPERTIES; _i < NON_TYPE_DOMAIN_RANGE_VEGA_SCALE_PROPERTIES_1.length; _i++) {
var prop = NON_TYPE_DOMAIN_RANGE_VEGA_SCALE_PROPERTIES_1[_i];
properties_1.parseScaleProperty(model, prop);
}
// range depends on zero
range_1.parseScaleRange(model);
}
exports.parseScale = parseScale;
function parseScaleCore(model) {
if (model_1.isUnitModel(model)) {
model.component.scales = parseUnitScaleCore(model);
}
else {
model.component.scales = parseNonUnitScaleCore(model);
}
}
exports.parseScaleCore = parseScaleCore;
/**
* Parse scales for all channels of a model.
*/
function parseUnitScaleCore(model) {
var encoding = model.encoding, config = model.config;
var mark = model.mark();
return channel_1.SCALE_CHANNELS.reduce(function (scaleComponents, channel) {
var fieldDef;
var specifiedScale = {};
var channelDef = encoding[channel];
if (fielddef_1.isFieldDef(channelDef)) {
fieldDef = channelDef;
specifiedScale = channelDef.scale || {};
}
else if (fielddef_1.isConditionalDef(channelDef) && fielddef_1.isFieldDef(channelDef.condition)) {
fieldDef = channelDef.condition;
specifiedScale = channelDef.condition.scale || {};
}
else if (channel === 'x') {
fieldDef = fielddef_1.getFieldDef(encoding.x2);
}
else if (channel === 'y') {
fieldDef = fielddef_1.getFieldDef(encoding.y2);
}
if (fieldDef) {
var specifiedScaleType = specifiedScale.type;
var sType = type_1.scaleType(specifiedScale.type, channel, fieldDef, mark, config.scale);
scaleComponents[channel] = new component_1.ScaleComponent(model.scaleName(channel + '', true), { value: sType, explicit: specifiedScaleType === sType });
}
return scaleComponents;
}, {});
}
var scaleTypeTieBreaker = split_1.tieBreakByComparing(function (st1, st2) { return (scale_1.scaleTypePrecedence(st1) - scale_1.scaleTypePrecedence(st2)); });
function parseNonUnitScaleCore(model) {
var scaleComponents = model.component.scales = {};
var scaleTypeWithExplicitIndex = {};
var resolve = model.component.resolve;
var _loop_1 = function (child) {
parseScaleCore(child);
// Instead of always merging right away -- check if it is compatible to merge first!
util_1.keys(child.component.scales).forEach(function (channel) {
// if resolve is undefined, set default first
resolve.scale[channel] = resolve.scale[channel] || resolve_1.defaultScaleResolve(channel, model);
if (resolve.scale[channel] === 'shared') {
var scaleType_1 = scaleTypeWithExplicitIndex[channel];
var childScaleType = child.component.scales[channel].getWithExplicit('type');
if (scaleType_1) {
if (scale_1.scaleCompatible(scaleType_1.value, childScaleType.value)) {
// merge scale component if type are compatible
scaleTypeWithExplicitIndex[channel] = split_1.mergeValuesWithExplicit(scaleType_1, childScaleType, 'type', 'scale', scaleTypeTieBreaker);
}
else {
// Otherwise, update conflicting channel to be independent
resolve.scale[channel] = 'independent';
// Remove from the index so they don't get merged
delete scaleTypeWithExplicitIndex[channel];
}
}
else {
scaleTypeWithExplicitIndex[channel] = childScaleType;
}
}
});
};
// Parse each child scale and determine if a particular channel can be merged.
for (var _i = 0, _a = model.children; _i < _a.length; _i++) {
var child = _a[_i];
_loop_1(child);
}
// Merge each channel listed in the index
util_1.keys(scaleTypeWithExplicitIndex).forEach(function (channel) {
// Create new merged scale component
var name = model.scaleName(channel, true);
var typeWithExplicit = scaleTypeWithExplicitIndex[channel];
scaleComponents[channel] = new component_1.ScaleComponent(name, typeWithExplicit);
// rename each child and mark them as merged
for (var _i = 0, _a = model.children; _i < _a.length; _i++) {
var child = _a[_i];
var childScale = child.component.scales[channel];
if (childScale) {
child.renameScale(childScale.get('name'), name);
childScale.merged = true;
}
}
});
return scaleComponents;
}
},{"../../channel":12,"../../fielddef":96,"../../scale":104,"../../util":114,"../model":63,"../resolve":66,"../split":86,"./component":68,"./domain":69,"./properties":71,"./range":72,"./type":73}],71:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var channel_1 = require("../../channel");
var log = require("../../log");
var scale_1 = require("../../scale");
var timeunit_1 = require("../../timeunit");
var util = require("../../util");
var util_1 = require("../../util");
var model_1 = require("../model");
var split_1 = require("../split");
var range_1 = require("./range");
function parseScaleProperty(model, property) {
if (model_1.isUnitModel(model)) {
parseUnitScaleProperty(model, property);
}
else {
parseNonUnitScaleProperty(model, property);
}
}
exports.parseScaleProperty = parseScaleProperty;
function parseUnitScaleProperty(model, property) {
var localScaleComponents = model.component.scales;
util_1.keys(localScaleComponents).forEach(function (channel) {
var specifiedScale = model.specifiedScales[channel];
var localScaleCmpt = localScaleComponents[channel];
var mergedScaleCmpt = model.getScaleComponent(channel);
var fieldDef = model.fieldDef(channel);
var sort = model.sort(channel);
var config = model.config;
var specifiedValue = specifiedScale[property];
var sType = mergedScaleCmpt.get('type');
var supportedByScaleType = scale_1.scaleTypeSupportProperty(sType, property);
var channelIncompatability = scale_1.channelScalePropertyIncompatability(channel, property);
if (specifiedValue !== undefined) {
// If there is a specified value, check if it is compatible with scale type and channel
if (!supportedByScaleType) {
log.warn(log.message.scalePropertyNotWorkWithScaleType(sType, property, channel));
}
else if (channelIncompatability) {
log.warn(channelIncompatability);
}
}
if (supportedByScaleType && channelIncompatability === undefined) {
if (specifiedValue !== undefined) {
// copyKeyFromObject ensure type safety
localScaleCmpt.copyKeyFromObject(property, specifiedScale);
}
else {
var value = getDefaultValue(property, channel, fieldDef, sort, mergedScaleCmpt.get('type'), mergedScaleCmpt.get('padding'), mergedScaleCmpt.get('paddingInner'), specifiedScale.domain, config.scale);
if (value !== undefined) {
localScaleCmpt.set(property, value, false);
}
}
}
});
}
// Note: This method is used in Voyager.
function getDefaultValue(property, channel, fieldDef, sort, scaleType, scalePadding, scalePaddingInner, specifiedDomain, scaleConfig) {
// If we have default rule-base, determine default value first
switch (property) {
case 'nice':
return nice(scaleType, channel, fieldDef);
case 'padding':
return padding(channel, scaleType, scaleConfig);
case 'paddingInner':
return paddingInner(scalePadding, channel, scaleConfig);
case 'paddingOuter':
return paddingOuter(scalePadding, channel, scaleType, scalePaddingInner, scaleConfig);
case 'reverse':
return reverse(scaleType, sort);
case 'zero':
return zero(channel, fieldDef, specifiedDomain);
}
// Otherwise, use scale config
return scaleConfig[property];
}
exports.getDefaultValue = getDefaultValue;
function parseNonUnitScaleProperty(model, property) {
var localScaleComponents = model.component.scales;
for (var _i = 0, _a = model.children; _i < _a.length; _i++) {
var child = _a[_i];
if (property === 'range') {
range_1.parseScaleRange(child);
}
else {
parseScaleProperty(child, property);
}
}
util_1.keys(localScaleComponents).forEach(function (channel) {
var valueWithExplicit;
for (var _i = 0, _a = model.children; _i < _a.length; _i++) {
var child = _a[_i];
var childComponent = child.component.scales[channel];
if (childComponent) {
var childValueWithExplicit = childComponent.getWithExplicit(property);
valueWithExplicit = split_1.mergeValuesWithExplicit(valueWithExplicit, childValueWithExplicit, property, 'scale', split_1.tieBreakByComparing(function (v1, v2) {
switch (property) {
case 'range':
// For range step, prefer larger step
if (v1.step && v2.step) {
return v1.step - v2.step;
}
return 0;
}
return 0;
}));
}
}
localScaleComponents[channel].setWithExplicit(property, valueWithExplicit);
});
}
exports.parseNonUnitScaleProperty = parseNonUnitScaleProperty;
function nice(scaleType, channel, fieldDef) {
if (util.contains([scale_1.ScaleType.TIME, scale_1.ScaleType.UTC], scaleType)) {
return timeunit_1.smallestUnit(fieldDef.timeUnit);
}
if (fieldDef.bin) {
return undefined;
}
return util.contains([channel_1.X, channel_1.Y], channel); // return true for quantitative X/Y unless binned
}
exports.nice = nice;
function padding(channel, scaleType, scaleConfig) {
if (util.contains([channel_1.X, channel_1.Y], channel)) {
if (scaleType === scale_1.ScaleType.POINT) {
return scaleConfig.pointPadding;
}
}
return undefined;
}
exports.padding = padding;
function paddingInner(padding, channel, scaleConfig) {
if (padding !== undefined) {
// If user has already manually specified "padding", no need to add default paddingInner.
return undefined;
}
if (util.contains([channel_1.X, channel_1.Y], channel)) {
// Padding is only set for X and Y by default.
// Basically it doesn't make sense to add padding for color and size.
// paddingOuter would only be called if it's a band scale, just return the default for bandScale.
return scaleConfig.bandPaddingInner;
}
return undefined;
}
exports.paddingInner = paddingInner;
function paddingOuter(padding, channel, scaleType, paddingInner, scaleConfig) {
if (padding !== undefined) {
// If user has already manually specified "padding", no need to add default paddingOuter.
return undefined;
}
if (util.contains([channel_1.X, channel_1.Y], channel)) {
// Padding is only set for X and Y by default.
// Basically it doesn't make sense to add padding for color and size.
if (scaleType === scale_1.ScaleType.BAND) {
if (scaleConfig.bandPaddingOuter !== undefined) {
return scaleConfig.bandPaddingOuter;
}
/* By default, paddingOuter is paddingInner / 2. The reason is that
size (width/height) = step * (cardinality - paddingInner + 2 * paddingOuter).
and we want the width/height to be integer by default.
Note that step (by default) and cardinality are integers.) */
return paddingInner / 2;
}
}
return undefined;
}
exports.paddingOuter = paddingOuter;
function reverse(scaleType, sort) {
if (scale_1.hasContinuousDomain(scaleType) && sort === 'descending') {
// For continuous domain scales, Vega does not support domain sort.
// Thus, we reverse range instead if sort is descending
return true;
}
return undefined;
}
exports.reverse = reverse;
function zero(channel, fieldDef, specifiedScale) {
// By default, return true only for the following cases:
// 1) using quantitative field with size
// While this can be either ratio or interval fields, our assumption is that
// ratio are more common.
if (channel === 'size' && fieldDef.type === 'quantitative') {
return true;
}
// 2) non-binned, quantitative x-scale or y-scale if no custom domain is provided.
// (For binning, we should not include zero by default because binning are calculated without zero.
// Similar, if users explicitly provide a domain range, we should not augment zero as that will be unexpected.)
var hasCustomDomain = !!specifiedScale && specifiedScale !== 'unaggregated';
if (!hasCustomDomain && !fieldDef.bin && util.contains([channel_1.X, channel_1.Y], channel)) {
return true;
}
return false;
}
exports.zero = zero;
},{"../../channel":12,"../../log":101,"../../scale":104,"../../timeunit":109,"../../util":114,"../model":63,"../split":86,"./range":72}],72:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var vega_util_1 = require("vega-util");
var channel_1 = require("../../channel");
var log = require("../../log");
var scale_1 = require("../../scale");
var util = require("../../util");
var vega_schema_1 = require("../../vega.schema");
var model_1 = require("../model");
var split_1 = require("../split");
var properties_1 = require("./properties");
exports.RANGE_PROPERTIES = ['range', 'rangeStep', 'scheme'];
function parseScaleRange(model) {
if (model_1.isUnitModel(model)) {
parseUnitScaleRange(model);
}
else {
properties_1.parseNonUnitScaleProperty(model, 'range');
}
}
exports.parseScaleRange = parseScaleRange;
function parseUnitScaleRange(model) {
var localScaleComponents = model.component.scales;
// use SCALE_CHANNELS instead of scales[channel] to ensure that x, y come first!
channel_1.SCALE_CHANNELS.forEach(function (channel) {
var localScaleCmpt = localScaleComponents[channel];
if (!localScaleCmpt) {
return;
}
var mergedScaleCmpt = model.getScaleComponent(channel);
var specifiedScale = model.specifiedScales[channel];
var fieldDef = model.fieldDef(channel);
// Read if there is a specified width/height
var sizeType = channel === 'x' ? 'width' : channel === 'y' ? 'height' : undefined;
var specifiedSize = sizeType ? model.component.layoutSize.get(sizeType) : undefined;
var xyRangeSteps = getXYRangeStep(model);
var rangeWithExplicit = parseRangeForChannel(channel, mergedScaleCmpt.get('type'), fieldDef.type, specifiedScale, model.config, localScaleCmpt.get('zero'), model.mark(), specifiedSize, model.getName(sizeType), xyRangeSteps);
localScaleCmpt.setWithExplicit('range', rangeWithExplicit);
});
}
function getXYRangeStep(model) {
var xyRangeSteps = [];
var xScale = model.getScaleComponent('x');
var xRange = xScale && xScale.get('range');
if (xRange && vega_schema_1.isVgRangeStep(xRange) && vega_util_1.isNumber(xRange.step)) {
xyRangeSteps.push(xRange.step);
}
var yScale = model.getScaleComponent('y');
var yRange = yScale && yScale.get('range');
if (yRange && vega_schema_1.isVgRangeStep(yRange) && vega_util_1.isNumber(yRange.step)) {
xyRangeSteps.push(yRange.step);
}
return xyRangeSteps;
}
/**
* Return mixins that includes one of the range properties (range, rangeStep, scheme).
*/
function parseRangeForChannel(channel, scaleType, type, specifiedScale, config, zero, mark, specifiedSize, sizeSignal, xyRangeSteps) {
var noRangeStep = !!specifiedSize || specifiedScale.rangeStep === null;
// Check if any of the range properties is specified.
// If so, check if it is compatible and make sure that we only output one of the properties
for (var _i = 0, RANGE_PROPERTIES_1 = exports.RANGE_PROPERTIES; _i < RANGE_PROPERTIES_1.length; _i++) {
var property = RANGE_PROPERTIES_1[_i];
if (specifiedScale[property] !== undefined) {
var supportedByScaleType = scale_1.scaleTypeSupportProperty(scaleType, property);
var channelIncompatability = scale_1.channelScalePropertyIncompatability(channel, property);
if (!supportedByScaleType) {
log.warn(log.message.scalePropertyNotWorkWithScaleType(scaleType, property, channel));
}
else if (channelIncompatability) {
log.warn(channelIncompatability);
}
else {
switch (property) {
case 'range':
return split_1.makeImplicit(specifiedScale[property]);
case 'scheme':
return split_1.makeImplicit(parseScheme(specifiedScale[property]));
case 'rangeStep':
var rangeStep = specifiedScale[property];
if (rangeStep !== null) {
if (specifiedSize === undefined) {
return split_1.makeImplicit({ step: rangeStep });
}
else {
// If top-level size is specified, we ignore specified rangeStep.
log.warn(log.message.rangeStepDropped(channel));
}
}
}
}
}
}
return {
explicit: false,
value: defaultRange(channel, scaleType, type, config, zero, mark, sizeSignal, xyRangeSteps, noRangeStep)
};
}
exports.parseRangeForChannel = parseRangeForChannel;
function parseScheme(scheme) {
if (scale_1.isExtendedScheme(scheme)) {
var r = { scheme: scheme.name };
if (scheme.count) {
r.count = scheme.count;
}
if (scheme.extent) {
r.extent = scheme.extent;
}
return r;
}
return { scheme: scheme };
}
function defaultRange(channel, scaleType, type, config, zero, mark, sizeSignal, xyRangeSteps, noRangeStep) {
switch (channel) {
case channel_1.X:
case channel_1.Y:
if (util.contains(['point', 'band'], scaleType) && !noRangeStep) {
if (channel === channel_1.X && mark === 'text') {
if (config.scale.textXRangeStep) {
return { step: config.scale.textXRangeStep };
}
}
else {
if (config.scale.rangeStep) {
return { step: config.scale.rangeStep };
}
}
}
// If range step is null, assign temporary range signals,
// which will be later replaced with proper signals in assemble.
// We cannot set the right size signal here since parseLayoutSize() happens after parseScale().
return channel === channel_1.X ? [0, { signal: sizeSignal }] : [{ signal: sizeSignal }, 0];
case channel_1.SIZE:
// TODO: support custom rangeMin, rangeMax
var rangeMin = sizeRangeMin(mark, zero, config);
var rangeMax = sizeRangeMax(mark, xyRangeSteps, config);
return [rangeMin, rangeMax];
case channel_1.SHAPE:
return 'symbol';
case channel_1.COLOR:
if (scaleType === 'ordinal') {
// Only nominal data uses ordinal scale by default
return type === 'nominal' ? 'category' : 'ordinal';
}
return mark === 'rect' ? 'heatmap' : 'ramp';
case channel_1.OPACITY:
// TODO: support custom rangeMin, rangeMax
return [config.scale.minOpacity, config.scale.maxOpacity];
}
/* istanbul ignore next: should never reach here */
throw new Error("Scale range undefined for channel " + channel);
}
exports.defaultRange = defaultRange;
function sizeRangeMin(mark, zero, config) {
if (zero) {
return 0;
}
switch (mark) {
case 'bar':
case 'tick':
return config.scale.minBandSize;
case 'line':
case 'rule':
return config.scale.minStrokeWidth;
case 'text':
return config.scale.minFontSize;
case 'point':
case 'square':
case 'circle':
return config.scale.minSize;
}
/* istanbul ignore next: should never reach here */
// sizeRangeMin not implemented for the mark
throw new Error(log.message.incompatibleChannel('size', mark));
}
function sizeRangeMax(mark, xyRangeSteps, config) {
var scaleConfig = config.scale;
// TODO(#1168): make max size scale based on rangeStep / overall plot size
switch (mark) {
case 'bar':
case 'tick':
if (config.scale.maxBandSize !== undefined) {
return config.scale.maxBandSize;
}
return minXYRangeStep(xyRangeSteps, config.scale) - 1;
case 'line':
case 'rule':
return config.scale.maxStrokeWidth;
case 'text':
return config.scale.maxFontSize;
case 'point':
case 'square':
case 'circle':
if (config.scale.maxSize) {
return config.scale.maxSize;
}
// FIXME this case totally should be refactored
var pointStep = minXYRangeStep(xyRangeSteps, scaleConfig);
return (pointStep - 2) * (pointStep - 2);
}
/* istanbul ignore next: should never reach here */
// sizeRangeMax not implemented for the mark
throw new Error(log.message.incompatibleChannel('size', mark));
}
/**
* @returns {number} Range step of x or y or minimum between the two if both are ordinal scale.
*/
function minXYRangeStep(xyRangeSteps, scaleConfig) {
if (xyRangeSteps.length > 0) {
return Math.min.apply(null, xyRangeSteps);
}
if (scaleConfig.rangeStep) {
return scaleConfig.rangeStep;
}
return 21; // FIXME: re-evaluate the default value here.
}
},{"../../channel":12,"../../log":101,"../../scale":104,"../../util":114,"../../vega.schema":116,"../model":63,"../split":86,"./properties":71,"vega-util":7}],73:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var channel_1 = require("../../channel");
var log = require("../../log");
var scale_1 = require("../../scale");
var scale_2 = require("../../scale");
var type_1 = require("../../type");
var util = require("../../util");
var util_1 = require("../../util");
/**
* Determine if there is a specified scale type and if it is appropriate,
* or determine default type if type is unspecified or inappropriate.
*/
// NOTE: CompassQL uses this method.
function scaleType(specifiedType, channel, fieldDef, mark, scaleConfig) {
var defaultScaleType = defaultType(channel, fieldDef, mark, scaleConfig);
if (!channel_1.isScaleChannel(channel)) {
// There is no scale for these channels
return null;
}
if (specifiedType !== undefined) {
// Check if explicitly specified scale type is supported by the channel
if (!scale_1.channelSupportScaleType(channel, specifiedType)) {
log.warn(log.message.scaleTypeNotWorkWithChannel(channel, specifiedType, defaultScaleType));
return defaultScaleType;
}
// Check if explicitly specified scale type is supported by the data type
if (!fieldDefMatchScaleType(specifiedType, fieldDef)) {
log.warn(log.message.scaleTypeNotWorkWithFieldDef(specifiedType, defaultScaleType));
return defaultScaleType;
}
return specifiedType;
}
return defaultScaleType;
}
exports.scaleType = scaleType;
/**
* Determine appropriate default scale type.
*/
// NOTE: Voyager uses this method.
function defaultType(channel, fieldDef, mark, scaleConfig) {
switch (fieldDef.type) {
case 'nominal':
case 'ordinal':
if (channel === 'color' || channel_1.rangeType(channel) === 'discrete') {
if (channel === 'shape' && fieldDef.type === 'ordinal') {
log.warn(log.message.discreteChannelCannotEncode(channel, 'ordinal'));
}
return 'ordinal';
}
if (util.contains(['x', 'y'], channel)) {
if (mark === 'rect') {
// The rect mark should fit into a band.
return 'band';
}
if (mark === 'bar') {
return 'band';
}
}
// Otherwise, use ordinal point scale so we can easily get center positions of the marks.
return 'point';
case 'temporal':
if (channel === 'color') {
return 'sequential';
}
else if (channel_1.rangeType(channel) === 'discrete') {
log.warn(log.message.discreteChannelCannotEncode(channel, 'temporal'));
// TODO: consider using quantize (equivalent to binning) once we have it
return 'ordinal';
}
return 'time';
case 'quantitative':
if (channel === 'color') {
if (fieldDef.bin) {
return 'bin-ordinal';
}
// Use `sequential` as the default color scale for continuous data
// since it supports both array range and scheme range.
return 'sequential';
}
else if (channel_1.rangeType(channel) === 'discrete') {
log.warn(log.message.discreteChannelCannotEncode(channel, 'quantitative'));
// TODO: consider using quantize (equivalent to binning) once we have it
return 'ordinal';
}
// x and y use a linear scale because selections don't work with bin scales.
// Binned scales apply discretization but pan/zoom apply transformations to a [min, max] extent domain.
if (fieldDef.bin && channel !== 'x' && channel !== 'y') {
return 'bin-linear';
}
return 'linear';
}
/* istanbul ignore next: should never reach this */
throw new Error(log.message.invalidFieldType(fieldDef.type));
}
function fieldDefMatchScaleType(specifiedType, fieldDef) {
var type = fieldDef.type;
if (util_1.contains([type_1.Type.ORDINAL, type_1.Type.NOMINAL], type)) {
return specifiedType === undefined || scale_2.hasDiscreteDomain(specifiedType);
}
else if (type === type_1.Type.TEMPORAL) {
return util_1.contains([scale_1.ScaleType.TIME, scale_1.ScaleType.UTC, scale_1.ScaleType.SEQUENTIAL, undefined], specifiedType);
}
else if (type === type_1.Type.QUANTITATIVE) {
if (fieldDef.bin) {
return util_1.contains([scale_1.ScaleType.BIN_LINEAR, scale_1.ScaleType.BIN_ORDINAL, scale_1.ScaleType.LINEAR], specifiedType);
}
return util_1.contains([scale_1.ScaleType.LOG, scale_1.ScaleType.POW, scale_1.ScaleType.SQRT, scale_1.ScaleType.QUANTILE, scale_1.ScaleType.QUANTIZE, scale_1.ScaleType.LINEAR, scale_1.ScaleType.SEQUENTIAL, undefined], specifiedType);
}
return true;
}
exports.fieldDefMatchScaleType = fieldDefMatchScaleType;
},{"../../channel":12,"../../log":101,"../../scale":104,"../../type":113,"../../util":114}],74:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var channel_1 = require("../../channel");
var log_1 = require("../../log");
var scale_1 = require("../../scale");
var util_1 = require("../../util");
var selection_1 = require("./selection");
var scales_1 = require("./transforms/scales");
exports.BRUSH = '_brush';
exports.SCALE_TRIGGER = '_scale_trigger';
var interval = {
predicate: 'vlInterval',
scaleDomain: 'vlIntervalDomain',
signals: function (model, selCmpt) {
var name = selCmpt.name;
var hasScales = scales_1.default.has(selCmpt);
var signals = [];
var intervals = [];
var tupleTriggers = [];
var scaleTriggers = [];
if (selCmpt.translate && !hasScales) {
var filterExpr_1 = "!event.item || event.item.mark.name !== " + util_1.stringValue(name + exports.BRUSH);
events(selCmpt, function (_, evt) {
var filters = evt.between[0].filter || (evt.between[0].filter = []);
if (filters.indexOf(filterExpr_1) < 0) {
filters.push(filterExpr_1);
}
});
}
selCmpt.project.forEach(function (p) {
var channel = p.channel;
if (channel !== channel_1.X && channel !== channel_1.Y) {
log_1.warn('Interval selections only support x and y encoding channels.');
return;
}
var cs = channelSignals(model, selCmpt, channel);
var dname = selection_1.channelSignalName(selCmpt, channel, 'data');
var vname = selection_1.channelSignalName(selCmpt, channel, 'visual');
var scaleStr = util_1.stringValue(model.scaleName(channel));
var scaleType = model.getScaleComponent(channel).get('type');
var toNum = scale_1.hasContinuousDomain(scaleType) ? '+' : '';
signals.push.apply(signals, cs);
tupleTriggers.push(dname);
intervals.push("{encoding: " + util_1.stringValue(channel) + ", " +
("field: " + util_1.stringValue(p.field) + ", extent: " + dname + "}"));
scaleTriggers.push({
scaleName: model.scaleName(channel),
expr: "(!isArray(" + dname + ") || " +
("(" + toNum + "invert(" + scaleStr + ", " + vname + ")[0] === " + toNum + dname + "[0] && ") +
(toNum + "invert(" + scaleStr + ", " + vname + ")[1] === " + toNum + dname + "[1]))")
});
});
// Proxy scale reactions to ensure that an infinite loop doesn't occur
// when an interval selection filter touches the scale.
if (!hasScales) {
signals.push({
name: name + exports.SCALE_TRIGGER,
update: scaleTriggers.map(function (t) { return t.expr; }).join(' && ') +
(" ? " + (name + exports.SCALE_TRIGGER) + " : {}")
});
}
// Only add an interval to the store if it has valid data extents. Data extents
// are set to null if pixel extents are equal to account for intervals over
// ordinal/nominal domains which, when inverted, will still produce a valid datum.
return signals.concat({
name: name + selection_1.TUPLE,
on: [{
events: tupleTriggers.map(function (t) { return ({ signal: t }); }),
update: tupleTriggers.join(' && ') +
(" ? {unit: " + selection_1.unitName(model) + ", intervals: [" + intervals.join(', ') + "]} : null")
}]
});
},
modifyExpr: function (model, selCmpt) {
var tpl = selCmpt.name + selection_1.TUPLE;
return tpl + ', ' +
(selCmpt.resolve === 'global' ? 'true' : "{unit: " + selection_1.unitName(model) + "}");
},
marks: function (model, selCmpt, marks) {
var name = selCmpt.name;
var _a = selection_1.spatialProjections(selCmpt), xi = _a.xi, yi = _a.yi;
var store = "data(" + util_1.stringValue(selCmpt.name + selection_1.STORE) + ")";
// Do not add a brush if we're binding to scales.
if (scales_1.default.has(selCmpt)) {
return marks;
}
var update = {
x: xi !== null ? { signal: name + "_x[0]" } : { value: 0 },
y: yi !== null ? { signal: name + "_y[0]" } : { value: 0 },
x2: xi !== null ? { signal: name + "_x[1]" } : { field: { group: 'width' } },
y2: yi !== null ? { signal: name + "_y[1]" } : { field: { group: 'height' } }
};
// If the selection is resolved to global, only a single interval is in
// the store. Wrap brush mark's encodings with a production rule to test
// this based on the `unit` property. Hide the brush mark if it corresponds
// to a unit different from the one in the store.
if (selCmpt.resolve === 'global') {
util_1.keys(update).forEach(function (key) {
update[key] = [tslib_1.__assign({ test: store + ".length && " + store + "[0].unit === " + selection_1.unitName(model) }, update[key]), { value: 0 }];
});
}
// Two brush marks ensure that fill colors and other aesthetic choices do
// not interefere with the core marks, but that the brushed region can still
// be interacted with (e.g., dragging it around).
var _b = selCmpt.mark, fill = _b.fill, fillOpacity = _b.fillOpacity, stroke = tslib_1.__rest(_b, ["fill", "fillOpacity"]);
var vgStroke = util_1.keys(stroke).reduce(function (def, k) {
def[k] = { value: stroke[k] };
return def;
}, {});
return [{
name: name + exports.BRUSH + '_bg',
type: 'rect',
clip: true,
encode: {
enter: {
fill: { value: fill },
fillOpacity: { value: fillOpacity }
},
update: update
}
}].concat(marks, {
name: name + exports.BRUSH,
type: 'rect',
clip: true,
encode: {
enter: tslib_1.__assign({ fill: { value: 'transparent' } }, vgStroke),
update: update
}
});
}
};
exports.default = interval;
/**
* Returns the visual and data signals for an interval selection.
*/
function channelSignals(model, selCmpt, channel) {
var vname = selection_1.channelSignalName(selCmpt, channel, 'visual');
var dname = selection_1.channelSignalName(selCmpt, channel, 'data');
var hasScales = scales_1.default.has(selCmpt);
var scaleName = model.scaleName(channel);
var scaleStr = util_1.stringValue(scaleName);
var scale = model.getScaleComponent(channel);
var scaleType = scale ? scale.get('type') : undefined;
var size = model.getSizeSignalRef(channel === channel_1.X ? 'width' : 'height').signal;
var coord = channel + "(unit)";
var on = events(selCmpt, function (def, evt) {
return def.concat({ events: evt.between[0], update: "[" + coord + ", " + coord + "]" }, // Brush Start
{ events: evt, update: "[" + vname + "[0], clamp(" + coord + ", 0, " + size + ")]" } // Brush End
);
});
// React to pan/zooms of continuous scales. Non-continuous scales
// (bin-linear, band, point) cannot be pan/zoomed and any other changes
// to their domains (e.g., filtering) should clear the brushes.
on.push({
events: { signal: selCmpt.name + exports.SCALE_TRIGGER },
update: scale_1.hasContinuousDomain(scaleType) && !scale_1.isBinScale(scaleType) ?
"[scale(" + scaleStr + ", " + dname + "[0]), scale(" + scaleStr + ", " + dname + "[1])]" : "[0, 0]"
});
return hasScales ? [{ name: dname, on: [] }] : [{
name: vname, value: [], on: on
}, {
name: dname,
on: [{ events: { signal: vname }, update: vname + "[0] === " + vname + "[1] ? null : invert(" + scaleStr + ", " + vname + ")" }]
}];
}
function events(selCmpt, cb) {
return selCmpt.events.reduce(function (on, evt) {
if (!evt.between) {
log_1.warn(evt + " is not an ordered event stream for interval selections");
return on;
}
return cb(on, evt);
}, []);
}
},{"../../channel":12,"../../log":101,"../../scale":104,"../../util":114,"./selection":76,"./transforms/scales":81,"tslib":5}],75:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var util_1 = require("../../util");
var selection_1 = require("./selection");
var nearest_1 = require("./transforms/nearest");
var multi = {
predicate: 'vlMulti',
scaleDomain: 'vlMultiDomain',
signals: function (model, selCmpt) {
var proj = selCmpt.project;
var datum = nearest_1.default.has(selCmpt) ?
'(item().isVoronoi ? datum.datum : datum)' : 'datum';
var bins = [];
var encodings = proj.map(function (p) { return util_1.stringValue(p.channel); }).filter(function (e) { return e; }).join(', ');
var fields = proj.map(function (p) { return util_1.stringValue(p.field); }).join(', ');
var values = proj.map(function (p) {
var channel = p.channel;
var fieldDef = model.fieldDef(channel);
// Binned fields should capture extents, for a range test against the raw field.
return (fieldDef && fieldDef.bin) ? (bins.push(p.field),
"[" + datum + "[" + util_1.stringValue(model.field(channel, {})) + "], " +
(datum + "[" + util_1.stringValue(model.field(channel, { binSuffix: 'end' })) + "]]")) :
datum + "[" + util_1.stringValue(p.field) + "]";
}).join(', ');
// Only add a discrete selection to the store if a datum is present _and_
// the interaction isn't occuring on a group mark. This guards against
// polluting interactive state with invalid values in faceted displays
// as the group marks are also data-driven. We force the update to account
// for constant null states but varying toggles (e.g., shift-click in
// whitespace followed by a click in whitespace; the store should only
// be cleared on the second click).
return [{
name: selCmpt.name + selection_1.TUPLE,
value: {},
on: [{
events: selCmpt.events,
update: "datum && item().mark.marktype !== 'group' ? " +
("{unit: " + selection_1.unitName(model) + ", encodings: [" + encodings + "], ") +
("fields: [" + fields + "], values: [" + values + "]") +
(bins.length ? ', ' + bins.map(function (b) { return util_1.stringValue('bin_' + b) + ": 1"; }).join(', ') : '') +
'} : null',
force: true
}]
}];
},
modifyExpr: function (model, selCmpt) {
var tpl = selCmpt.name + selection_1.TUPLE;
return tpl + ', ' +
(selCmpt.resolve === 'global' ? 'null' : "{unit: " + selection_1.unitName(model) + "}");
}
};
exports.default = multi;
},{"../../util":114,"./selection":76,"./transforms/nearest":79}],76:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var vega_event_selector_1 = require("vega-event-selector");
var channel_1 = require("../../channel");
var log_1 = require("../../log");
var selection_1 = require("../../selection");
var util_1 = require("../../util");
var model_1 = require("../model");
var interval_1 = require("./interval");
var multi_1 = require("./multi");
var single_1 = require("./single");
var transforms_1 = require("./transforms/transforms");
exports.STORE = '_store';
exports.TUPLE = '_tuple';
exports.MODIFY = '_modify';
exports.SELECTION_DOMAIN = '_selection_domain_';
function parseUnitSelection(model, selDefs) {
var selCmpts = {};
var selectionConfig = model.config.selection;
var _loop_1 = function (name_1) {
if (!selDefs.hasOwnProperty(name_1)) {
return "continue";
}
var selDef = selDefs[name_1];
var cfg = selectionConfig[selDef.type];
// Set default values from config if a property hasn't been specified,
// or if it is true. E.g., "translate": true should use the default
// event handlers for translate. However, true may be a valid value for
// a property (e.g., "nearest": true).
for (var key in cfg) {
// A selection should contain either `encodings` or `fields`, only use
// default values for these two values if neither of them is specified.
if ((key === 'encodings' && selDef.fields) || (key === 'fields' && selDef.encodings)) {
continue;
}
if (key === 'mark') {
selDef[key] = tslib_1.__assign({}, cfg[key], selDef[key]);
}
if (selDef[key] === undefined || selDef[key] === true) {
selDef[key] = cfg[key] || selDef[key];
}
}
name_1 = util_1.varName(name_1);
var selCmpt = selCmpts[name_1] = tslib_1.__assign({}, selDef, { name: name_1, events: util_1.isString(selDef.on) ? vega_event_selector_1.selector(selDef.on, 'scope') : selDef.on });
transforms_1.forEachTransform(selCmpt, function (txCompiler) {
if (txCompiler.parse) {
txCompiler.parse(model, selDef, selCmpt);
}
});
};
for (var name_1 in selDefs) {
_loop_1(name_1);
}
return selCmpts;
}
exports.parseUnitSelection = parseUnitSelection;
function assembleUnitSelectionSignals(model, signals) {
forEachSelection(model, function (selCmpt, selCompiler) {
var name = selCmpt.name;
var modifyExpr = selCompiler.modifyExpr(model, selCmpt);
signals.push.apply(signals, selCompiler.signals(model, selCmpt));
transforms_1.forEachTransform(selCmpt, function (txCompiler) {
if (txCompiler.signals) {
signals = txCompiler.signals(model, selCmpt, signals);
}
if (txCompiler.modifyExpr) {
modifyExpr = txCompiler.modifyExpr(model, selCmpt, modifyExpr);
}
});
signals.push({
name: name + exports.MODIFY,
on: [{
events: { signal: name + exports.TUPLE },
update: "modify(" + util_1.stringValue(selCmpt.name + exports.STORE) + ", " + modifyExpr + ")"
}]
});
});
var facetModel = getFacetModel(model);
if (signals.length && facetModel) {
var name_2 = util_1.stringValue(facetModel.getName('cell'));
signals.unshift({
name: 'facet',
value: {},
on: [{
events: vega_event_selector_1.selector('mousemove', 'scope'),
update: "isTuple(facet) ? facet : group(" + name_2 + ").datum"
}]
});
}
return signals;
}
exports.assembleUnitSelectionSignals = assembleUnitSelectionSignals;
function assembleTopLevelSignals(model, signals) {
var needsUnit = false;
forEachSelection(model, function (selCmpt, selCompiler) {
if (selCompiler.topLevelSignals) {
signals = selCompiler.topLevelSignals(model, selCmpt, signals);
}
transforms_1.forEachTransform(selCmpt, function (txCompiler) {
if (txCompiler.topLevelSignals) {
signals = txCompiler.topLevelSignals(model, selCmpt, signals);
}
});
needsUnit = true;
});
if (needsUnit) {
var hasUnit = signals.filter(function (s) { return s.name === 'unit'; });
if (!(hasUnit.length)) {
signals.unshift({
name: 'unit',
value: {},
on: [{ events: 'mousemove', update: 'isTuple(group()) ? group() : unit' }]
});
}
}
return signals;
}
exports.assembleTopLevelSignals = assembleTopLevelSignals;
function assembleUnitSelectionData(model, data) {
forEachSelection(model, function (selCmpt) {
var contains = data.filter(function (d) { return d.name === selCmpt.name + exports.STORE; });
if (!contains.length) {
data.push({ name: selCmpt.name + exports.STORE });
}
});
return data;
}
exports.assembleUnitSelectionData = assembleUnitSelectionData;
function assembleUnitSelectionMarks(model, marks) {
var selMarks = marks;
forEachSelection(model, function (selCmpt, selCompiler) {
selMarks = selCompiler.marks ? selCompiler.marks(model, selCmpt, selMarks) : selMarks;
transforms_1.forEachTransform(selCmpt, function (txCompiler) {
if (txCompiler.marks) {
selMarks = txCompiler.marks(model, selCmpt, marks, selMarks);
}
});
});
return selMarks;
}
exports.assembleUnitSelectionMarks = assembleUnitSelectionMarks;
function assembleLayerSelectionMarks(model, marks) {
model.children.forEach(function (child) {
if (model_1.isUnitModel(child)) {
marks = assembleUnitSelectionMarks(child, marks);
}
});
return marks;
}
exports.assembleLayerSelectionMarks = assembleLayerSelectionMarks;
function predicate(model, selections, dfnode) {
var stores = [];
function expr(name) {
var vname = util_1.varName(name);
var selCmpt = model.getSelectionComponent(vname, name);
var store = util_1.stringValue(vname + exports.STORE);
if (selCmpt.timeUnit) {
var child = dfnode || model.component.data.raw;
var tunode = selCmpt.timeUnit.clone();
if (child.parent) {
tunode.insertAsParentOf(child);
}
else {
child.parent = tunode;
}
}
stores.push(store);
return compiler(selCmpt.type).predicate + ("(" + store + ", datum") +
(selCmpt.resolve === 'global' ? ')' : ", " + util_1.stringValue(selCmpt.resolve) + ")");
}
var predicateStr = util_1.logicalExpr(selections, expr);
return '!(' + stores.map(function (s) { return "length(data(" + s + "))"; }).join(' || ') +
(") || (" + predicateStr + ")");
}
exports.predicate = predicate;
// Selections are parsed _after_ scales. If a scale domain is set to
// use a selection, the SELECTION_DOMAIN constant is used as the
// domainRaw.signal during scale.parse and then replaced with the necessary
// selection expression function during scale.assemble. To not pollute the
// type signatures to account for this setup, the selection domain definition
// is coerced to a string and appended to SELECTION_DOMAIN.
function isRawSelectionDomain(domainRaw) {
return domainRaw.signal.indexOf(exports.SELECTION_DOMAIN) >= 0;
}
exports.isRawSelectionDomain = isRawSelectionDomain;
function selectionScaleDomain(model, domainRaw) {
var selDomain = JSON.parse(domainRaw.signal.replace(exports.SELECTION_DOMAIN, ''));
var name = util_1.varName(selDomain.selection);
var selCmpt = model.component.selection && model.component.selection[name];
if (selCmpt) {
log_1.warn('Use "bind": "scales" to setup a binding for scales and selections within the same view.');
}
else {
selCmpt = model.getSelectionComponent(name, selDomain.selection);
if (!selDomain.encoding && !selDomain.field) {
selDomain.field = selCmpt.project[0].field;
if (selCmpt.project.length > 1) {
log_1.warn('A "field" or "encoding" must be specified when using a selection as a scale domain. ' +
("Using \"field\": " + util_1.stringValue(selDomain.field) + "."));
}
}
return {
signal: compiler(selCmpt.type).scaleDomain +
("(" + util_1.stringValue(name + exports.STORE) + ", " + util_1.stringValue(selDomain.encoding || null) + ", ") +
util_1.stringValue(selDomain.field || null) +
(selCmpt.resolve === 'global' ? ')' : ", " + util_1.stringValue(selCmpt.resolve) + ")")
};
}
return { signal: 'null' };
}
exports.selectionScaleDomain = selectionScaleDomain;
// Utility functions
function forEachSelection(model, cb) {
var selections = model.component.selection;
for (var name_3 in selections) {
if (selections.hasOwnProperty(name_3)) {
var sel = selections[name_3];
cb(sel, compiler(sel.type));
}
}
}
function compiler(type) {
switch (type) {
case 'single':
return single_1.default;
case 'multi':
return multi_1.default;
case 'interval':
return interval_1.default;
}
return null;
}
function getFacetModel(model) {
var parent = model.parent;
while (parent) {
if (model_1.isFacetModel(parent)) {
break;
}
parent = parent.parent;
}
return parent;
}
function unitName(model) {
var name = util_1.stringValue(model.name);
var facet = getFacetModel(model);
if (facet) {
name += (facet.facet.row ? " + '_' + facet[" + util_1.stringValue(facet.field('row')) + "]" : '')
+ (facet.facet.column ? " + '_' + facet[" + util_1.stringValue(facet.field('column')) + "]" : '');
}
return name;
}
exports.unitName = unitName;
function requiresSelectionId(model) {
var identifier = false;
forEachSelection(model, function (selCmpt) {
identifier = identifier || selCmpt.project.some(function (proj) { return proj.field === selection_1.SELECTION_ID; });
});
return identifier;
}
exports.requiresSelectionId = requiresSelectionId;
function channelSignalName(selCmpt, channel, range) {
return util_1.varName(selCmpt.name + '_' + (range === 'visual' ? channel : selCmpt.fields[channel]));
}
exports.channelSignalName = channelSignalName;
function spatialProjections(selCmpt) {
var x = null;
var xi = null;
var y = null;
var yi = null;
selCmpt.project.forEach(function (p, i) {
if (p.channel === channel_1.X) {
x = p;
xi = i;
}
else if (p.channel === channel_1.Y) {
y = p;
yi = i;
}
});
return { x: x, xi: xi, y: y, yi: yi };
}
exports.spatialProjections = spatialProjections;
},{"../../channel":12,"../../log":101,"../../selection":105,"../../util":114,"../model":63,"./interval":74,"./multi":75,"./single":77,"./transforms/transforms":83,"tslib":5,"vega-event-selector":6}],77:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var util_1 = require("../../util");
var multi_1 = require("./multi");
var selection_1 = require("./selection");
var single = {
predicate: 'vlSingle',
scaleDomain: 'vlSingleDomain',
signals: multi_1.default.signals,
topLevelSignals: function (model, selCmpt, signals) {
var hasSignal = signals.filter(function (s) { return s.name === selCmpt.name; });
var data = "data(" + util_1.stringValue(selCmpt.name + selection_1.STORE) + ")";
var values = data + "[0].values";
return hasSignal.length ? signals : signals.concat({
name: selCmpt.name,
update: data + ".length && {" +
selCmpt.project.map(function (p, i) { return p.field + ": " + values + "[" + i + "]"; }).join(', ') + '}'
});
},
modifyExpr: function (model, selCmpt) {
var tpl = selCmpt.name + selection_1.TUPLE;
return tpl + ', ' +
(selCmpt.resolve === 'global' ? 'true' : "{unit: " + selection_1.unitName(model) + "}");
}
};
exports.default = single;
},{"../../util":114,"./multi":75,"./selection":76}],78:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var util_1 = require("../../../util");
var selection_1 = require("../selection");
var nearest_1 = require("./nearest");
var inputBindings = {
has: function (selCmpt) {
return selCmpt.type === 'single' && selCmpt.resolve === 'global' &&
selCmpt.bind && selCmpt.bind !== 'scales';
},
topLevelSignals: function (model, selCmpt, signals) {
var name = selCmpt.name;
var proj = selCmpt.project;
var bind = selCmpt.bind;
var datum = nearest_1.default.has(selCmpt) ?
'(item().isVoronoi ? datum.datum : datum)' : 'datum';
proj.forEach(function (p) {
var sgname = util_1.varName(name + "_" + p.field);
var hasSignal = signals.filter(function (s) { return s.name === sgname; });
if (!hasSignal.length) {
signals.unshift({
name: sgname,
value: '',
on: [{
events: selCmpt.events,
update: "datum && item().mark.marktype !== 'group' ? " + datum + "[" + util_1.stringValue(p.field) + "] : null"
}],
bind: bind[p.field] || bind[p.channel] || bind
});
}
});
return signals;
},
signals: function (model, selCmpt, signals) {
var name = selCmpt.name;
var proj = selCmpt.project;
var signal = signals.filter(function (s) { return s.name === name + selection_1.TUPLE; })[0];
var fields = proj.map(function (p) { return util_1.stringValue(p.field); }).join(', ');
var values = proj.map(function (p) { return util_1.varName(name + "_" + p.field); });
signal.update = values.join(' && ') + " ? {fields: [" + fields + "], values: [" + values.join(', ') + "]} : null";
delete signal.value;
delete signal.on;
return signals;
}
};
exports.default = inputBindings;
},{"../../../util":114,"../selection":76,"./nearest":79}],79:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var selection_1 = require("../selection");
var VORONOI = 'voronoi';
var nearest = {
has: function (selCmpt) {
return selCmpt.type !== 'interval' && selCmpt.nearest;
},
marks: function (model, selCmpt, marks, selMarks) {
var _a = selection_1.spatialProjections(selCmpt), x = _a.x, y = _a.y;
var mark = marks[0];
var index = selMarks.indexOf(mark);
var isPathgroup = mark.name === model.getName('pathgroup');
var exists = (function (m) { return m.name && m.name.indexOf(VORONOI) >= 0; });
var cellDef = {
name: model.getName(VORONOI),
type: 'path',
from: { data: model.getName('marks') },
encode: {
enter: {
fill: { value: 'transparent' },
strokeWidth: { value: 0.35 },
stroke: { value: 'transparent' },
isVoronoi: { value: true }
}
},
transform: [{
type: 'voronoi',
x: (x || (!x && !y)) ? 'datum.x' : { expr: '0' },
y: (y || (!x && !y)) ? 'datum.y' : { expr: '0' },
size: [model.getSizeSignalRef('width'), model.getSizeSignalRef('height')]
}]
};
if (isPathgroup && !mark.marks.filter(exists).length) {
mark.marks.push(cellDef);
selMarks.splice(index, 1, mark);
}
else if (!isPathgroup && !selMarks.filter(exists).length) {
selMarks.splice(index + 1, 0, cellDef);
}
return selMarks;
}
};
exports.default = nearest;
},{"../selection":76}],80:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var log = require("../../../log");
var util_1 = require("../../../util");
var timeunit_1 = require("../../data/timeunit");
var project = {
has: function (selDef) {
return selDef.fields !== undefined || selDef.encodings !== undefined;
},
parse: function (model, selDef, selCmpt) {
var channels = {};
var timeUnits = {};
// TODO: find a possible channel mapping for these fields.
(selDef.fields || []).forEach(function (field) { return channels[field] = null; });
(selDef.encodings || []).forEach(function (channel) {
var fieldDef = model.fieldDef(channel);
if (fieldDef) {
if (fieldDef.timeUnit) {
var tuField = model.field(channel);
channels[tuField] = channel;
// Construct TimeUnitComponents which will be combined into a
// TimeUnitNode. This node may need to be inserted into the
// dataflow if the selection is used across views that do not
// have these time units defined.
timeUnits[tuField] = {
as: tuField,
field: fieldDef.field,
timeUnit: fieldDef.timeUnit
};
}
else {
channels[fieldDef.field] = channel;
}
}
else {
log.warn(log.message.cannotProjectOnChannelWithoutField(channel));
}
});
var projection = selCmpt.project || (selCmpt.project = []);
for (var field in channels) {
if (channels.hasOwnProperty(field)) {
projection.push({ field: field, channel: channels[field] });
}
}
var fields = selCmpt.fields || (selCmpt.fields = {});
projection.filter(function (p) { return p.channel; }).forEach(function (p) { return fields[p.channel] = p.field; });
if (util_1.keys(timeUnits).length) {
selCmpt.timeUnit = new timeunit_1.TimeUnitNode(timeUnits);
}
}
};
exports.default = project;
},{"../../../log":101,"../../../util":114,"../../data/timeunit":40}],81:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var log_1 = require("../../../log");
var scale_1 = require("../../../scale");
var util_1 = require("../../../util");
var selection_1 = require("../selection");
var scaleBindings = {
has: function (selCmpt) {
return selCmpt.type === 'interval' && selCmpt.resolve === 'global' &&
selCmpt.bind && selCmpt.bind === 'scales';
},
parse: function (model, selDef, selCmpt) {
var bound = selCmpt.scales = [];
selCmpt.project.forEach(function (p) {
var channel = p.channel;
var scale = model.getScaleComponent(channel);
var scaleType = scale ? scale.get('type') : undefined;
if (!scale || !scale_1.hasContinuousDomain(scaleType) || scale_1.isBinScale(scaleType)) {
log_1.warn('Scale bindings are currently only supported for scales with unbinned, continuous domains.');
return;
}
scale.set('domainRaw', { signal: selection_1.channelSignalName(selCmpt, channel, 'data') }, true);
bound.push(channel);
});
},
topLevelSignals: function (model, selCmpt, signals) {
// Top-level signals are only needed when coordinating composed views.
if (!model.parent) {
return signals;
}
var channels = selCmpt.scales.filter(function (channel) {
return !(signals.filter(function (s) { return s.name === selection_1.channelSignalName(selCmpt, channel, 'data'); }).length);
});
return signals.concat(channels.map(function (channel) {
return { name: selection_1.channelSignalName(selCmpt, channel, 'data') };
}));
},
signals: function (model, selCmpt, signals) {
// Nested signals need only push to top-level signals when within composed views.
if (model.parent) {
selCmpt.scales.forEach(function (channel) {
var signal = signals.filter(function (s) { return s.name === selection_1.channelSignalName(selCmpt, channel, 'data'); })[0];
signal.push = 'outer';
delete signal.value;
delete signal.update;
});
}
return signals;
}
};
exports.default = scaleBindings;
function domain(model, channel) {
var scale = util_1.stringValue(model.scaleName(channel));
return "domain(" + scale + ")";
}
exports.domain = domain;
},{"../../../log":101,"../../../scale":104,"../../../util":114,"../selection":76}],82:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var selection_1 = require("../selection");
var TOGGLE = '_toggle';
var toggle = {
has: function (selCmpt) {
return selCmpt.type === 'multi' && selCmpt.toggle;
},
signals: function (model, selCmpt, signals) {
return signals.concat({
name: selCmpt.name + TOGGLE,
value: false,
on: [{ events: selCmpt.events, update: selCmpt.toggle }]
});
},
modifyExpr: function (model, selCmpt, expr) {
var tpl = selCmpt.name + selection_1.TUPLE;
var signal = selCmpt.name + TOGGLE;
return signal + " ? null : " + tpl + ", " +
(selCmpt.resolve === 'global' ?
signal + " ? null : true, " :
signal + " ? null : {unit: " + selection_1.unitName(model) + "}, ") +
(signal + " ? " + tpl + " : null");
}
};
exports.default = toggle;
},{"../selection":76}],83:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var inputs_1 = require("./inputs");
var nearest_1 = require("./nearest");
var project_1 = require("./project");
var scales_1 = require("./scales");
var toggle_1 = require("./toggle");
var translate_1 = require("./translate");
var zoom_1 = require("./zoom");
var compilers = { project: project_1.default, toggle: toggle_1.default, scales: scales_1.default,
translate: translate_1.default, zoom: zoom_1.default, inputs: inputs_1.default, nearest: nearest_1.default };
function forEachTransform(selCmpt, cb) {
for (var t in compilers) {
if (compilers[t].has(selCmpt)) {
cb(compilers[t]);
}
}
}
exports.forEachTransform = forEachTransform;
},{"./inputs":78,"./nearest":79,"./project":80,"./scales":81,"./toggle":82,"./translate":84,"./zoom":85}],84:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var vega_event_selector_1 = require("vega-event-selector");
var channel_1 = require("../../../channel");
var interval_1 = require("../interval");
var selection_1 = require("../selection");
var scales_1 = require("./scales");
var ANCHOR = '_translate_anchor';
var DELTA = '_translate_delta';
var translate = {
has: function (selCmpt) {
return selCmpt.type === 'interval' && selCmpt.translate;
},
signals: function (model, selCmpt, signals) {
var name = selCmpt.name;
var hasScales = scales_1.default.has(selCmpt);
var anchor = name + ANCHOR;
var _a = selection_1.spatialProjections(selCmpt), x = _a.x, y = _a.y;
var events = vega_event_selector_1.selector(selCmpt.translate, 'scope');
if (!hasScales) {
events = events.map(function (e) { return (e.between[0].markname = name + interval_1.BRUSH, e); });
}
signals.push({
name: anchor,
value: {},
on: [{
events: events.map(function (e) { return e.between[0]; }),
update: '{x: x(unit), y: y(unit)' +
(x !== null ? ', extent_x: ' + (hasScales ? scales_1.domain(model, channel_1.X) :
"slice(" + selection_1.channelSignalName(selCmpt, 'x', 'visual') + ")") : '') +
(y !== null ? ', extent_y: ' + (hasScales ? scales_1.domain(model, channel_1.Y) :
"slice(" + selection_1.channelSignalName(selCmpt, 'y', 'visual') + ")") : '') + '}'
}]
}, {
name: name + DELTA,
value: {},
on: [{
events: events,
update: "{x: " + anchor + ".x - x(unit), y: " + anchor + ".y - y(unit)}"
}]
});
if (x !== null) {
onDelta(model, selCmpt, channel_1.X, 'width', signals);
}
if (y !== null) {
onDelta(model, selCmpt, channel_1.Y, 'height', signals);
}
return signals;
}
};
exports.default = translate;
function onDelta(model, selCmpt, channel, size, signals) {
var name = selCmpt.name;
var hasScales = scales_1.default.has(selCmpt);
var signal = signals.filter(function (s) {
return s.name === selection_1.channelSignalName(selCmpt, channel, hasScales ? 'data' : 'visual');
})[0];
var anchor = name + ANCHOR;
var delta = name + DELTA;
var sizeSg = model.getSizeSignalRef(size).signal;
var scaleCmpt = model.getScaleComponent(channel);
var scaleType = scaleCmpt.get('type');
var sign = hasScales && channel === channel_1.X ? '-' : ''; // Invert delta when panning x-scales.
var extent = anchor + ".extent_" + channel;
var offset = "" + sign + delta + "." + channel + " / " + (hasScales ? "" + sizeSg : "span(" + extent + ")");
var panFn = !hasScales ? 'panLinear' :
scaleType === 'log' ? 'panLog' :
scaleType === 'pow' ? 'panPow' : 'panLinear';
var update = panFn + "(" + extent + ", " + offset +
(hasScales && scaleType === 'pow' ? ", " + (scaleCmpt.get('exponent') || 1) : '') + ')';
signal.on.push({
events: { signal: delta },
update: hasScales ? update : "clampRange(" + update + ", 0, " + sizeSg + ")"
});
}
},{"../../../channel":12,"../interval":74,"../selection":76,"./scales":81,"vega-event-selector":6}],85:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var vega_event_selector_1 = require("vega-event-selector");
var channel_1 = require("../../../channel");
var util_1 = require("../../../util");
var interval_1 = require("../interval");
var selection_1 = require("../selection");
var scales_1 = require("./scales");
var ANCHOR = '_zoom_anchor';
var DELTA = '_zoom_delta';
var zoom = {
has: function (selCmpt) {
return selCmpt.type === 'interval' && selCmpt.zoom;
},
signals: function (model, selCmpt, signals) {
var name = selCmpt.name;
var hasScales = scales_1.default.has(selCmpt);
var delta = name + DELTA;
var _a = selection_1.spatialProjections(selCmpt), x = _a.x, y = _a.y;
var sx = util_1.stringValue(model.scaleName(channel_1.X));
var sy = util_1.stringValue(model.scaleName(channel_1.Y));
var events = vega_event_selector_1.selector(selCmpt.zoom, 'scope');
if (!hasScales) {
events = events.map(function (e) { return (e.markname = name + interval_1.BRUSH, e); });
}
signals.push({
name: name + ANCHOR,
on: [{
events: events,
update: !hasScales ? "{x: x(unit), y: y(unit)}" :
'{' + [
(sx ? "x: invert(" + sx + ", x(unit))" : ''),
(sy ? "y: invert(" + sy + ", y(unit))" : '')
].filter(function (expr) { return !!expr; }).join(', ') + '}'
}]
}, {
name: delta,
on: [{
events: events,
force: true,
update: 'pow(1.001, event.deltaY * pow(16, event.deltaMode))'
}]
});
if (x !== null) {
onDelta(model, selCmpt, 'x', 'width', signals);
}
if (y !== null) {
onDelta(model, selCmpt, 'y', 'height', signals);
}
return signals;
}
};
exports.default = zoom;
function onDelta(model, selCmpt, channel, size, signals) {
var name = selCmpt.name;
var hasScales = scales_1.default.has(selCmpt);
var signal = signals.filter(function (s) {
return s.name === selection_1.channelSignalName(selCmpt, channel, hasScales ? 'data' : 'visual');
})[0];
var sizeSg = model.getSizeSignalRef(size).signal;
var scaleCmpt = model.getScaleComponent(channel);
var scaleType = scaleCmpt.get('type');
var base = hasScales ? scales_1.domain(model, channel) : signal.name;
var delta = name + DELTA;
var anchor = "" + name + ANCHOR + "." + channel;
var zoomFn = !hasScales ? 'zoomLinear' :
scaleType === 'log' ? 'zoomLog' :
scaleType === 'pow' ? 'zoomPow' : 'zoomLinear';
var update = zoomFn + "(" + base + ", " + anchor + ", " + delta +
(hasScales && scaleType === 'pow' ? ", " + (scaleCmpt.get('exponent') || 1) : '') + ')';
signal.on.push({
events: { signal: delta },
update: hasScales ? update : "clampRange(" + update + ", 0, " + sizeSg + ")"
});
}
},{"../../../channel":12,"../../../util":114,"../interval":74,"../selection":76,"./scales":81,"vega-event-selector":6}],86:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var log = require("../log");
var util_1 = require("../util");
/**
* Generic class for storing properties that are explicitly specified
* and implicitly determined by the compiler.
* This is important for scale/axis/legend merging as
* we want to prioritize properties that users explicitly specified.
*/
var Split = /** @class */ (function () {
function Split(explicit, implicit) {
if (explicit === void 0) { explicit = {}; }
if (implicit === void 0) { implicit = {}; }
this.explicit = explicit;
this.implicit = implicit;
}
Split.prototype.clone = function () {
return new Split(util_1.duplicate(this.explicit), util_1.duplicate(this.implicit));
};
Split.prototype.combine = function () {
// FIXME remove "as any".
// Add "as any" to avoid an error "Spread types may only be created from object types".
return tslib_1.__assign({}, this.explicit, this.implicit);
};
Split.prototype.get = function (key) {
// Explicit has higher precedence
return this.explicit[key] !== undefined ? this.explicit[key] : this.implicit[key];
};
Split.prototype.getWithExplicit = function (key) {
// Explicit has higher precedence
if (this.explicit[key] !== undefined) {
return { explicit: true, value: this.explicit[key] };
}
else if (this.implicit[key] !== undefined) {
return { explicit: false, value: this.implicit[key] };
}
return { explicit: false, value: undefined };
};
Split.prototype.setWithExplicit = function (key, value) {
if (value.value !== undefined) {
this.set(key, value.value, value.explicit);
}
};
Split.prototype.set = function (key, value, explicit) {
delete this[explicit ? 'implicit' : 'explicit'][key];
this[explicit ? 'explicit' : 'implicit'][key] = value;
return this;
};
Split.prototype.copyKeyFromSplit = function (key, s) {
// Explicit has higher precedence
if (s.explicit[key] !== undefined) {
this.set(key, s.explicit[key], true);
}
else if (s.implicit[key] !== undefined) {
this.set(key, s.implicit[key], false);
}
};
Split.prototype.copyKeyFromObject = function (key, s) {
// Explicit has higher precedence
if (s[key] !== undefined) {
this.set(key, s[key], true);
}
};
return Split;
}());
exports.Split = Split;
function makeExplicit(value) {
return {
explicit: true,
value: value
};
}
exports.makeExplicit = makeExplicit;
function makeImplicit(value) {
return {
explicit: false,
value: value
};
}
exports.makeImplicit = makeImplicit;
function tieBreakByComparing(compare) {
return function (v1, v2, property, propertyOf) {
var diff = compare(v1.value, v2.value);
if (diff > 0) {
return v1;
}
else if (diff < 0) {
return v2;
}
return defaultTieBreaker(v1, v2, property, propertyOf);
};
}
exports.tieBreakByComparing = tieBreakByComparing;
function defaultTieBreaker(v1, v2, property, propertyOf) {
if (v1.explicit && v2.explicit) {
log.warn(log.message.mergeConflictingProperty(property, propertyOf, v1.value, v2.value));
}
// If equal score, prefer v1.
return v1;
}
exports.defaultTieBreaker = defaultTieBreaker;
function mergeValuesWithExplicit(v1, v2, property, propertyOf, tieBreaker) {
if (tieBreaker === void 0) { tieBreaker = defaultTieBreaker; }
if (v1 === undefined || v1.value === undefined) {
// For first run
return v2;
}
if (v1.explicit && !v2.explicit) {
return v1;
}
else if (v2.explicit && !v1.explicit) {
return v2;
}
else if (v1.value === v2.value) {
return v1;
}
else {
return tieBreaker(v1, v2, property, propertyOf);
}
}
exports.mergeValuesWithExplicit = mergeValuesWithExplicit;
},{"../log":101,"../util":114,"tslib":5}],87:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var channel_1 = require("../channel");
var vlEncoding = require("../encoding");
var encoding_1 = require("../encoding");
var fielddef_1 = require("../fielddef");
var mark_1 = require("../mark");
var stack_1 = require("../stack");
var util_1 = require("../util");
var parse_1 = require("./axis/parse");
var parse_2 = require("./data/parse");
var assemble_1 = require("./layoutsize/assemble");
var parse_3 = require("./layoutsize/parse");
var init_1 = require("./mark/init");
var mark_2 = require("./mark/mark");
var model_1 = require("./model");
var repeater_1 = require("./repeater");
var selection_1 = require("./selection/selection");
/**
* Internal model of Vega-Lite specification for the compiler.
*/
var UnitModel = /** @class */ (function (_super) {
tslib_1.__extends(UnitModel, _super);
function UnitModel(spec, parent, parentGivenName, parentGivenSize, repeater, config) {
if (parentGivenSize === void 0) { parentGivenSize = {}; }
var _this = _super.call(this, spec, parent, parentGivenName, config, undefined) || this;
_this.type = 'unit';
_this.specifiedScales = {};
_this.specifiedAxes = {};
_this.specifiedLegends = {};
_this.selection = {};
_this.children = [];
_this.initSize(tslib_1.__assign({}, parentGivenSize, (spec.width ? { width: spec.width } : {}), (spec.height ? { height: spec.height } : {})));
_this.markDef = mark_1.isMarkDef(spec.mark) ? tslib_1.__assign({}, spec.mark) : { type: spec.mark };
var mark = _this.markDef.type;
var encoding = _this.encoding = encoding_1.normalizeEncoding(repeater_1.replaceRepeaterInEncoding(spec.encoding || {}, repeater), mark);
// calculate stack properties
_this.stack = stack_1.stack(mark, encoding, _this.config.stack);
_this.specifiedScales = _this.initScales(mark, encoding);
// FIXME: this one seems out of place!
_this.encoding = init_1.initEncoding(_this.markDef, encoding, _this.stack, _this.config);
_this.specifiedAxes = _this.initAxes(encoding);
_this.specifiedLegends = _this.initLegend(encoding);
// Selections will be initialized upon parse.
_this.selection = spec.selection;
return _this;
}
/**
* Return specified Vega-lite scale domain for a particular channel
* @param channel
*/
UnitModel.prototype.scaleDomain = function (channel) {
var scale = this.specifiedScales[channel];
return scale ? scale.domain : undefined;
};
UnitModel.prototype.sort = function (channel) {
return (this.getMapping()[channel] || {}).sort;
};
UnitModel.prototype.axis = function (channel) {
return this.specifiedAxes[channel];
};
UnitModel.prototype.legend = function (channel) {
return this.specifiedLegends[channel];
};
UnitModel.prototype.initScales = function (mark, encoding) {
return channel_1.SCALE_CHANNELS.reduce(function (scales, channel) {
var fieldDef;
var specifiedScale;
var channelDef = encoding[channel];
if (fielddef_1.isFieldDef(channelDef)) {
fieldDef = channelDef;
specifiedScale = channelDef.scale;
}
else if (fielddef_1.isConditionalDef(channelDef) && fielddef_1.isFieldDef(channelDef.condition)) {
fieldDef = channelDef.condition;
specifiedScale = channelDef.condition.scale;
}
else if (channel === 'x') {
fieldDef = fielddef_1.getFieldDef(encoding.x2);
}
else if (channel === 'y') {
fieldDef = fielddef_1.getFieldDef(encoding.y2);
}
if (fieldDef) {
scales[channel] = specifiedScale || {};
}
return scales;
}, {});
};
UnitModel.prototype.initAxes = function (encoding) {
return [channel_1.X, channel_1.Y].reduce(function (_axis, channel) {
// Position Axis
// TODO: handle ConditionFieldDef
var channelDef = encoding[channel];
if (fielddef_1.isFieldDef(channelDef) ||
(channel === channel_1.X && fielddef_1.isFieldDef(encoding.x2)) ||
(channel === channel_1.Y && fielddef_1.isFieldDef(encoding.y2))) {
var axisSpec = fielddef_1.isFieldDef(channelDef) ? channelDef.axis : null;
// We no longer support false in the schema, but we keep false here for backward compatability.
if (axisSpec !== null && axisSpec !== false) {
_axis[channel] = tslib_1.__assign({}, axisSpec);
}
}
return _axis;
}, {});
};
UnitModel.prototype.initLegend = function (encoding) {
return channel_1.NONSPATIAL_SCALE_CHANNELS.reduce(function (_legend, channel) {
var channelDef = encoding[channel];
if (channelDef) {
var legend = fielddef_1.isFieldDef(channelDef) ? channelDef.legend :
(channelDef.condition && fielddef_1.isFieldDef(channelDef.condition)) ? channelDef.condition.legend : null;
if (legend !== null && legend !== false) {
_legend[channel] = tslib_1.__assign({}, legend);
}
}
return _legend;
}, {});
};
UnitModel.prototype.parseData = function () {
this.component.data = parse_2.parseData(this);
};
UnitModel.prototype.parseLayoutSize = function () {
parse_3.parseUnitLayoutSize(this);
};
UnitModel.prototype.parseSelection = function () {
this.component.selection = selection_1.parseUnitSelection(this, this.selection);
};
UnitModel.prototype.parseMarkGroup = function () {
this.component.mark = mark_2.parseMarkGroup(this);
};
UnitModel.prototype.parseAxisAndHeader = function () {
this.component.axes = parse_1.parseUnitAxis(this);
};
UnitModel.prototype.assembleSelectionTopLevelSignals = function (signals) {
return selection_1.assembleTopLevelSignals(this, signals);
};
UnitModel.prototype.assembleSelectionSignals = function () {
return selection_1.assembleUnitSelectionSignals(this, []);
};
UnitModel.prototype.assembleSelectionData = function (data) {
return selection_1.assembleUnitSelectionData(this, data);
};
UnitModel.prototype.assembleLayout = function () {
return null;
};
UnitModel.prototype.assembleLayoutSignals = function () {
return assemble_1.assembleLayoutSignals(this);
};
UnitModel.prototype.assembleMarks = function () {
var marks = this.component.mark || [];
// If this unit is part of a layer, selections should augment
// all in concert rather than each unit individually. This
// ensures correct interleaving of clipping and brushed marks.
if (!this.parent || !model_1.isLayerModel(this.parent)) {
marks = selection_1.assembleUnitSelectionMarks(this, marks);
}
return marks.map(this.correctDataNames);
};
UnitModel.prototype.assembleLayoutSize = function () {
return {
width: this.getSizeSignalRef('width'),
height: this.getSizeSignalRef('height')
};
};
UnitModel.prototype.getMapping = function () {
return this.encoding;
};
UnitModel.prototype.toSpec = function (excludeConfig, excludeData) {
var encoding = util_1.duplicate(this.encoding);
var spec;
spec = {
mark: this.markDef,
encoding: encoding
};
if (!excludeConfig) {
spec.config = util_1.duplicate(this.config);
}
if (!excludeData) {
spec.data = util_1.duplicate(this.data);
}
// remove defaults
return spec;
};
UnitModel.prototype.mark = function () {
return this.markDef.type;
};
UnitModel.prototype.channelHasField = function (channel) {
return vlEncoding.channelHasField(this.encoding, channel);
};
UnitModel.prototype.fieldDef = function (channel) {
var channelDef = this.encoding[channel];
return fielddef_1.getFieldDef(channelDef);
};
return UnitModel;
}(model_1.ModelWithField));
exports.UnitModel = UnitModel;
},{"../channel":12,"../encoding":94,"../fielddef":96,"../mark":103,"../stack":108,"../util":114,"./axis/parse":16,"./data/parse":37,"./layoutsize/assemble":44,"./layoutsize/parse":45,"./mark/init":53,"./mark/mark":55,"./model":63,"./repeater":65,"./selection/selection":76,"tslib":5}],88:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var vega_util_1 = require("vega-util");
var encoding_1 = require("../encoding");
var encoding_2 = require("./../encoding");
var fielddef_1 = require("./../fielddef");
var log = require("./../log");
exports.BOXPLOT = 'box-plot';
function isBoxPlotDef(mark) {
return !!mark['type'];
}
exports.isBoxPlotDef = isBoxPlotDef;
exports.BOXPLOT_STYLES = ['boxWhisker', 'box', 'boxMid'];
exports.VL_ONLY_BOXPLOT_CONFIG_PROPERTY_INDEX = {
box: ['size']
};
var supportedChannels = ['x', 'y', 'color', 'detail', 'opacity', 'size'];
function filterUnsupportedChannels(spec) {
return tslib_1.__assign({}, spec, { encoding: encoding_1.reduce(spec.encoding, function (newEncoding, fieldDef, channel) {
if (supportedChannels.indexOf(channel) > -1) {
newEncoding[channel] = fieldDef;
}
else {
log.warn(log.message.incompatibleChannel(channel, exports.BOXPLOT));
}
return newEncoding;
}, {}) });
}
exports.filterUnsupportedChannels = filterUnsupportedChannels;
function normalizeBoxPlot(spec, config) {
spec = filterUnsupportedChannels(spec);
// TODO: use selection
var mark = spec.mark, encoding = spec.encoding, selection = spec.selection, outerSpec = tslib_1.__rest(spec, ["mark", "encoding", "selection"]);
var kIQRScalar = undefined;
if (isBoxPlotDef(mark)) {
if (mark.extent) {
if (vega_util_1.isNumber(mark.extent)) {
kIQRScalar = mark.extent;
}
}
}
var orient = boxOrient(spec);
var _a = boxParams(spec, orient, kIQRScalar), transform = _a.transform, continuousAxisChannelDef = _a.continuousAxisChannelDef, continuousAxis = _a.continuousAxis, encodingWithoutContinuousAxis = _a.encodingWithoutContinuousAxis;
var size = encodingWithoutContinuousAxis.size, color = encodingWithoutContinuousAxis.color, nonPositionEncodingWithoutColorSize = tslib_1.__rest(encodingWithoutContinuousAxis, ["size", "color"]);
var sizeMixins = size ? { size: size } : { size: { value: config.box.size } };
var continuousAxisScaleAndAxis = {};
if (continuousAxisChannelDef.scale) {
continuousAxisScaleAndAxis['scale'] = continuousAxisChannelDef.scale;
}
if (continuousAxisChannelDef.axis) {
continuousAxisScaleAndAxis['axis'] = continuousAxisChannelDef.axis;
}
return tslib_1.__assign({}, outerSpec, { transform: transform, layer: [
{
mark: {
type: 'rule',
style: 'boxWhisker'
},
encoding: tslib_1.__assign((_b = {}, _b[continuousAxis] = tslib_1.__assign({ field: 'lowerWhisker', type: continuousAxisChannelDef.type }, continuousAxisScaleAndAxis), _b[continuousAxis + '2'] = {
field: 'lowerBox',
type: continuousAxisChannelDef.type
}, _b), nonPositionEncodingWithoutColorSize)
}, {
mark: {
type: 'rule',
style: 'boxWhisker'
},
encoding: tslib_1.__assign((_c = {}, _c[continuousAxis] = {
field: 'upperBox',
type: continuousAxisChannelDef.type
}, _c[continuousAxis + '2'] = {
field: 'upperWhisker',
type: continuousAxisChannelDef.type
}, _c), nonPositionEncodingWithoutColorSize)
},
tslib_1.__assign({}, (selection ? { selection: selection } : {}), { mark: {
type: 'bar',
style: 'box'
}, encoding: tslib_1.__assign((_d = {}, _d[continuousAxis] = {
field: 'lowerBox',
type: continuousAxisChannelDef.type
}, _d[continuousAxis + '2'] = {
field: 'upperBox',
type: continuousAxisChannelDef.type
}, _d), encodingWithoutContinuousAxis, sizeMixins) }),
{
mark: {
type: 'tick',
style: 'boxMid'
},
encoding: tslib_1.__assign((_e = {}, _e[continuousAxis] = {
field: 'midBox',
type: continuousAxisChannelDef.type
}, _e), nonPositionEncodingWithoutColorSize, sizeMixins)
}
] });
var _b, _c, _d, _e;
}
exports.normalizeBoxPlot = normalizeBoxPlot;
function boxOrient(spec) {
var mark = spec.mark, encoding = spec.encoding, _outerSpec = tslib_1.__rest(spec, ["mark", "encoding"]);
if (fielddef_1.isFieldDef(encoding.x) && fielddef_1.isContinuous(encoding.x)) {
// x is continuous
if (fielddef_1.isFieldDef(encoding.y) && fielddef_1.isContinuous(encoding.y)) {
// both x and y are continuous
if (encoding.x.aggregate === undefined && encoding.y.aggregate === exports.BOXPLOT) {
return 'vertical';
}
else if (encoding.y.aggregate === undefined && encoding.x.aggregate === exports.BOXPLOT) {
return 'horizontal';
}
else if (encoding.x.aggregate === exports.BOXPLOT && encoding.y.aggregate === exports.BOXPLOT) {
throw new Error('Both x and y cannot have aggregate');
}
else {
if (isBoxPlotDef(mark) && mark.orient) {
return mark.orient;
}
// default orientation = vertical
return 'vertical';
}
}
// x is continuous but y is not
return 'horizontal';
}
else if (fielddef_1.isFieldDef(encoding.y) && fielddef_1.isContinuous(encoding.y)) {
// y is continuous but x is not
return 'vertical';
}
else {
// Neither x nor y is continuous.
throw new Error('Need a valid continuous axis for boxplots');
}
}
function boxContinousAxis(spec, orient) {
var mark = spec.mark, encoding = spec.encoding, _outerSpec = tslib_1.__rest(spec, ["mark", "encoding"]);
var continuousAxisChannelDef;
var continuousAxis;
if (orient === 'vertical') {
continuousAxis = 'y';
continuousAxisChannelDef = encoding.y; // Safe to cast because if y is not continous fielddef, the orient would not be vertical.
}
else {
continuousAxis = 'x';
continuousAxisChannelDef = encoding.x; // Safe to cast because if x is not continous fielddef, the orient would not be horizontal.
}
if (continuousAxisChannelDef && continuousAxisChannelDef.aggregate) {
var aggregate = continuousAxisChannelDef.aggregate, continuousAxisWithoutAggregate = tslib_1.__rest(continuousAxisChannelDef, ["aggregate"]);
if (aggregate !== exports.BOXPLOT) {
log.warn("Continuous axis should not have customized aggregation function " + aggregate);
}
continuousAxisChannelDef = continuousAxisWithoutAggregate;
}
return {
continuousAxisChannelDef: continuousAxisChannelDef,
continuousAxis: continuousAxis
};
}
function boxParams(spec, orient, kIQRScalar) {
var _a = boxContinousAxis(spec, orient), continuousAxisChannelDef = _a.continuousAxisChannelDef, continuousAxis = _a.continuousAxis;
var encoding = spec.encoding;
var isMinMax = kIQRScalar === undefined;
var summarize = [
{
aggregate: 'q1',
field: continuousAxisChannelDef.field,
as: 'lowerBox'
},
{
aggregate: 'q3',
field: continuousAxisChannelDef.field,
as: 'upperBox'
},
{
aggregate: 'median',
field: continuousAxisChannelDef.field,
as: 'midBox'
}
];
var postAggregateCalculates = [];
if (isMinMax) {
summarize.push({
aggregate: 'min',
field: continuousAxisChannelDef.field,
as: 'lowerWhisker'
});
summarize.push({
aggregate: 'max',
field: continuousAxisChannelDef.field,
as: 'upperWhisker'
});
}
else {
postAggregateCalculates = [
{
calculate: 'datum.upperBox - datum.lowerBox',
as: 'IQR'
},
{
calculate: 'datum.lowerBox - datum.IQR * ' + kIQRScalar,
as: 'lowerWhisker'
},
{
calculate: 'datum.upperBox + datum.IQR * ' + kIQRScalar,
as: 'lowerWhisker'
}
];
}
var groupby = [];
var bins = [];
var timeUnits = [];
var encodingWithoutContinuousAxis = {};
encoding_2.forEach(encoding, function (channelDef, channel) {
if (channel === continuousAxis) {
// Skip continuous axis as we already handle it separately
return;
}
if (fielddef_1.isFieldDef(channelDef)) {
if (channelDef.aggregate && channelDef.aggregate !== exports.BOXPLOT) {
summarize.push({
aggregate: channelDef.aggregate,
field: channelDef.field,
as: fielddef_1.field(channelDef)
});
}
else if (channelDef.aggregate === undefined) {
var transformedField = fielddef_1.field(channelDef);
// Add bin or timeUnit transform if applicable
var bin = channelDef.bin;
if (bin) {
var field_1 = channelDef.field;
bins.push({ bin: bin, field: field_1, as: transformedField });
}
else if (channelDef.timeUnit) {
var timeUnit = channelDef.timeUnit, field_2 = channelDef.field;
timeUnits.push({ timeUnit: timeUnit, field: field_2, as: transformedField });
}
groupby.push(transformedField);
}
// now the field should refer to post-transformed field instead
encodingWithoutContinuousAxis[channel] = {
field: fielddef_1.field(channelDef),
type: channelDef.type
};
}
else {
// For value def, just copy
encodingWithoutContinuousAxis[channel] = encoding[channel];
}
});
return {
transform: [].concat(bins, timeUnits, [{ summarize: summarize, groupby: groupby }], postAggregateCalculates),
continuousAxisChannelDef: continuousAxisChannelDef,
continuousAxis: continuousAxis,
encodingWithoutContinuousAxis: encodingWithoutContinuousAxis
};
}
},{"../encoding":94,"./../encoding":94,"./../fielddef":96,"./../log":101,"tslib":5,"vega-util":7}],89:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
exports.ERRORBAR = 'error-bar';
function normalizeErrorBar(spec) {
// TODO: use selection
var _m = spec.mark, _sel = spec.selection, encoding = spec.encoding, outerSpec = tslib_1.__rest(spec, ["mark", "selection", "encoding"]);
var _s = encoding.size, encodingWithoutSize = tslib_1.__rest(encoding, ["size"]);
var _x2 = encoding.x2, _y2 = encoding.y2, encodingWithoutX2Y2 = tslib_1.__rest(encoding, ["x2", "y2"]);
var _x = encodingWithoutX2Y2.x, _y = encodingWithoutX2Y2.y, encodingWithoutX_X2_Y_Y2 = tslib_1.__rest(encodingWithoutX2Y2, ["x", "y"]);
if (!encoding.x2 && !encoding.y2) {
throw new Error('Neither x2 or y2 provided');
}
return tslib_1.__assign({}, outerSpec, { layer: [
{
mark: 'rule',
encoding: encodingWithoutSize
}, {
mark: 'tick',
encoding: encodingWithoutX2Y2
}, {
mark: 'tick',
encoding: encoding.x2 ? tslib_1.__assign({ x: encoding.x2, y: encoding.y }, encodingWithoutX_X2_Y_Y2) : tslib_1.__assign({ x: encoding.x, y: encoding.y2 }, encodingWithoutX_X2_Y_Y2)
}
] });
}
exports.normalizeErrorBar = normalizeErrorBar;
},{"tslib":5}],90:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var mark_1 = require("./../mark");
var boxplot_1 = require("./boxplot");
var errorbar_1 = require("./errorbar");
/**
* Registry index for all composite mark's normalizer
*/
var normalizerRegistry = {};
function add(mark, normalizer) {
normalizerRegistry[mark] = normalizer;
}
exports.add = add;
function remove(mark) {
delete normalizerRegistry[mark];
}
exports.remove = remove;
exports.COMPOSITE_MARK_STYLES = boxplot_1.BOXPLOT_STYLES;
exports.VL_ONLY_COMPOSITE_MARK_SPECIFIC_CONFIG_PROPERTY_INDEX = tslib_1.__assign({}, boxplot_1.VL_ONLY_BOXPLOT_CONFIG_PROPERTY_INDEX);
add(boxplot_1.BOXPLOT, boxplot_1.normalizeBoxPlot);
add(errorbar_1.ERRORBAR, errorbar_1.normalizeErrorBar);
/**
* Transform a unit spec with composite mark into a normal layer spec.
*/
function normalize(
// This GenericUnitSpec has any as Encoding because unit specs with composite mark can have additional encoding channels.
spec, config) {
var mark = mark_1.isMarkDef(spec.mark) ? spec.mark.type : spec.mark;
var normalizer = normalizerRegistry[mark];
if (normalizer) {
return normalizer(spec, config);
}
throw new Error("Unregistered composite mark " + mark);
}
exports.normalize = normalize;
},{"./../mark":103,"./boxplot":88,"./errorbar":89,"tslib":5}],91:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var compositemark_1 = require("./compositemark");
var index_1 = require("./compositemark/index");
var guide_1 = require("./guide");
var legend_1 = require("./legend");
var mark_1 = require("./mark");
var mark = require("./mark");
var scale_1 = require("./scale");
var selection_1 = require("./selection");
var title_1 = require("./title");
var util_1 = require("./util");
exports.defaultViewConfig = {
width: 200,
height: 200
};
exports.defaultConfig = {
padding: 5,
timeFormat: '%b %d, %Y',
countTitle: 'Number of Records',
invalidValues: 'filter',
view: exports.defaultViewConfig,
mark: mark.defaultMarkConfig,
area: {},
bar: mark.defaultBarConfig,
circle: {},
line: {},
point: {},
rect: {},
rule: { color: 'black' },
square: {},
text: { color: 'black' },
tick: mark.defaultTickConfig,
box: { size: 14 },
boxWhisker: {},
boxMid: { color: 'white' },
scale: scale_1.defaultScaleConfig,
axis: {},
axisX: {},
axisY: { minExtent: 30 },
axisLeft: {},
axisRight: {},
axisTop: {},
axisBottom: {},
axisBand: {},
legend: legend_1.defaultLegendConfig,
selection: selection_1.defaultConfig,
style: {},
title: {},
};
function initConfig(config) {
return util_1.mergeDeep(util_1.duplicate(exports.defaultConfig), config);
}
exports.initConfig = initConfig;
var MARK_STYLES = ['view'].concat(mark_1.PRIMITIVE_MARKS, compositemark_1.COMPOSITE_MARK_STYLES);
var VL_ONLY_CONFIG_PROPERTIES = [
'padding', 'numberFormat', 'timeFormat', 'countTitle',
'stack', 'scale', 'selection', 'invalidValues',
'overlay' // FIXME: Redesign and unhide this
];
var VL_ONLY_ALL_MARK_SPECIFIC_CONFIG_PROPERTY_INDEX = tslib_1.__assign({ view: ['width', 'height'] }, mark_1.VL_ONLY_MARK_SPECIFIC_CONFIG_PROPERTY_INDEX, index_1.VL_ONLY_COMPOSITE_MARK_SPECIFIC_CONFIG_PROPERTY_INDEX);
function stripAndRedirectConfig(config) {
config = util_1.duplicate(config);
for (var _i = 0, VL_ONLY_CONFIG_PROPERTIES_1 = VL_ONLY_CONFIG_PROPERTIES; _i < VL_ONLY_CONFIG_PROPERTIES_1.length; _i++) {
var prop = VL_ONLY_CONFIG_PROPERTIES_1[_i];
delete config[prop];
}
// Remove Vega-Lite only axis/legend config
if (config.axis) {
for (var _a = 0, VL_ONLY_GUIDE_CONFIG_1 = guide_1.VL_ONLY_GUIDE_CONFIG; _a < VL_ONLY_GUIDE_CONFIG_1.length; _a++) {
var prop = VL_ONLY_GUIDE_CONFIG_1[_a];
delete config.axis[prop];
}
}
if (config.legend) {
for (var _b = 0, VL_ONLY_GUIDE_CONFIG_2 = guide_1.VL_ONLY_GUIDE_CONFIG; _b < VL_ONLY_GUIDE_CONFIG_2.length; _b++) {
var prop = VL_ONLY_GUIDE_CONFIG_2[_b];
delete config.legend[prop];
}
}
// Remove Vega-Lite only generic mark config
if (config.mark) {
for (var _c = 0, VL_ONLY_MARK_CONFIG_PROPERTIES_1 = mark_1.VL_ONLY_MARK_CONFIG_PROPERTIES; _c < VL_ONLY_MARK_CONFIG_PROPERTIES_1.length; _c++) {
var prop = VL_ONLY_MARK_CONFIG_PROPERTIES_1[_c];
delete config.mark[prop];
}
}
for (var _d = 0, MARK_STYLES_1 = MARK_STYLES; _d < MARK_STYLES_1.length; _d++) {
var mark_2 = MARK_STYLES_1[_d];
// Remove Vega-Lite-only mark config
for (var _e = 0, VL_ONLY_MARK_CONFIG_PROPERTIES_2 = mark_1.VL_ONLY_MARK_CONFIG_PROPERTIES; _e < VL_ONLY_MARK_CONFIG_PROPERTIES_2.length; _e++) {
var prop = VL_ONLY_MARK_CONFIG_PROPERTIES_2[_e];
delete config[mark_2][prop];
}
// Remove Vega-Lite only mark-specific config
var vlOnlyMarkSpecificConfigs = VL_ONLY_ALL_MARK_SPECIFIC_CONFIG_PROPERTY_INDEX[mark_2];
if (vlOnlyMarkSpecificConfigs) {
for (var _f = 0, vlOnlyMarkSpecificConfigs_1 = vlOnlyMarkSpecificConfigs; _f < vlOnlyMarkSpecificConfigs_1.length; _f++) {
var prop = vlOnlyMarkSpecificConfigs_1[_f];
delete config[mark_2][prop];
}
}
// Redirect mark config to config.style so that mark config only affect its own mark type
// without affecting other marks that share the same underlying Vega marks.
// For example, config.rect should not affect bar marks.
redirectConfig(config, mark_2);
}
// Redirect config.title -- so that title config do not
// affect header labels, which also uses `title` directive to implement.
redirectConfig(config, 'title', 'group-title');
// Remove empty config objects
for (var prop in config) {
if (util_1.isObject(config[prop]) && util_1.keys(config[prop]).length === 0) {
delete config[prop];
}
}
return util_1.keys(config).length > 0 ? config : undefined;
}
exports.stripAndRedirectConfig = stripAndRedirectConfig;
function redirectConfig(config, prop, toProp) {
var propConfig = prop === 'title' ? title_1.extractTitleConfig(config.title).mark : config[prop];
if (prop === 'view') {
toProp = 'cell'; // View's default style is "cell"
}
var style = tslib_1.__assign({}, propConfig, config.style[prop]);
// set config.style if it is not an empty object
if (util_1.keys(style).length > 0) {
config.style[toProp || prop] = style;
}
delete config[prop];
}
},{"./compositemark":90,"./compositemark/index":90,"./guide":98,"./legend":100,"./mark":103,"./scale":104,"./selection":105,"./title":110,"./util":114,"tslib":5}],92:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function isUrlData(data) {
return !!data['url'];
}
exports.isUrlData = isUrlData;
function isInlineData(data) {
return !!data['values'];
}
exports.isInlineData = isInlineData;
function isNamedData(data) {
return !!data['name'];
}
exports.isNamedData = isNamedData;
exports.MAIN = 'main';
exports.RAW = 'raw';
},{}],93:[function(require,module,exports){
"use strict";
// DateTime definition object
Object.defineProperty(exports, "__esModule", { value: true });
var log = require("./log");
var util_1 = require("./util");
/*
* A designated year that starts on Sunday.
*/
var SUNDAY_YEAR = 2006;
function isDateTime(o) {
return !!o && (!!o.year || !!o.quarter || !!o.month || !!o.date || !!o.day ||
!!o.hours || !!o.minutes || !!o.seconds || !!o.milliseconds);
}
exports.isDateTime = isDateTime;
exports.MONTHS = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'];
exports.SHORT_MONTHS = exports.MONTHS.map(function (m) { return m.substr(0, 3); });
exports.DAYS = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
exports.SHORT_DAYS = exports.DAYS.map(function (d) { return d.substr(0, 3); });
function normalizeQuarter(q) {
if (util_1.isNumber(q)) {
if (q > 4) {
log.warn(log.message.invalidTimeUnit('quarter', q));
}
// We accept 1-based quarter, so need to readjust to 0-based quarter
return (q - 1) + '';
}
else {
// Invalid quarter
throw new Error(log.message.invalidTimeUnit('quarter', q));
}
}
function normalizeMonth(m) {
if (util_1.isNumber(m)) {
// We accept 1-based month, so need to readjust to 0-based month
return (m - 1) + '';
}
else {
var lowerM = m.toLowerCase();
var monthIndex = exports.MONTHS.indexOf(lowerM);
if (monthIndex !== -1) {
return monthIndex + ''; // 0 for january, ...
}
var shortM = lowerM.substr(0, 3);
var shortMonthIndex = exports.SHORT_MONTHS.indexOf(shortM);
if (shortMonthIndex !== -1) {
return shortMonthIndex + '';
}
// Invalid month
throw new Error(log.message.invalidTimeUnit('month', m));
}
}
function normalizeDay(d) {
if (util_1.isNumber(d)) {
// mod so that this can be both 0-based where 0 = sunday
// and 1-based where 7=sunday
return (d % 7) + '';
}
else {
var lowerD = d.toLowerCase();
var dayIndex = exports.DAYS.indexOf(lowerD);
if (dayIndex !== -1) {
return dayIndex + ''; // 0 for january, ...
}
var shortD = lowerD.substr(0, 3);
var shortDayIndex = exports.SHORT_DAYS.indexOf(shortD);
if (shortDayIndex !== -1) {
return shortDayIndex + '';
}
// Invalid day
throw new Error(log.message.invalidTimeUnit('day', d));
}
}
/**
* Return Vega Expression for a particular date time.
* @param d
* @param normalize whether to normalize quarter, month, day.
*/
function dateTimeExpr(d, normalize) {
if (normalize === void 0) { normalize = false; }
var units = [];
if (normalize && d.day !== undefined) {
if (util_1.keys(d).length > 1) {
log.warn(log.message.droppedDay(d));
d = util_1.duplicate(d);
delete d.day;
}
}
if (d.year !== undefined) {
units.push(d.year);
}
else if (d.day !== undefined) {
// Set year to 2006 for working with day since January 1 2006 is a Sunday
units.push(SUNDAY_YEAR);
}
else {
units.push(0);
}
if (d.month !== undefined) {
var month = normalize ? normalizeMonth(d.month) : d.month;
units.push(month);
}
else if (d.quarter !== undefined) {
var quarter = normalize ? normalizeQuarter(d.quarter) : d.quarter;
units.push(quarter + '*3');
}
else {
units.push(0); // months start at zero in JS
}
if (d.date !== undefined) {
units.push(d.date);
}
else if (d.day !== undefined) {
// HACK: Day only works as a standalone unit
// This is only correct because we always set year to 2006 for day
var day = normalize ? normalizeDay(d.day) : d.day;
units.push(day + '+1');
}
else {
units.push(1); // Date starts at 1 in JS
}
// Note: can't use TimeUnit enum here as importing it will create
// circular dependency problem!
for (var _i = 0, _a = ['hours', 'minutes', 'seconds', 'milliseconds']; _i < _a.length; _i++) {
var timeUnit = _a[_i];
if (d[timeUnit] !== undefined) {
units.push(d[timeUnit]);
}
else {
units.push(0);
}
}
if (d.utc) {
return "utc(" + units.join(', ') + ")";
}
else {
return "datetime(" + units.join(', ') + ")";
}
}
exports.dateTimeExpr = dateTimeExpr;
},{"./log":101,"./util":114}],94:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var channel_1 = require("./channel");
var fielddef_1 = require("./fielddef");
var log = require("./log");
var util_1 = require("./util");
function channelHasField(encoding, channel) {
var channelDef = encoding && encoding[channel];
if (channelDef) {
if (util_1.isArray(channelDef)) {
return util_1.some(channelDef, function (fieldDef) { return !!fieldDef.field; });
}
else {
return fielddef_1.isFieldDef(channelDef) || fielddef_1.hasConditionFieldDef(channelDef);
}
}
return false;
}
exports.channelHasField = channelHasField;
function isAggregate(encoding) {
return util_1.some(channel_1.CHANNELS, function (channel) {
if (channelHasField(encoding, channel)) {
var channelDef = encoding[channel];
if (util_1.isArray(channelDef)) {
return util_1.some(channelDef, function (fieldDef) { return !!fieldDef.aggregate; });
}
else {
var fieldDef = fielddef_1.getFieldDef(channelDef);
return fieldDef && !!fieldDef.aggregate;
}
}
return false;
});
}
exports.isAggregate = isAggregate;
function normalizeEncoding(encoding, mark) {
return util_1.keys(encoding).reduce(function (normalizedEncoding, channel) {
if (!channel_1.supportMark(channel, mark)) {
// Drop unsupported channel
log.warn(log.message.incompatibleChannel(channel, mark));
return normalizedEncoding;
}
// Drop line's size if the field is aggregated.
if (channel === 'size' && mark === 'line') {
var fieldDef = fielddef_1.getFieldDef(encoding[channel]);
if (fieldDef && fieldDef.aggregate) {
log.warn(log.message.incompatibleChannel(channel, mark, 'when the field is aggregated.'));
return normalizedEncoding;
}
}
if (channel === 'detail' || channel === 'order') {
var channelDef = encoding[channel];
if (channelDef) {
// Array of fieldDefs for detail channel (or production rule)
normalizedEncoding[channel] = (util_1.isArray(channelDef) ? channelDef : [channelDef])
.reduce(function (fieldDefs, fieldDef) {
if (!fielddef_1.isFieldDef(fieldDef)) {
log.warn(log.message.emptyFieldDef(fieldDef, channel));
}
else {
fieldDefs.push(fielddef_1.normalizeFieldDef(fieldDef, channel));
}
return fieldDefs;
}, []);
}
}
else {
// FIXME: remove this casting. (I don't know why Typescript doesn't infer this correctly here.)
var channelDef = encoding[channel];
if (!fielddef_1.isFieldDef(channelDef) && !fielddef_1.isValueDef(channelDef) && !fielddef_1.isConditionalDef(channelDef)) {
log.warn(log.message.emptyFieldDef(channelDef, channel));
return normalizedEncoding;
}
normalizedEncoding[channel] = fielddef_1.normalize(channelDef, channel);
}
return normalizedEncoding;
}, {});
}
exports.normalizeEncoding = normalizeEncoding;
function isRanged(encoding) {
return encoding && ((!!encoding.x && !!encoding.x2) || (!!encoding.y && !!encoding.y2));
}
exports.isRanged = isRanged;
function fieldDefs(encoding) {
var arr = [];
channel_1.CHANNELS.forEach(function (channel) {
if (channelHasField(encoding, channel)) {
var channelDef = encoding[channel];
(util_1.isArray(channelDef) ? channelDef : [channelDef]).forEach(function (def) {
if (fielddef_1.isFieldDef(def)) {
arr.push(def);
}
else if (fielddef_1.hasConditionFieldDef(def)) {
arr.push(def.condition);
}
});
}
});
return arr;
}
exports.fieldDefs = fieldDefs;
function forEach(mapping, f, thisArg) {
if (!mapping) {
return;
}
util_1.keys(mapping).forEach(function (c) {
var channel = c;
if (util_1.isArray(mapping[channel])) {
mapping[channel].forEach(function (channelDef) {
f.call(thisArg, channelDef, channel);
});
}
else {
f.call(thisArg, mapping[channel], channel);
}
});
}
exports.forEach = forEach;
function reduce(mapping, f, init, thisArg) {
if (!mapping) {
return init;
}
return util_1.keys(mapping).reduce(function (r, c) {
var channel = c;
if (util_1.isArray(mapping[channel])) {
return mapping[channel].reduce(function (r1, channelDef) {
return f.call(thisArg, r1, channelDef, channel);
}, r);
}
else {
return f.call(thisArg, r, mapping[channel], channel);
}
}, init);
}
exports.reduce = reduce;
},{"./channel":12,"./fielddef":96,"./log":101,"./util":114}],95:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
},{}],96:[function(require,module,exports){
"use strict";
// utility for a field definition object
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var aggregate_1 = require("./aggregate");
var bin_1 = require("./bin");
var channel_1 = require("./channel");
var log = require("./log");
var timeunit_1 = require("./timeunit");
var type_1 = require("./type");
var util_1 = require("./util");
function isRepeatRef(field) {
return field && !util_1.isString(field) && 'repeat' in field;
}
exports.isRepeatRef = isRepeatRef;
function isConditionalDef(channelDef) {
return !!channelDef && !!channelDef.condition;
}
exports.isConditionalDef = isConditionalDef;
/**
* Return if a channelDef is a ConditionalValueDef with ConditionFieldDef
*/
function hasConditionFieldDef(channelDef) {
return !!channelDef && !!channelDef.condition && isFieldDef(channelDef.condition);
}
exports.hasConditionFieldDef = hasConditionFieldDef;
function isFieldDef(channelDef) {
return !!channelDef && (!!channelDef['field'] || channelDef['aggregate'] === 'count');
}
exports.isFieldDef = isFieldDef;
function isValueDef(channelDef) {
return channelDef && 'value' in channelDef && channelDef['value'] !== undefined;
}
exports.isValueDef = isValueDef;
function isScaleFieldDef(channelDef) {
return !!channelDef && (!!channelDef['scale'] || !!channelDef['sort']);
}
exports.isScaleFieldDef = isScaleFieldDef;
function field(fieldDef, opt) {
if (opt === void 0) { opt = {}; }
var field = fieldDef.field;
var prefix = opt.prefix;
var suffix = opt.suffix;
if (isCount(fieldDef)) {
field = 'count_*';
}
else {
var fn = undefined;
if (!opt.nofn) {
if (fieldDef.bin) {
fn = bin_1.binToString(fieldDef.bin);
suffix = opt.binSuffix || '';
}
else if (fieldDef.aggregate) {
fn = String(opt.aggregate || fieldDef.aggregate);
}
else if (fieldDef.timeUnit) {
fn = String(fieldDef.timeUnit);
}
}
if (fn) {
field = fn + "_" + field;
}
}
if (suffix) {
field = field + "_" + suffix;
}
if (prefix) {
field = prefix + "_" + field;
}
if (opt.expr) {
field = opt.expr + "[" + util_1.stringValue(field) + "]";
}
return field;
}
exports.field = field;
function isDiscrete(fieldDef) {
switch (fieldDef.type) {
case 'nominal':
case 'ordinal':
return true;
case 'quantitative':
return !!fieldDef.bin;
case 'temporal':
return false;
}
throw new Error(log.message.invalidFieldType(fieldDef.type));
}
exports.isDiscrete = isDiscrete;
function isContinuous(fieldDef) {
return !isDiscrete(fieldDef);
}
exports.isContinuous = isContinuous;
function isCount(fieldDef) {
return fieldDef.aggregate === 'count';
}
exports.isCount = isCount;
function title(fieldDef, config) {
if (isCount(fieldDef)) {
return config.countTitle;
}
var fn = fieldDef.aggregate || fieldDef.timeUnit || (fieldDef.bin && 'bin');
if (fn) {
return fn.toUpperCase() + '(' + fieldDef.field + ')';
}
else {
return fieldDef.field;
}
}
exports.title = title;
function defaultType(fieldDef, channel) {
if (fieldDef.timeUnit) {
return 'temporal';
}
if (fieldDef.bin) {
return 'quantitative';
}
switch (channel_1.rangeType(channel)) {
case 'continuous':
return 'quantitative';
case 'discrete':
return 'nominal';
case 'flexible':// color
return 'nominal';
default:
return 'quantitative';
}
}
exports.defaultType = defaultType;
/**
* Returns the fieldDef -- either from the outer channelDef or from the condition of channelDef.
* @param channelDef
*/
function getFieldDef(channelDef) {
if (isFieldDef(channelDef)) {
return channelDef;
}
else if (hasConditionFieldDef(channelDef)) {
return channelDef.condition;
}
return undefined;
}
exports.getFieldDef = getFieldDef;
/**
* Convert type to full, lowercase type, or augment the fieldDef with a default type if missing.
*/
function normalize(channelDef, channel) {
// If a fieldDef contains a field, we need type.
if (isFieldDef(channelDef)) {
return normalizeFieldDef(channelDef, channel);
}
else if (hasConditionFieldDef(channelDef)) {
return tslib_1.__assign({}, channelDef, {
// Need to cast as normalizeFieldDef normally return FieldDef, but here we know that it is definitely Condition<FieldDef>
condition: normalizeFieldDef(channelDef.condition, channel) });
}
return channelDef;
}
exports.normalize = normalize;
function normalizeFieldDef(fieldDef, channel) {
// Drop invalid aggregate
if (fieldDef.aggregate && !aggregate_1.isAggregateOp(fieldDef.aggregate)) {
var aggregate = fieldDef.aggregate, fieldDefWithoutAggregate = tslib_1.__rest(fieldDef, ["aggregate"]);
log.warn(log.message.invalidAggregate(fieldDef.aggregate));
fieldDef = fieldDefWithoutAggregate;
}
// Normalize Time Unit
if (fieldDef.timeUnit) {
fieldDef = tslib_1.__assign({}, fieldDef, { timeUnit: timeunit_1.normalizeTimeUnit(fieldDef.timeUnit) });
}
// Normalize bin
if (fieldDef.bin) {
fieldDef = tslib_1.__assign({}, fieldDef, { bin: normalizeBin(fieldDef.bin, channel) });
}
// Normalize Type
if (fieldDef.type) {
var fullType = type_1.getFullName(fieldDef.type);
if (fieldDef.type !== fullType) {
// convert short type to full type
fieldDef = tslib_1.__assign({}, fieldDef, { type: fullType });
}
if (fieldDef.type !== 'quantitative') {
if (aggregate_1.isCountingAggregateOp(fieldDef.aggregate)) {
log.warn(log.message.invalidFieldTypeForCountAggregate(fieldDef.type, fieldDef.aggregate));
fieldDef = tslib_1.__assign({}, fieldDef, { type: 'quantitative' });
}
}
}
else {
// If type is empty / invalid, then augment with default type
var newType = defaultType(fieldDef, channel);
log.warn(log.message.emptyOrInvalidFieldType(fieldDef.type, channel, newType));
fieldDef = tslib_1.__assign({}, fieldDef, { type: newType });
}
var _a = channelCompatibility(fieldDef, channel), compatible = _a.compatible, warning = _a.warning;
if (!compatible) {
log.warn(warning);
}
return fieldDef;
}
exports.normalizeFieldDef = normalizeFieldDef;
function normalizeBin(bin, channel) {
if (util_1.isBoolean(bin)) {
return { maxbins: bin_1.autoMaxBins(channel) };
}
else if (!bin.maxbins && !bin.step) {
return tslib_1.__assign({}, bin, { maxbins: bin_1.autoMaxBins(channel) });
}
else {
return bin;
}
}
exports.normalizeBin = normalizeBin;
var COMPATIBLE = { compatible: true };
function channelCompatibility(fieldDef, channel) {
switch (channel) {
case 'row':
case 'column':
if (isContinuous(fieldDef) && !fieldDef.timeUnit) {
// TODO:(https://github.com/vega/vega-lite/issues/2011):
// with timeUnit it's not always strictly continuous
return {
compatible: false,
warning: log.message.facetChannelShouldBeDiscrete(channel)
};
}
return COMPATIBLE;
case 'x':
case 'y':
case 'color':
case 'text':
case 'detail':
case 'tooltip':
return COMPATIBLE;
case 'opacity':
case 'size':
case 'x2':
case 'y2':
if (isDiscrete(fieldDef) && !fieldDef.bin) {
return {
compatible: false,
warning: "Channel " + channel + " should not be used with discrete field."
};
}
return COMPATIBLE;
case 'shape':
if (fieldDef.type !== 'nominal') {
return {
compatible: false,
warning: 'Shape channel should be used with nominal data only'
};
}
return COMPATIBLE;
case 'order':
if (fieldDef.type === 'nominal') {
return {
compatible: false,
warning: "Channel order is inappropriate for nominal field, which has no inherent order."
};
}
return COMPATIBLE;
}
throw new Error('channelCompatability not implemented for channel ' + channel);
}
exports.channelCompatibility = channelCompatibility;
function isNumberFieldDef(fieldDef) {
return fieldDef.type === 'quantitative' || !!fieldDef.bin;
}
exports.isNumberFieldDef = isNumberFieldDef;
function isTimeFieldDef(fieldDef) {
return fieldDef.type === 'temporal' || !!fieldDef.timeUnit;
}
exports.isTimeFieldDef = isTimeFieldDef;
},{"./aggregate":9,"./bin":11,"./channel":12,"./log":101,"./timeunit":109,"./type":113,"./util":114,"tslib":5}],97:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var selection_1 = require("./compile/selection/selection");
var datetime_1 = require("./datetime");
var fielddef_1 = require("./fielddef");
var timeunit_1 = require("./timeunit");
var util_1 = require("./util");
function isSelectionFilter(filter) {
return filter && filter['selection'];
}
exports.isSelectionFilter = isSelectionFilter;
function isEqualFilter(filter) {
return filter && !!filter.field && filter.equal !== undefined;
}
exports.isEqualFilter = isEqualFilter;
function isRangeFilter(filter) {
if (filter && filter.field) {
if (util_1.isArray(filter.range) && filter.range.length === 2) {
return true;
}
}
return false;
}
exports.isRangeFilter = isRangeFilter;
function isOneOfFilter(filter) {
return filter && !!filter.field && (util_1.isArray(filter.oneOf) ||
util_1.isArray(filter.in) // backward compatibility
);
}
exports.isOneOfFilter = isOneOfFilter;
function isFieldFilter(filter) {
return isOneOfFilter(filter) || isEqualFilter(filter) || isRangeFilter(filter);
}
exports.isFieldFilter = isFieldFilter;
/**
* Converts a filter into an expression.
*/
// model is only used for selection filters.
function expression(model, filterOp, node) {
return util_1.logicalExpr(filterOp, function (filter) {
if (util_1.isString(filter)) {
return filter;
}
else if (isSelectionFilter(filter)) {
return selection_1.predicate(model, filter.selection, node);
}
else {
return fieldFilterExpression(filter);
}
});
}
exports.expression = expression;
// This method is used by Voyager. Do not change its behavior without changing Voyager.
function fieldFilterExpression(filter, useInRange) {
if (useInRange === void 0) { useInRange = true; }
var fieldExpr = filter.timeUnit ?
// For timeUnit, cast into integer with time() so we can use ===, inrange, indexOf to compare values directly.
// TODO: We calculate timeUnit on the fly here. Consider if we would like to consolidate this with timeUnit pipeline
// TODO: support utc
('time(' + timeunit_1.fieldExpr(filter.timeUnit, filter.field) + ')') :
fielddef_1.field(filter, { expr: 'datum' });
if (isEqualFilter(filter)) {
return fieldExpr + '===' + valueExpr(filter.equal, filter.timeUnit);
}
else if (isOneOfFilter(filter)) {
// "oneOf" was formerly "in" -- so we need to add backward compatibility
var oneOf = filter.oneOf || filter['in'];
return 'indexof([' +
oneOf.map(function (v) { return valueExpr(v, filter.timeUnit); }).join(',') +
'], ' + fieldExpr + ') !== -1';
}
else if (isRangeFilter(filter)) {
var lower = filter.range[0];
var upper = filter.range[1];
if (lower !== null && upper !== null && useInRange) {
return 'inrange(' + fieldExpr + ', [' +
valueExpr(lower, filter.timeUnit) + ', ' +
valueExpr(upper, filter.timeUnit) + '])';
}
var exprs = [];
if (lower !== null) {
exprs.push(fieldExpr + " >= " + valueExpr(lower, filter.timeUnit));
}
if (upper !== null) {
exprs.push(fieldExpr + " <= " + valueExpr(upper, filter.timeUnit));
}
return exprs.length > 0 ? exprs.join(' && ') : 'true';
}
/* istanbul ignore next: it should never reach here */
throw new Error("Invalid field filter: " + JSON.stringify(filter));
}
exports.fieldFilterExpression = fieldFilterExpression;
function valueExpr(v, timeUnit) {
if (datetime_1.isDateTime(v)) {
var expr = datetime_1.dateTimeExpr(v, true);
return 'time(' + expr + ')';
}
if (timeunit_1.isLocalSingleTimeUnit(timeUnit)) {
var datetime = {};
datetime[timeUnit] = v;
var expr = datetime_1.dateTimeExpr(datetime, true);
return 'time(' + expr + ')';
}
else if (timeunit_1.isUtcSingleTimeUnit(timeUnit)) {
return valueExpr(v, timeunit_1.getLocalTimeUnit(timeUnit));
}
return JSON.stringify(v);
}
function normalizeFilter(f) {
if (isFieldFilter(f) && f.timeUnit) {
return tslib_1.__assign({}, f, { timeUnit: timeunit_1.normalizeTimeUnit(f.timeUnit) });
}
return f;
}
exports.normalizeFilter = normalizeFilter;
},{"./compile/selection/selection":76,"./datetime":93,"./fielddef":96,"./timeunit":109,"./util":114,"tslib":5}],98:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.VL_ONLY_GUIDE_CONFIG = ['shortTimeLabels'];
},{}],99:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.axis = require("./axis");
exports.aggregate = require("./aggregate");
exports.bin = require("./bin");
exports.channel = require("./channel");
exports.compositeMark = require("./compositemark");
var compile_1 = require("./compile/compile");
exports.compile = compile_1.compile;
exports.config = require("./config");
exports.data = require("./data");
exports.datetime = require("./datetime");
exports.encoding = require("./encoding");
exports.facet = require("./facet");
exports.fieldDef = require("./fielddef");
exports.legend = require("./legend");
exports.mark = require("./mark");
exports.scale = require("./scale");
exports.sort = require("./sort");
exports.spec = require("./spec");
exports.stack = require("./stack");
exports.timeUnit = require("./timeunit");
exports.transform = require("./transform");
exports.type = require("./type");
exports.util = require("./util");
exports.validate = require("./validate");
exports.version = require('../package.json').version;
},{"../package.json":8,"./aggregate":9,"./axis":10,"./bin":11,"./channel":12,"./compile/compile":21,"./compositemark":90,"./config":91,"./data":92,"./datetime":93,"./encoding":94,"./facet":95,"./fielddef":96,"./legend":100,"./mark":103,"./scale":104,"./sort":106,"./spec":107,"./stack":108,"./timeunit":109,"./transform":112,"./type":113,"./util":114,"./validate":115}],100:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultLegendConfig = {};
exports.LEGEND_PROPERTIES = ['entryPadding', 'format', 'offset', 'orient', 'tickCount', 'title', 'type', 'values', 'zindex'];
exports.VG_LEGEND_PROPERTIES = [].concat(['fill', 'stroke', 'shape', 'size', 'opacity', 'encode'], exports.LEGEND_PROPERTIES);
},{}],101:[function(require,module,exports){
"use strict";
/**
* Vega-Lite's singleton logger utility.
*/
Object.defineProperty(exports, "__esModule", { value: true });
var vega_util_1 = require("vega-util");
/**
* Main (default) Vega Logger instance for Vega-Lite
*/
var main = vega_util_1.logger(vega_util_1.Warn);
var current = main;
/**
* Logger tool for checking if the code throws correct warning
*/
var LocalLogger = /** @class */ (function () {
function LocalLogger() {
this.warns = [];
this.infos = [];
this.debugs = [];
}
LocalLogger.prototype.level = function () {
return this;
};
LocalLogger.prototype.warn = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
(_a = this.warns).push.apply(_a, args);
return this;
var _a;
};
LocalLogger.prototype.info = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
(_a = this.infos).push.apply(_a, args);
return this;
var _a;
};
LocalLogger.prototype.debug = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
(_a = this.debugs).push.apply(_a, args);
return this;
var _a;
};
return LocalLogger;
}());
exports.LocalLogger = LocalLogger;
function runLocalLogger(f) {
var localLogger = current = new LocalLogger();
f(localLogger);
reset();
}
exports.runLocalLogger = runLocalLogger;
function wrap(f) {
return function () {
var logger = current = new LocalLogger();
f(logger);
reset();
};
}
exports.wrap = wrap;
/**
* Set the singleton logger to be a custom logger
*/
function set(logger) {
current = logger;
return current;
}
exports.set = set;
/**
* Reset the main logger to use the default Vega Logger
*/
function reset() {
current = main;
return current;
}
exports.reset = reset;
function warn() {
var _ = [];
for (var _i = 0; _i < arguments.length; _i++) {
_[_i] = arguments[_i];
}
current.warn.apply(current, arguments);
}
exports.warn = warn;
function info() {
var _ = [];
for (var _i = 0; _i < arguments.length; _i++) {
_[_i] = arguments[_i];
}
current.info.apply(current, arguments);
}
exports.info = info;
function debug() {
var _ = [];
for (var _i = 0; _i < arguments.length; _i++) {
_[_i] = arguments[_i];
}
current.debug.apply(current, arguments);
}
exports.debug = debug;
/**
* Collection of all Vega-Lite Error Messages
*/
var message;
(function (message) {
message.INVALID_SPEC = 'Invalid spec';
// SELECTION
function cannotProjectOnChannelWithoutField(channel) {
return "Cannot project a selection on encoding channel \"" + channel + "\", which has no field.";
}
message.cannotProjectOnChannelWithoutField = cannotProjectOnChannelWithoutField;
function selectionNotFound(name) {
return "Cannot find a selection named \"" + name + "\"";
}
message.selectionNotFound = selectionNotFound;
// REPEAT
function noSuchRepeatedValue(field) {
return "Unknown repeated value \"" + field + "\".";
}
message.noSuchRepeatedValue = noSuchRepeatedValue;
// TITLE
function cannotSetTitleAnchor(type) {
return "Cannot set title \"anchor\" for a " + type + " spec";
}
message.cannotSetTitleAnchor = cannotSetTitleAnchor;
// DATA
function unrecognizedParse(p) {
return "Unrecognized parse \"" + p + "\".";
}
message.unrecognizedParse = unrecognizedParse;
function differentParse(field, local, ancestor) {
return "An ancestor parsed field \"" + field + "\" as " + ancestor + " but a child wants to parse the field as " + local + ".";
}
message.differentParse = differentParse;
// TRANSFORMS
function invalidTransformIgnored(transform) {
return "Ignoring an invalid transform: " + JSON.stringify(transform) + ".";
}
message.invalidTransformIgnored = invalidTransformIgnored;
message.NO_FIELDS_NEEDS_AS = 'If "from.fields" is not specified, "as" has to be a string that specifies the key to be used for the the data from the secondary source.';
// ENCODING & FACET
function invalidFieldType(type) {
return "Invalid field type \"" + type + "\"";
}
message.invalidFieldType = invalidFieldType;
function invalidFieldTypeForCountAggregate(type, aggregate) {
return "Invalid field type \"" + type + "\" for aggregate: \"" + aggregate + "\", using \"quantitative\" instead.";
}
message.invalidFieldTypeForCountAggregate = invalidFieldTypeForCountAggregate;
function invalidAggregate(aggregate) {
return "Invalid aggregation operator \"" + aggregate + "\"";
}
message.invalidAggregate = invalidAggregate;
function emptyOrInvalidFieldType(type, channel, newType) {
return "Invalid field type \"" + type + "\" for channel \"" + channel + "\", using \"" + newType + "\" instead.";
}
message.emptyOrInvalidFieldType = emptyOrInvalidFieldType;
function emptyFieldDef(fieldDef, channel) {
return "Dropping " + JSON.stringify(fieldDef) + " from channel \"" + channel + "\" since it does not contain data field or value.";
}
message.emptyFieldDef = emptyFieldDef;
function incompatibleChannel(channel, markOrFacet, when) {
return channel + " dropped as it is incompatible with \"" + markOrFacet + "\"" + (when ? " when " + when : '') + ".";
}
message.incompatibleChannel = incompatibleChannel;
function facetChannelShouldBeDiscrete(channel) {
return channel + " encoding should be discrete (ordinal / nominal / binned).";
}
message.facetChannelShouldBeDiscrete = facetChannelShouldBeDiscrete;
function discreteChannelCannotEncode(channel, type) {
return "Using discrete channel \"" + channel + "\" to encode \"" + type + "\" field can be misleading as it does not encode " + (type === 'ordinal' ? 'order' : 'magnitude') + ".";
}
message.discreteChannelCannotEncode = discreteChannelCannotEncode;
// Mark
message.BAR_WITH_POINT_SCALE_AND_RANGESTEP_NULL = 'Bar mark should not be used with point scale when rangeStep is null. Please use band scale instead.';
function unclearOrientContinuous(mark) {
return "Cannot clearly determine orientation for \"" + mark + "\" since both x and y channel encode continous fields. In this case, we use vertical by default";
}
message.unclearOrientContinuous = unclearOrientContinuous;
function unclearOrientDiscreteOrEmpty(mark) {
return "Cannot clearly determine orientation for \"" + mark + "\" since both x and y channel encode discrete or empty fields.";
}
message.unclearOrientDiscreteOrEmpty = unclearOrientDiscreteOrEmpty;
function orientOverridden(original, actual) {
return "Specified orient \"" + original + "\" overridden with \"" + actual + "\"";
}
message.orientOverridden = orientOverridden;
// SCALE
message.CANNOT_UNION_CUSTOM_DOMAIN_WITH_FIELD_DOMAIN = 'custom domain scale cannot be unioned with default field-based domain';
function cannotUseScalePropertyWithNonColor(prop) {
return "Cannot use the scale property \"" + prop + "\" with non-color channel.";
}
message.cannotUseScalePropertyWithNonColor = cannotUseScalePropertyWithNonColor;
function unaggregateDomainHasNoEffectForRawField(fieldDef) {
return "Using unaggregated domain with raw field has no effect (" + JSON.stringify(fieldDef) + ").";
}
message.unaggregateDomainHasNoEffectForRawField = unaggregateDomainHasNoEffectForRawField;
function unaggregateDomainWithNonSharedDomainOp(aggregate) {
return "Unaggregated domain not applicable for \"" + aggregate + "\" since it produces values outside the origin domain of the source data.";
}
message.unaggregateDomainWithNonSharedDomainOp = unaggregateDomainWithNonSharedDomainOp;
function unaggregatedDomainWithLogScale(fieldDef) {
return "Unaggregated domain is currently unsupported for log scale (" + JSON.stringify(fieldDef) + ").";
}
message.unaggregatedDomainWithLogScale = unaggregatedDomainWithLogScale;
message.CANNOT_USE_RANGE_WITH_POSITION = 'Cannot use a custom "range" with x or y channel. Please customize width, height, padding, or rangeStep instead.';
function cannotUseSizeFieldWithBandSize(positionChannel) {
return "Using size field when " + positionChannel + "-channel has a band scale is not supported.";
}
message.cannotUseSizeFieldWithBandSize = cannotUseSizeFieldWithBandSize;
function cannotApplySizeToNonOrientedMark(mark) {
return "Cannot apply size to non-oriented mark \"" + mark + "\".";
}
message.cannotApplySizeToNonOrientedMark = cannotApplySizeToNonOrientedMark;
function rangeStepDropped(channel) {
return "rangeStep for \"" + channel + "\" is dropped as top-level " + (channel === 'x' ? 'width' : 'height') + " is provided.";
}
message.rangeStepDropped = rangeStepDropped;
function scaleTypeNotWorkWithChannel(channel, scaleType, defaultScaleType) {
return "Channel \"" + channel + "\" does not work with \"" + scaleType + "\" scale. We are using \"" + defaultScaleType + "\" scale instead.";
}
message.scaleTypeNotWorkWithChannel = scaleTypeNotWorkWithChannel;
function scaleTypeNotWorkWithFieldDef(scaleType, defaultScaleType) {
return "FieldDef does not work with \"" + scaleType + "\" scale. We are using \"" + defaultScaleType + "\" scale instead.";
}
message.scaleTypeNotWorkWithFieldDef = scaleTypeNotWorkWithFieldDef;
function scalePropertyNotWorkWithScaleType(scaleType, propName, channel) {
return channel + "-scale's \"" + propName + "\" is dropped as it does not work with " + scaleType + " scale.";
}
message.scalePropertyNotWorkWithScaleType = scalePropertyNotWorkWithScaleType;
function scaleTypeNotWorkWithMark(mark, scaleType) {
return "Scale type \"" + scaleType + "\" does not work with mark \"" + mark + "\".";
}
message.scaleTypeNotWorkWithMark = scaleTypeNotWorkWithMark;
function mergeConflictingProperty(property, propertyOf, v1, v2) {
return "Conflicting " + propertyOf + " property \"" + property + "\" (\"" + v1 + "\" and \"" + v2 + "\"). Using \"" + v1 + "\".";
}
message.mergeConflictingProperty = mergeConflictingProperty;
function independentScaleMeansIndependentGuide(channel) {
return "Setting the scale to be independent for \"" + channel + "\" means we also have to set the guide (axis or legend) to be independent.";
}
message.independentScaleMeansIndependentGuide = independentScaleMeansIndependentGuide;
function conflictedDomain(channel) {
return "Cannot set " + channel + "-scale's \"domain\" as it is binned. Please use \"bin\"'s \"extent\" instead.";
}
message.conflictedDomain = conflictedDomain;
function domainSortDropped(sort) {
return "Dropping sort property \"" + JSON.stringify(sort) + "\" as unioned domains only support boolean or op 'count'.";
}
message.domainSortDropped = domainSortDropped;
message.UNABLE_TO_MERGE_DOMAINS = 'Unable to merge domains';
message.MORE_THAN_ONE_SORT = 'Domains that should be unioned has conflicting sort properties. Sort will be set to true.';
// AXIS
message.INVALID_CHANNEL_FOR_AXIS = 'Invalid channel for axis.';
// STACK
function cannotStackRangedMark(channel) {
return "Cannot stack \"" + channel + "\" if there is already \"" + channel + "2\"";
}
message.cannotStackRangedMark = cannotStackRangedMark;
function cannotStackNonLinearScale(scaleType) {
return "Cannot stack non-linear scale (" + scaleType + ")";
}
message.cannotStackNonLinearScale = cannotStackNonLinearScale;
function cannotStackNonSummativeAggregate(aggregate) {
return "Cannot stack when the aggregate function is non-summative (\"" + aggregate + "\")";
}
message.cannotStackNonSummativeAggregate = cannotStackNonSummativeAggregate;
// TIMEUNIT
function invalidTimeUnit(unitName, value) {
return "Invalid " + unitName + ": \"" + value + "\"";
}
message.invalidTimeUnit = invalidTimeUnit;
function dayReplacedWithDate(fullTimeUnit) {
return "Time unit \"" + fullTimeUnit + "\" is not supported. We are replacing it with " + fullTimeUnit.replace('day', 'date') + ".";
}
message.dayReplacedWithDate = dayReplacedWithDate;
function droppedDay(d) {
return "Dropping day from datetime " + JSON.stringify(d) + " as day cannot be combined with other units.";
}
message.droppedDay = droppedDay;
})(message = exports.message || (exports.message = {}));
},{"vega-util":7}],102:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function isLogicalOr(op) {
return !!op.or;
}
exports.isLogicalOr = isLogicalOr;
function isLogicalAnd(op) {
return !!op.and;
}
exports.isLogicalAnd = isLogicalAnd;
function isLogicalNot(op) {
return !!op.not;
}
exports.isLogicalNot = isLogicalNot;
function forEachLeave(op, fn) {
if (isLogicalNot(op)) {
forEachLeave(op.not, fn);
}
else if (isLogicalAnd(op)) {
for (var _i = 0, _a = op.and; _i < _a.length; _i++) {
var subop = _a[_i];
forEachLeave(subop, fn);
}
}
else if (isLogicalOr(op)) {
for (var _b = 0, _c = op.or; _b < _c.length; _b++) {
var subop = _c[_b];
forEachLeave(subop, fn);
}
}
else {
fn(op);
}
}
exports.forEachLeave = forEachLeave;
function normalizeLogicalOperand(op, normalizer) {
if (isLogicalNot(op)) {
return { not: normalizeLogicalOperand(op.not, normalizer) };
}
else if (isLogicalAnd(op)) {
return { and: op.and.map(function (o) { return normalizeLogicalOperand(o, normalizer); }) };
}
else if (isLogicalOr(op)) {
return { or: op.or.map(function (o) { return normalizeLogicalOperand(o, normalizer); }) };
}
else {
return normalizer(op);
}
}
exports.normalizeLogicalOperand = normalizeLogicalOperand;
},{}],103:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var util_1 = require("./util");
var Mark;
(function (Mark) {
Mark.AREA = 'area';
Mark.BAR = 'bar';
Mark.LINE = 'line';
Mark.POINT = 'point';
Mark.RECT = 'rect';
Mark.RULE = 'rule';
Mark.TEXT = 'text';
Mark.TICK = 'tick';
Mark.CIRCLE = 'circle';
Mark.SQUARE = 'square';
})(Mark = exports.Mark || (exports.Mark = {}));
exports.AREA = Mark.AREA;
exports.BAR = Mark.BAR;
exports.LINE = Mark.LINE;
exports.POINT = Mark.POINT;
exports.TEXT = Mark.TEXT;
exports.TICK = Mark.TICK;
exports.RECT = Mark.RECT;
exports.RULE = Mark.RULE;
exports.CIRCLE = Mark.CIRCLE;
exports.SQUARE = Mark.SQUARE;
// Using mapped type to declare index, ensuring we always have all marks when we add more.
var MARK_INDEX = {
area: 1,
bar: 1,
line: 1,
point: 1,
text: 1,
tick: 1,
rect: 1,
rule: 1,
circle: 1,
square: 1
};
function isMark(m) {
return !!MARK_INDEX[m];
}
exports.isMark = isMark;
exports.PRIMITIVE_MARKS = util_1.flagKeys(MARK_INDEX);
function isMarkDef(mark) {
return mark['type'];
}
exports.isMarkDef = isMarkDef;
var PRIMITIVE_MARK_INDEX = util_1.toSet(exports.PRIMITIVE_MARKS);
function isPrimitiveMark(mark) {
var markType = isMarkDef(mark) ? mark.type : mark;
return markType in PRIMITIVE_MARK_INDEX;
}
exports.isPrimitiveMark = isPrimitiveMark;
exports.STROKE_CONFIG = ['stroke', 'strokeWidth',
'strokeDash', 'strokeDashOffset', 'strokeOpacity'];
exports.FILL_CONFIG = ['fill', 'fillOpacity'];
exports.FILL_STROKE_CONFIG = [].concat(exports.STROKE_CONFIG, exports.FILL_CONFIG);
exports.VL_ONLY_MARK_CONFIG_PROPERTIES = ['filled', 'color'];
exports.VL_ONLY_MARK_SPECIFIC_CONFIG_PROPERTY_INDEX = {
bar: ['binSpacing', 'continuousBandSize', 'discreteBandSize'],
text: ['shortTimeLabels'],
tick: ['bandSize', 'thickness']
};
exports.defaultMarkConfig = {
color: '#4c78a8',
};
exports.defaultBarConfig = {
binSpacing: 1,
continuousBandSize: 2
};
exports.defaultTickConfig = {
thickness: 1
};
},{"./util":114}],104:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var channel_1 = require("./channel");
var log = require("./log");
var util_1 = require("./util");
var ScaleType;
(function (ScaleType) {
// Continuous - Quantitative
ScaleType.LINEAR = 'linear';
ScaleType.BIN_LINEAR = 'bin-linear';
ScaleType.LOG = 'log';
ScaleType.POW = 'pow';
ScaleType.SQRT = 'sqrt';
// Continuous - Time
ScaleType.TIME = 'time';
ScaleType.UTC = 'utc';
// sequential
ScaleType.SEQUENTIAL = 'sequential';
// Quantile, Quantize, threshold
ScaleType.QUANTILE = 'quantile';
ScaleType.QUANTIZE = 'quantize';
ScaleType.THRESHOLD = 'threshold';
ScaleType.ORDINAL = 'ordinal';
ScaleType.BIN_ORDINAL = 'bin-ordinal';
ScaleType.POINT = 'point';
ScaleType.BAND = 'band';
})(ScaleType = exports.ScaleType || (exports.ScaleType = {}));
/**
* Index for scale categories -- only scale of the same categories can be merged together.
* Current implementation is trying to be conservative and avoid merging scale type that might not work together
*/
var SCALE_CATEGORY_INDEX = {
linear: 'numeric',
log: 'numeric',
pow: 'numeric',
sqrt: 'numeric',
'bin-linear': 'bin-linear',
time: 'time',
utc: 'time',
sequential: 'sequential',
ordinal: 'ordinal',
'bin-ordinal': 'bin-ordinal',
point: 'ordinal-position',
band: 'ordinal-position'
};
exports.SCALE_TYPES = util_1.keys(SCALE_CATEGORY_INDEX);
/**
* Whether the two given scale types can be merged together.
*/
function scaleCompatible(scaleType1, scaleType2) {
var scaleCategory1 = SCALE_CATEGORY_INDEX[scaleType1];
var scaleCategory2 = SCALE_CATEGORY_INDEX[scaleType2];
return scaleCategory1 === scaleCategory2 ||
(scaleCategory1 === 'ordinal-position' && scaleCategory2 === 'time') ||
(scaleCategory2 === 'ordinal-position' && scaleCategory1 === 'time');
}
exports.scaleCompatible = scaleCompatible;
/**
* Index for scale predecence -- high score = higher priority for merging.
*/
var SCALE_PRECEDENCE_INDEX = {
// numeric
linear: 0,
log: 1,
pow: 1,
sqrt: 1,
// time
time: 0,
utc: 0,
// ordinal-position -- these have higher precedence than continuous scales as they support more types of data
point: 10,
band: 11,
// non grouped types
'bin-linear': 0,
sequential: 0,
ordinal: 0,
'bin-ordinal': 0,
};
/**
* Return scale categories -- only scale of the same categories can be merged together.
*/
function scaleTypePrecedence(scaleType) {
return SCALE_PRECEDENCE_INDEX[scaleType];
}
exports.scaleTypePrecedence = scaleTypePrecedence;
exports.CONTINUOUS_TO_CONTINUOUS_SCALES = ['linear', 'bin-linear', 'log', 'pow', 'sqrt', 'time', 'utc'];
var CONTINUOUS_TO_CONTINUOUS_INDEX = util_1.toSet(exports.CONTINUOUS_TO_CONTINUOUS_SCALES);
exports.CONTINUOUS_DOMAIN_SCALES = exports.CONTINUOUS_TO_CONTINUOUS_SCALES.concat(['sequential' /* TODO add 'quantile', 'quantize', 'threshold'*/]);
var CONTINUOUS_DOMAIN_INDEX = util_1.toSet(exports.CONTINUOUS_DOMAIN_SCALES);
exports.DISCRETE_DOMAIN_SCALES = ['ordinal', 'bin-ordinal', 'point', 'band'];
var DISCRETE_DOMAIN_INDEX = util_1.toSet(exports.DISCRETE_DOMAIN_SCALES);
var BIN_SCALES_INDEX = util_1.toSet(['bin-linear', 'bin-ordinal']);
exports.TIME_SCALE_TYPES = ['time', 'utc'];
function hasDiscreteDomain(type) {
return type in DISCRETE_DOMAIN_INDEX;
}
exports.hasDiscreteDomain = hasDiscreteDomain;
function isBinScale(type) {
return type in BIN_SCALES_INDEX;
}
exports.isBinScale = isBinScale;
function hasContinuousDomain(type) {
return type in CONTINUOUS_DOMAIN_INDEX;
}
exports.hasContinuousDomain = hasContinuousDomain;
function isContinuousToContinuous(type) {
return type in CONTINUOUS_TO_CONTINUOUS_INDEX;
}
exports.isContinuousToContinuous = isContinuousToContinuous;
exports.defaultScaleConfig = {
textXRangeStep: 90,
rangeStep: 21,
pointPadding: 0.5,
bandPaddingInner: 0.1,
facetSpacing: 16,
minBandSize: 2,
minFontSize: 8,
maxFontSize: 40,
minOpacity: 0.3,
maxOpacity: 0.8,
// FIXME: revise if these *can* become ratios of rangeStep
minSize: 9,
minStrokeWidth: 1,
maxStrokeWidth: 4
};
function isExtendedScheme(scheme) {
return scheme && !!scheme['name'];
}
exports.isExtendedScheme = isExtendedScheme;
function isSelectionDomain(domain) {
return domain && domain['selection'];
}
exports.isSelectionDomain = isSelectionDomain;
var SCALE_PROPERTY_INDEX = {
type: 1,
domain: 1,
range: 1,
rangeStep: 1,
scheme: 1,
// Other properties
reverse: 1,
round: 1,
// quantitative / time
clamp: 1,
nice: 1,
// quantitative
base: 1,
exponent: 1,
interpolate: 1,
zero: 1,
// band/point
padding: 1,
paddingInner: 1,
paddingOuter: 1
};
exports.SCALE_PROPERTIES = util_1.flagKeys(SCALE_PROPERTY_INDEX);
var type = SCALE_PROPERTY_INDEX.type, domain = SCALE_PROPERTY_INDEX.domain, range = SCALE_PROPERTY_INDEX.range, rangeStep = SCALE_PROPERTY_INDEX.rangeStep, scheme = SCALE_PROPERTY_INDEX.scheme, NON_TYPE_DOMAIN_RANGE_VEGA_SCALE_PROPERTY_INDEX = tslib_1.__rest(SCALE_PROPERTY_INDEX, ["type", "domain", "range", "rangeStep", "scheme"]);
exports.NON_TYPE_DOMAIN_RANGE_VEGA_SCALE_PROPERTIES = util_1.flagKeys(NON_TYPE_DOMAIN_RANGE_VEGA_SCALE_PROPERTY_INDEX);
function scaleTypeSupportProperty(scaleType, propName) {
switch (propName) {
case 'type':
case 'domain':
case 'reverse':
case 'range':
return true;
case 'scheme':
return util_1.contains(['sequential', 'ordinal', 'bin-ordinal', 'quantile', 'quantize'], scaleType);
case 'interpolate':
// FIXME(https://github.com/vega/vega-lite/issues/2902) how about ordinal?
return util_1.contains(['linear', 'bin-linear', 'pow', 'log', 'sqrt', 'utc', 'time'], scaleType);
case 'round':
return isContinuousToContinuous(scaleType) || scaleType === 'band' || scaleType === 'point';
case 'rangeStep':
case 'padding':
case 'paddingOuter':
return util_1.contains(['point', 'band'], scaleType);
case 'paddingInner':
return scaleType === 'band';
case 'clamp':
return isContinuousToContinuous(scaleType) || scaleType === 'sequential';
case 'nice':
return isContinuousToContinuous(scaleType) || scaleType === 'sequential' || scaleType === 'quantize';
case 'exponent':
return scaleType === 'pow';
case 'base':
return scaleType === 'log';
case 'zero':
return hasContinuousDomain(scaleType) && !util_1.contains([
'log',
'time', 'utc',
'bin-linear',
'threshold',
'quantile' // quantile depends on distribution so zero does not matter
], scaleType);
}
/* istanbul ignore next: should never reach here*/
throw new Error("Invalid scale property " + propName + ".");
}
exports.scaleTypeSupportProperty = scaleTypeSupportProperty;
/**
* Returns undefined if the input channel supports the input scale property name
*/
function channelScalePropertyIncompatability(channel, propName) {
switch (propName) {
case 'range':
// User should not customize range for position and facet channel directly.
if (channel === 'x' || channel === 'y') {
return log.message.CANNOT_USE_RANGE_WITH_POSITION;
}
return undefined; // GOOD!
case 'interpolate':
case 'scheme':
if (channel !== 'color') {
return log.message.cannotUseScalePropertyWithNonColor(channel);
}
return undefined;
case 'type':
case 'domain':
case 'base':
case 'exponent':
case 'nice':
case 'padding':
case 'paddingInner':
case 'paddingOuter':
case 'rangeStep':
case 'reverse':
case 'round':
case 'clamp':
case 'zero':
return undefined; // GOOD!
}
/* istanbul ignore next: it should never reach here */
throw new Error("Invalid scale property \"" + propName + "\".");
}
exports.channelScalePropertyIncompatability = channelScalePropertyIncompatability;
function channelSupportScaleType(channel, scaleType) {
switch (channel) {
case channel_1.Channel.X:
case channel_1.Channel.Y:
case channel_1.Channel.SIZE: // TODO: size and opacity can support ordinal with more modification
case channel_1.Channel.OPACITY:
// Although it generally doesn't make sense to use band with size and opacity,
// it can also work since we use band: 0.5 to get midpoint.
return isContinuousToContinuous(scaleType) || util_1.contains(['band', 'point'], scaleType);
case channel_1.Channel.COLOR:
return scaleType !== 'band'; // band does not make sense with color
case channel_1.Channel.SHAPE:
return scaleType === 'ordinal'; // shape = lookup only
}
/* istanbul ignore next: it should never reach here */
return false;
}
exports.channelSupportScaleType = channelSupportScaleType;
},{"./channel":12,"./log":101,"./util":114,"tslib":5}],105:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SELECTION_ID = '_vgsid_';
exports.defaultConfig = {
single: { on: 'click', fields: [exports.SELECTION_ID], resolve: 'global' },
multi: { on: 'click', fields: [exports.SELECTION_ID], toggle: 'event.shiftKey', resolve: 'global' },
interval: {
on: '[mousedown, window:mouseup] > window:mousemove!',
encodings: ['x', 'y'],
translate: '[mousedown, window:mouseup] > window:mousemove!',
zoom: 'wheel!',
mark: { fill: '#333', fillOpacity: 0.125, stroke: 'white' },
resolve: 'global'
}
};
},{}],106:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function isSortField(sort) {
return !!sort && (sort['op'] === 'count' || !!sort['field']) && !!sort['op'];
}
exports.isSortField = isSortField;
},{}],107:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var channel_1 = require("./channel");
var compositeMark = require("./compositemark");
var encoding_1 = require("./encoding");
var vlEncoding = require("./encoding");
var log = require("./log");
var mark_1 = require("./mark");
var stack_1 = require("./stack");
var util_1 = require("./util");
/* Custom type guards */
function isFacetSpec(spec) {
return spec['facet'] !== undefined;
}
exports.isFacetSpec = isFacetSpec;
function isUnitSpec(spec) {
return !!spec['mark'];
}
exports.isUnitSpec = isUnitSpec;
function isLayerSpec(spec) {
return spec['layer'] !== undefined;
}
exports.isLayerSpec = isLayerSpec;
function isRepeatSpec(spec) {
return spec['repeat'] !== undefined;
}
exports.isRepeatSpec = isRepeatSpec;
function isConcatSpec(spec) {
return isVConcatSpec(spec) || isHConcatSpec(spec);
}
exports.isConcatSpec = isConcatSpec;
function isVConcatSpec(spec) {
return spec['vconcat'] !== undefined;
}
exports.isVConcatSpec = isVConcatSpec;
function isHConcatSpec(spec) {
return spec['hconcat'] !== undefined;
}
exports.isHConcatSpec = isHConcatSpec;
/**
* Decompose extended unit specs into composition of pure unit specs.
*/
// TODO: consider moving this to another file. Maybe vl.spec.normalize or vl.normalize
function normalize(spec, config) {
if (isFacetSpec(spec)) {
return normalizeFacet(spec, config);
}
if (isLayerSpec(spec)) {
return normalizeLayer(spec, config);
}
if (isRepeatSpec(spec)) {
return normalizeRepeat(spec, config);
}
if (isVConcatSpec(spec)) {
return normalizeVConcat(spec, config);
}
if (isHConcatSpec(spec)) {
return normalizeHConcat(spec, config);
}
if (isUnitSpec(spec)) {
var hasRow = encoding_1.channelHasField(spec.encoding, channel_1.ROW);
var hasColumn = encoding_1.channelHasField(spec.encoding, channel_1.COLUMN);
if (hasRow || hasColumn) {
return normalizeFacetedUnit(spec, config);
}
return normalizeNonFacetUnit(spec, config);
}
throw new Error(log.message.INVALID_SPEC);
}
exports.normalize = normalize;
function normalizeFacet(spec, config) {
var subspec = spec.spec, rest = tslib_1.__rest(spec, ["spec"]);
return tslib_1.__assign({}, rest, {
// TODO: remove "any" once we support all facet listed in https://github.com/vega/vega-lite/issues/2760
spec: normalize(subspec, config) });
}
function normalizeLayer(spec, config) {
var layer = spec.layer, rest = tslib_1.__rest(spec, ["layer"]);
return tslib_1.__assign({}, rest, { layer: layer.map(function (subspec) { return isLayerSpec(subspec) ? normalizeLayer(subspec, config) : normalizeNonFacetUnit(subspec, config); }) });
}
function normalizeRepeat(spec, config) {
var subspec = spec.spec, rest = tslib_1.__rest(spec, ["spec"]);
return tslib_1.__assign({}, rest, { spec: normalize(subspec, config) });
}
function normalizeVConcat(spec, config) {
var vconcat = spec.vconcat, rest = tslib_1.__rest(spec, ["vconcat"]);
return tslib_1.__assign({}, rest, { vconcat: vconcat.map(function (subspec) { return normalize(subspec, config); }) });
}
function normalizeHConcat(spec, config) {
var hconcat = spec.hconcat, rest = tslib_1.__rest(spec, ["hconcat"]);
return tslib_1.__assign({}, rest, { hconcat: hconcat.map(function (subspec) { return normalize(subspec, config); }) });
}
function normalizeFacetedUnit(spec, config) {
// New encoding in the inside spec should not contain row / column
// as row/column should be moved to facet
var _a = spec.encoding, row = _a.row, column = _a.column, encoding = tslib_1.__rest(_a, ["row", "column"]);
// Mark and encoding should be moved into the inner spec
var mark = spec.mark, width = spec.width, height = spec.height, selection = spec.selection, _ = spec.encoding, outerSpec = tslib_1.__rest(spec, ["mark", "width", "height", "selection", "encoding"]);
return tslib_1.__assign({}, outerSpec, { facet: tslib_1.__assign({}, (row ? { row: row } : {}), (column ? { column: column } : {})), spec: normalizeNonFacetUnit(tslib_1.__assign({ mark: mark }, (width ? { width: width } : {}), (height ? { height: height } : {}), { encoding: encoding }, (selection ? { selection: selection } : {})), config) });
}
function isNonFacetUnitSpecWithPrimitiveMark(spec) {
return mark_1.isPrimitiveMark(spec.mark);
}
function normalizeNonFacetUnit(spec, config) {
if (isNonFacetUnitSpecWithPrimitiveMark(spec)) {
// TODO: thoroughly test
if (encoding_1.isRanged(spec.encoding)) {
return normalizeRangedUnit(spec);
}
var overlayConfig = config && config.overlay;
var overlayWithLine = overlayConfig && spec.mark === mark_1.AREA &&
util_1.contains(['linepoint', 'line'], overlayConfig.area);
var overlayWithPoint = overlayConfig && ((overlayConfig.line && spec.mark === mark_1.LINE) ||
(overlayConfig.area === 'linepoint' && spec.mark === mark_1.AREA));
// TODO: consider moving this to become another case of compositeMark
if (overlayWithPoint || overlayWithLine) {
return normalizeOverlay(spec, overlayWithPoint, overlayWithLine, config);
}
return spec; // Nothing to normalize
}
else {
return compositeMark.normalize(spec, config);
}
}
function normalizeRangedUnit(spec) {
var hasX = encoding_1.channelHasField(spec.encoding, channel_1.X);
var hasY = encoding_1.channelHasField(spec.encoding, channel_1.Y);
var hasX2 = encoding_1.channelHasField(spec.encoding, channel_1.X2);
var hasY2 = encoding_1.channelHasField(spec.encoding, channel_1.Y2);
if ((hasX2 && !hasX) || (hasY2 && !hasY)) {
var normalizedSpec = util_1.duplicate(spec);
if (hasX2 && !hasX) {
normalizedSpec.encoding.x = normalizedSpec.encoding.x2;
delete normalizedSpec.encoding.x2;
}
if (hasY2 && !hasY) {
normalizedSpec.encoding.y = normalizedSpec.encoding.y2;
delete normalizedSpec.encoding.y2;
}
return normalizedSpec;
}
return spec;
}
// FIXME(#1804): re-design this
function normalizeOverlay(spec, overlayWithPoint, overlayWithLine, config) {
var mark = spec.mark, selection = spec.selection, encoding = spec.encoding, outerSpec = tslib_1.__rest(spec, ["mark", "selection", "encoding"]);
var layer = [{ mark: mark, encoding: encoding }];
// Need to copy stack config to overlayed layer
var stackProps = stack_1.stack(mark, encoding, config ? config.stack : undefined);
var overlayEncoding = encoding;
if (stackProps) {
var stackFieldChannel = stackProps.fieldChannel, offset = stackProps.offset;
overlayEncoding = tslib_1.__assign({}, encoding, (_a = {}, _a[stackFieldChannel] = tslib_1.__assign({}, encoding[stackFieldChannel], (offset ? { stack: offset } : {})), _a));
}
if (overlayWithLine) {
layer.push(tslib_1.__assign({ mark: {
type: 'line',
style: 'lineOverlay'
} }, (selection ? { selection: selection } : {}), { encoding: overlayEncoding }));
}
if (overlayWithPoint) {
layer.push(tslib_1.__assign({ mark: {
type: 'point',
filled: true,
style: 'pointOverlay'
} }, (selection ? { selection: selection } : {}), { encoding: overlayEncoding }));
}
return tslib_1.__assign({}, outerSpec, { layer: layer });
var _a;
}
// TODO: add vl.spec.validate & move stuff from vl.validate to here
/* Accumulate non-duplicate fieldDefs in a dictionary */
function accumulate(dict, fieldDefs) {
fieldDefs.forEach(function (fieldDef) {
// Consider only pure fieldDef properties (ignoring scale, axis, legend)
var pureFieldDef = ['field', 'type', 'value', 'timeUnit', 'bin', 'aggregate'].reduce(function (f, key) {
if (fieldDef[key] !== undefined) {
f[key] = fieldDef[key];
}
return f;
}, {});
var key = util_1.hash(pureFieldDef);
dict[key] = dict[key] || fieldDef;
});
return dict;
}
/* Recursively get fieldDefs from a spec, returns a dictionary of fieldDefs */
function fieldDefIndex(spec, dict) {
if (dict === void 0) { dict = {}; }
// FIXME(https://github.com/vega/vega-lite/issues/2207): Support fieldDefIndex for repeat
if (isLayerSpec(spec)) {
spec.layer.forEach(function (layer) {
if (isUnitSpec(layer)) {
accumulate(dict, vlEncoding.fieldDefs(layer.encoding));
}
else {
fieldDefIndex(layer, dict);
}
});
}
else if (isFacetSpec(spec)) {
accumulate(dict, vlEncoding.fieldDefs(spec.facet));
fieldDefIndex(spec.spec, dict);
}
else if (isRepeatSpec(spec)) {
fieldDefIndex(spec.spec, dict);
}
else if (isConcatSpec(spec)) {
var childSpec = isVConcatSpec(spec) ? spec.vconcat : spec.hconcat;
childSpec.forEach(function (child) { return fieldDefIndex(child, dict); });
}
else {
accumulate(dict, vlEncoding.fieldDefs(spec.encoding));
}
return dict;
}
/* Returns all non-duplicate fieldDefs in a spec in a flat array */
function fieldDefs(spec) {
return util_1.vals(fieldDefIndex(spec));
}
exports.fieldDefs = fieldDefs;
function isStacked(spec, config) {
config = config || spec.config;
if (mark_1.isPrimitiveMark(spec.mark)) {
return stack_1.stack(spec.mark, spec.encoding, config ? config.stack : undefined) !== null;
}
return false;
}
exports.isStacked = isStacked;
},{"./channel":12,"./compositemark":90,"./encoding":94,"./log":101,"./mark":103,"./stack":108,"./util":114,"tslib":5}],108:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var aggregate_1 = require("./aggregate");
var channel_1 = require("./channel");
var encoding_1 = require("./encoding");
var fielddef_1 = require("./fielddef");
var log = require("./log");
var mark_1 = require("./mark");
var scale_1 = require("./scale");
var util_1 = require("./util");
exports.STACKABLE_MARKS = [mark_1.BAR, mark_1.AREA, mark_1.RULE, mark_1.POINT, mark_1.CIRCLE, mark_1.SQUARE, mark_1.LINE, mark_1.TEXT, mark_1.TICK];
exports.STACK_BY_DEFAULT_MARKS = [mark_1.BAR, mark_1.AREA];
// Note: CompassQL uses this method and only pass in required properties of each argument object.
// If required properties change, make sure to update CompassQL.
function stack(m, encoding, stackConfig) {
var mark = mark_1.isMarkDef(m) ? m.type : m;
// Should have stackable mark
if (!util_1.contains(exports.STACKABLE_MARKS, mark)) {
return null;
}
// Should be aggregate plot
if (!encoding_1.isAggregate(encoding)) {
return null;
}
// Should have grouping level of detail
var stackBy = channel_1.NONSPATIAL_CHANNELS.reduce(function (sc, channel) {
if (encoding_1.channelHasField(encoding, channel)) {
var channelDef = encoding[channel];
(util_1.isArray(channelDef) ? channelDef : [channelDef]).forEach(function (cDef) {
var fieldDef = fielddef_1.getFieldDef(cDef);
if (!fieldDef.aggregate) {
sc.push({
channel: channel,
fieldDef: fieldDef
});
}
});
}
return sc;
}, []);
if (stackBy.length === 0) {
return null;
}
// Has only one aggregate axis
var hasXField = fielddef_1.isFieldDef(encoding.x);
var hasYField = fielddef_1.isFieldDef(encoding.y);
var xIsAggregate = fielddef_1.isFieldDef(encoding.x) && !!encoding.x.aggregate;
var yIsAggregate = fielddef_1.isFieldDef(encoding.y) && !!encoding.y.aggregate;
if (xIsAggregate !== yIsAggregate) {
var fieldChannel = xIsAggregate ? channel_1.X : channel_1.Y;
var fieldDef = encoding[fieldChannel];
var fieldChannelAggregate = fieldDef.aggregate;
var fieldChannelScale = fieldDef.scale;
var stackOffset = null;
if (fieldDef.stack !== undefined) {
stackOffset = fieldDef.stack;
}
else if (util_1.contains(exports.STACK_BY_DEFAULT_MARKS, mark)) {
// Bar and Area with sum ops are automatically stacked by default
stackOffset = stackConfig === undefined ? 'zero' : stackConfig;
}
else {
stackOffset = stackConfig;
}
if (!stackOffset || stackOffset === 'none') {
return null;
}
// If stacked, check if it qualifies for stacking (and log warning if not qualified.)
if (fieldChannelScale && fieldChannelScale.type && fieldChannelScale.type !== scale_1.ScaleType.LINEAR) {
log.warn(log.message.cannotStackNonLinearScale(fieldChannelScale.type));
return null;
}
if (encoding_1.channelHasField(encoding, fieldChannel === channel_1.X ? channel_1.X2 : channel_1.Y2)) {
log.warn(log.message.cannotStackRangedMark(fieldChannel));
return null;
}
if (!util_1.contains(aggregate_1.SUM_OPS, fieldChannelAggregate)) {
log.warn(log.message.cannotStackNonSummativeAggregate(fieldChannelAggregate));
return null;
}
return {
groupbyChannel: xIsAggregate ? (hasYField ? channel_1.Y : null) : (hasXField ? channel_1.X : null),
fieldChannel: fieldChannel,
impute: util_1.contains(['area', 'line'], mark),
stackBy: stackBy,
offset: stackOffset
};
}
return null;
}
exports.stack = stack;
},{"./aggregate":9,"./channel":12,"./encoding":94,"./fielddef":96,"./log":101,"./mark":103,"./scale":104,"./util":114}],109:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var datetime_1 = require("./datetime");
var log = require("./log");
var util_1 = require("./util");
var TimeUnit;
(function (TimeUnit) {
TimeUnit.YEAR = 'year';
TimeUnit.MONTH = 'month';
TimeUnit.DAY = 'day';
TimeUnit.DATE = 'date';
TimeUnit.HOURS = 'hours';
TimeUnit.MINUTES = 'minutes';
TimeUnit.SECONDS = 'seconds';
TimeUnit.MILLISECONDS = 'milliseconds';
TimeUnit.YEARMONTH = 'yearmonth';
TimeUnit.YEARMONTHDATE = 'yearmonthdate';
TimeUnit.YEARMONTHDATEHOURS = 'yearmonthdatehours';
TimeUnit.YEARMONTHDATEHOURSMINUTES = 'yearmonthdatehoursminutes';
TimeUnit.YEARMONTHDATEHOURSMINUTESSECONDS = 'yearmonthdatehoursminutesseconds';
// MONTHDATE always include 29 February since we use year 0th (which is a leap year);
TimeUnit.MONTHDATE = 'monthdate';
TimeUnit.HOURSMINUTES = 'hoursminutes';
TimeUnit.HOURSMINUTESSECONDS = 'hoursminutesseconds';
TimeUnit.MINUTESSECONDS = 'minutesseconds';
TimeUnit.SECONDSMILLISECONDS = 'secondsmilliseconds';
TimeUnit.QUARTER = 'quarter';
TimeUnit.YEARQUARTER = 'yearquarter';
TimeUnit.QUARTERMONTH = 'quartermonth';
TimeUnit.YEARQUARTERMONTH = 'yearquartermonth';
TimeUnit.UTCYEAR = 'utcyear';
TimeUnit.UTCMONTH = 'utcmonth';
TimeUnit.UTCDAY = 'utcday';
TimeUnit.UTCDATE = 'utcdate';
TimeUnit.UTCHOURS = 'utchours';
TimeUnit.UTCMINUTES = 'utcminutes';
TimeUnit.UTCSECONDS = 'utcseconds';
TimeUnit.UTCMILLISECONDS = 'utcmilliseconds';
TimeUnit.UTCYEARMONTH = 'utcyearmonth';
TimeUnit.UTCYEARMONTHDATE = 'utcyearmonthdate';
TimeUnit.UTCYEARMONTHDATEHOURS = 'utcyearmonthdatehours';
TimeUnit.UTCYEARMONTHDATEHOURSMINUTES = 'utcyearmonthdatehoursminutes';
TimeUnit.UTCYEARMONTHDATEHOURSMINUTESSECONDS = 'utcyearmonthdatehoursminutesseconds';
// MONTHDATE always include 29 February since we use year 0th (which is a leap year);
TimeUnit.UTCMONTHDATE = 'utcmonthdate';
TimeUnit.UTCHOURSMINUTES = 'utchoursminutes';
TimeUnit.UTCHOURSMINUTESSECONDS = 'utchoursminutesseconds';
TimeUnit.UTCMINUTESSECONDS = 'utcminutesseconds';
TimeUnit.UTCSECONDSMILLISECONDS = 'utcsecondsmilliseconds';
TimeUnit.UTCQUARTER = 'utcquarter';
TimeUnit.UTCYEARQUARTER = 'utcyearquarter';
TimeUnit.UTCQUARTERMONTH = 'utcquartermonth';
TimeUnit.UTCYEARQUARTERMONTH = 'utcyearquartermonth';
})(TimeUnit = exports.TimeUnit || (exports.TimeUnit = {}));
/** Time Unit that only corresponds to only one part of Date objects. */
var LOCAL_SINGLE_TIMEUNIT_INDEX = {
year: 1,
quarter: 1,
month: 1,
day: 1,
date: 1,
hours: 1,
minutes: 1,
seconds: 1,
milliseconds: 1
};
exports.TIMEUNIT_PARTS = util_1.flagKeys(LOCAL_SINGLE_TIMEUNIT_INDEX);
function isLocalSingleTimeUnit(timeUnit) {
return !!LOCAL_SINGLE_TIMEUNIT_INDEX[timeUnit];
}
exports.isLocalSingleTimeUnit = isLocalSingleTimeUnit;
var UTC_SINGLE_TIMEUNIT_INDEX = {
utcyear: 1,
utcquarter: 1,
utcmonth: 1,
utcday: 1,
utcdate: 1,
utchours: 1,
utcminutes: 1,
utcseconds: 1,
utcmilliseconds: 1
};
function isUtcSingleTimeUnit(timeUnit) {
return !!UTC_SINGLE_TIMEUNIT_INDEX[timeUnit];
}
exports.isUtcSingleTimeUnit = isUtcSingleTimeUnit;
var LOCAL_MULTI_TIMEUNIT_INDEX = {
yearquarter: 1,
yearquartermonth: 1,
yearmonth: 1,
yearmonthdate: 1,
yearmonthdatehours: 1,
yearmonthdatehoursminutes: 1,
yearmonthdatehoursminutesseconds: 1,
quartermonth: 1,
monthdate: 1,
hoursminutes: 1,
hoursminutesseconds: 1,
minutesseconds: 1,
secondsmilliseconds: 1
};
var UTC_MULTI_TIMEUNIT_INDEX = {
utcyearquarter: 1,
utcyearquartermonth: 1,
utcyearmonth: 1,
utcyearmonthdate: 1,
utcyearmonthdatehours: 1,
utcyearmonthdatehoursminutes: 1,
utcyearmonthdatehoursminutesseconds: 1,
utcquartermonth: 1,
utcmonthdate: 1,
utchoursminutes: 1,
utchoursminutesseconds: 1,
utcminutesseconds: 1,
utcsecondsmilliseconds: 1
};
var UTC_TIMEUNIT_INDEX = tslib_1.__assign({}, UTC_SINGLE_TIMEUNIT_INDEX, UTC_MULTI_TIMEUNIT_INDEX);
function isUTCTimeUnit(t) {
return !!UTC_TIMEUNIT_INDEX[t];
}
exports.isUTCTimeUnit = isUTCTimeUnit;
function getLocalTimeUnit(t) {
return t.substr(3);
}
exports.getLocalTimeUnit = getLocalTimeUnit;
var TIMEUNIT_INDEX = tslib_1.__assign({}, LOCAL_SINGLE_TIMEUNIT_INDEX, UTC_SINGLE_TIMEUNIT_INDEX, LOCAL_MULTI_TIMEUNIT_INDEX, UTC_MULTI_TIMEUNIT_INDEX);
exports.TIMEUNITS = util_1.flagKeys(TIMEUNIT_INDEX);
function isTimeUnit(t) {
return !!TIMEUNIT_INDEX[t];
}
exports.isTimeUnit = isTimeUnit;
var SET_DATE_METHOD = {
year: 'setFullYear',
month: 'setMonth',
date: 'setDate',
hours: 'setHours',
minutes: 'setMinutes',
seconds: 'setSeconds',
milliseconds: 'setMilliseconds',
// Day and quarter have their own special cases
quarter: null,
day: null,
};
/**
* Converts a date to only have the measurements relevant to the specified unit
* i.e. ('yearmonth', '2000-12-04 07:58:14') -> '2000-12-01 00:00:00'
* Note: the base date is Jan 01 1900 00:00:00
*/
function convert(unit, date) {
var isUTC = isUTCTimeUnit(unit);
var result = isUTC ?
// start with uniform date
new Date(Date.UTC(0, 0, 1, 0, 0, 0, 0)) :
new Date(0, 0, 1, 0, 0, 0, 0);
exports.TIMEUNIT_PARTS.forEach(function (timeUnitPart) {
if (containsTimeUnit(unit, timeUnitPart)) {
switch (timeUnitPart) {
case TimeUnit.DAY:
throw new Error('Cannot convert to TimeUnits containing \'day\'');
case TimeUnit.QUARTER: {
var _a = dateMethods('month', isUTC), getDateMethod_1 = _a.getDateMethod, setDateMethod_1 = _a.setDateMethod;
// indicate quarter by setting month to be the first of the quarter i.e. may (4) -> april (3)
result[setDateMethod_1]((Math.floor(date[getDateMethod_1]() / 3)) * 3);
break;
}
default:
var _b = dateMethods(timeUnitPart, isUTC), getDateMethod = _b.getDateMethod, setDateMethod = _b.setDateMethod;
result[setDateMethod](date[getDateMethod]());
}
}
});
return result;
}
exports.convert = convert;
function dateMethods(singleUnit, isUtc) {
var rawSetDateMethod = SET_DATE_METHOD[singleUnit];
var setDateMethod = isUtc ? 'setUTC' + rawSetDateMethod.substr(3) : rawSetDateMethod;
var getDateMethod = 'get' + (isUtc ? 'UTC' : '') + rawSetDateMethod.substr(3);
return { setDateMethod: setDateMethod, getDateMethod: getDateMethod };
}
/** Returns true if fullTimeUnit contains the timeUnit, false otherwise. */
function containsTimeUnit(fullTimeUnit, timeUnit) {
var index = fullTimeUnit.indexOf(timeUnit);
return index > -1 &&
(timeUnit !== TimeUnit.SECONDS ||
index === 0 ||
fullTimeUnit.charAt(index - 1) !== 'i' // exclude milliseconds
);
}
exports.containsTimeUnit = containsTimeUnit;
/**
* Returns Vega expresssion for a given timeUnit and fieldRef
*/
function fieldExpr(fullTimeUnit, field) {
var fieldRef = "datum[" + util_1.stringValue(field) + "]";
var utc = isUTCTimeUnit(fullTimeUnit) ? 'utc' : '';
function func(timeUnit) {
if (timeUnit === TimeUnit.QUARTER) {
// quarter starting at 0 (0,3,6,9).
return "(" + utc + "quarter(" + fieldRef + ")-1)";
}
else {
return "" + utc + timeUnit + "(" + fieldRef + ")";
}
}
var d = exports.TIMEUNIT_PARTS.reduce(function (dateExpr, tu) {
if (containsTimeUnit(fullTimeUnit, tu)) {
dateExpr[tu] = func(tu);
}
return dateExpr;
}, {});
return datetime_1.dateTimeExpr(d);
}
exports.fieldExpr = fieldExpr;
/** returns the smallest nice unit for scale.nice */
function smallestUnit(timeUnit) {
if (!timeUnit) {
return undefined;
}
if (containsTimeUnit(timeUnit, TimeUnit.SECONDS)) {
return 'second';
}
if (containsTimeUnit(timeUnit, TimeUnit.MINUTES)) {
return 'minute';
}
if (containsTimeUnit(timeUnit, TimeUnit.HOURS)) {
return 'hour';
}
if (containsTimeUnit(timeUnit, TimeUnit.DAY) ||
containsTimeUnit(timeUnit, TimeUnit.DATE)) {
return 'day';
}
if (containsTimeUnit(timeUnit, TimeUnit.MONTH)) {
return 'month';
}
if (containsTimeUnit(timeUnit, TimeUnit.YEAR)) {
return 'year';
}
return undefined;
}
exports.smallestUnit = smallestUnit;
/**
* returns the signal expression used for axis labels for a time unit
*/
function formatExpression(timeUnit, field, shortTimeLabels, isUTCScale) {
if (!timeUnit) {
return undefined;
}
var dateComponents = [];
var expression = '';
var hasYear = containsTimeUnit(timeUnit, TimeUnit.YEAR);
if (containsTimeUnit(timeUnit, TimeUnit.QUARTER)) {
// special expression for quarter as prefix
expression = "'Q' + quarter(" + field + ")";
}
if (containsTimeUnit(timeUnit, TimeUnit.MONTH)) {
// By default use short month name
dateComponents.push(shortTimeLabels !== false ? '%b' : '%B');
}
if (containsTimeUnit(timeUnit, TimeUnit.DAY)) {
dateComponents.push(shortTimeLabels ? '%a' : '%A');
}
else if (containsTimeUnit(timeUnit, TimeUnit.DATE)) {
dateComponents.push('%d' + (hasYear ? ',' : '')); // add comma if there is year
}
if (hasYear) {
dateComponents.push(shortTimeLabels ? '%y' : '%Y');
}
var timeComponents = [];
if (containsTimeUnit(timeUnit, TimeUnit.HOURS)) {
timeComponents.push('%H');
}
if (containsTimeUnit(timeUnit, TimeUnit.MINUTES)) {
timeComponents.push('%M');
}
if (containsTimeUnit(timeUnit, TimeUnit.SECONDS)) {
timeComponents.push('%S');
}
if (containsTimeUnit(timeUnit, TimeUnit.MILLISECONDS)) {
timeComponents.push('%L');
}
var dateTimeComponents = [];
if (dateComponents.length > 0) {
dateTimeComponents.push(dateComponents.join(' '));
}
if (timeComponents.length > 0) {
dateTimeComponents.push(timeComponents.join(':'));
}
if (dateTimeComponents.length > 0) {
if (expression) {
// Add space between quarter and main time format
expression += " + ' ' + ";
}
// We only use utcFormat for utc scale
// For utc time units, the data is already converted as a part of timeUnit transform.
// Thus, utc time units should use timeFormat to avoid shifting the time twice.
if (isUTCScale) {
expression += "utcFormat(" + field + ", '" + dateTimeComponents.join(' ') + "')";
}
else {
expression += "timeFormat(" + field + ", '" + dateTimeComponents.join(' ') + "')";
}
}
// If expression is still an empty string, return undefined instead.
return expression || undefined;
}
exports.formatExpression = formatExpression;
function normalizeTimeUnit(timeUnit) {
if (timeUnit !== 'day' && timeUnit.indexOf('day') >= 0) {
log.warn(log.message.dayReplacedWithDate(timeUnit));
return timeUnit.replace('day', 'date');
}
return timeUnit;
}
exports.normalizeTimeUnit = normalizeTimeUnit;
},{"./datetime":93,"./log":101,"./util":114,"tslib":5}],110:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
function extractTitleConfig(titleConfig) {
var
// These are non-mark title config that need to be hardcoded
anchor = titleConfig.anchor, offset = titleConfig.offset, orient = titleConfig.orient,
// color needs to be redirect to fill
color = titleConfig.color,
// The rest are mark config.
titleMarkConfig = tslib_1.__rest(titleConfig, ["anchor", "offset", "orient", "color"]);
var mark = tslib_1.__assign({}, titleMarkConfig, color ? { fill: color } : {});
var nonMark = tslib_1.__assign({}, anchor ? { anchor: anchor } : {}, offset ? { offset: offset } : {}, orient ? { orient: orient } : {});
return { mark: mark, nonMark: nonMark };
}
exports.extractTitleConfig = extractTitleConfig;
},{"tslib":5}],111:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var TOP_LEVEL_PROPERTIES = [
'background', 'padding', 'autoResize'
];
function extractTopLevelProperties(t) {
return TOP_LEVEL_PROPERTIES.reduce(function (o, p) {
if (t && t[p] !== undefined) {
o[p] = t[p];
}
return o;
}, {});
}
exports.extractTopLevelProperties = extractTopLevelProperties;
},{}],112:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var filter_1 = require("./filter");
var logical_1 = require("./logical");
function isFilter(t) {
return t['filter'] !== undefined;
}
exports.isFilter = isFilter;
function isLookup(t) {
return t['lookup'] !== undefined;
}
exports.isLookup = isLookup;
function isCalculate(t) {
return t['calculate'] !== undefined;
}
exports.isCalculate = isCalculate;
function isBin(t) {
return !!t['bin'];
}
exports.isBin = isBin;
function isTimeUnit(t) {
return t['timeUnit'] !== undefined;
}
exports.isTimeUnit = isTimeUnit;
function isSummarize(t) {
return t['summarize'] !== undefined;
}
exports.isSummarize = isSummarize;
function normalizeTransform(transform) {
return transform.map(function (t) {
if (isFilter(t)) {
return {
filter: logical_1.normalizeLogicalOperand(t.filter, filter_1.normalizeFilter)
};
}
return t;
});
}
exports.normalizeTransform = normalizeTransform;
},{"./filter":97,"./logical":102}],113:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/** Constants and utilities for data type */
/** Data type based on level of measurement */
var Type;
(function (Type) {
Type.QUANTITATIVE = 'quantitative';
Type.ORDINAL = 'ordinal';
Type.TEMPORAL = 'temporal';
Type.NOMINAL = 'nominal';
})(Type = exports.Type || (exports.Type = {}));
var TYPE_INDEX = {
quantitative: 1,
ordinal: 1,
temporal: 1,
nominal: 1
};
function isType(t) {
return !!TYPE_INDEX[t];
}
exports.isType = isType;
exports.QUANTITATIVE = Type.QUANTITATIVE;
exports.ORDINAL = Type.ORDINAL;
exports.TEMPORAL = Type.TEMPORAL;
exports.NOMINAL = Type.NOMINAL;
/**
* Get full, lowercase type name for a given type.
* @param type
* @return Full type name.
*/
function getFullName(type) {
if (type) {
type = type.toLowerCase();
switch (type) {
case 'q':
case exports.QUANTITATIVE:
return 'quantitative';
case 't':
case exports.TEMPORAL:
return 'temporal';
case 'o':
case exports.ORDINAL:
return 'ordinal';
case 'n':
case exports.NOMINAL:
return 'nominal';
}
}
// If we get invalid input, return undefined type.
return undefined;
}
exports.getFullName = getFullName;
},{}],114:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var stringify = require("json-stable-stringify");
var vega_util_1 = require("vega-util");
var logical_1 = require("./logical");
var vega_util_2 = require("vega-util");
exports.isArray = vega_util_2.isArray;
exports.isObject = vega_util_2.isObject;
exports.isNumber = vega_util_2.isNumber;
exports.isString = vega_util_2.isString;
exports.truncate = vega_util_2.truncate;
exports.toSet = vega_util_2.toSet;
exports.stringValue = vega_util_2.stringValue;
/**
* Creates an object composed of the picked object properties.
*
* Example: (from lodash)
*
* var object = {'a': 1, 'b': '2', 'c': 3};
* pick(object, ['a', 'c']);
* // → {'a': 1, 'c': 3}
*
*/
function pick(obj, props) {
var copy = {};
props.forEach(function (prop) {
if (obj.hasOwnProperty(prop)) {
copy[prop] = obj[prop];
}
});
return copy;
}
exports.pick = pick;
/**
* The opposite of _.pick; this method creates an object composed of the own
* and inherited enumerable string keyed properties of object that are not omitted.
*/
function omit(obj, props) {
var copy = duplicate(obj);
props.forEach(function (prop) {
delete copy[prop];
});
return copy;
}
exports.omit = omit;
function hash(a) {
if (vega_util_1.isString(a) || vega_util_1.isNumber(a) || isBoolean(a)) {
return String(a);
}
var str = stringify(a);
// short strings can be used as hash directly, longer strings are hashed to reduce memory usage
if (str.length < 100) {
return str;
}
// from http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
var h = 0;
for (var i = 0; i < str.length; i++) {
var char = str.charCodeAt(i);
h = ((h << 5) - h) + char;
h = h & h; // Convert to 32bit integer
}
return h;
}
exports.hash = hash;
function contains(array, item) {
return array.indexOf(item) > -1;
}
exports.contains = contains;
/** Returns the array without the elements in item */
function without(array, excludedItems) {
return array.filter(function (item) { return !contains(excludedItems, item); });
}
exports.without = without;
function union(array, other) {
return array.concat(without(other, array));
}
exports.union = union;
/**
* Returns true if any item returns true.
*/
function some(arr, f) {
var i = 0;
for (var k = 0; k < arr.length; k++) {
if (f(arr[k], k, i++)) {
return true;
}
}
return false;
}
exports.some = some;
/**
* Returns true if all items return true.
*/
function every(arr, f) {
var i = 0;
for (var k = 0; k < arr.length; k++) {
if (!f(arr[k], k, i++)) {
return false;
}
}
return true;
}
exports.every = every;
function flatten(arrays) {
return [].concat.apply([], arrays);
}
exports.flatten = flatten;
/**
* recursively merges src into dest
*/
function mergeDeep(dest) {
var src = [];
for (var _i = 1; _i < arguments.length; _i++) {
src[_i - 1] = arguments[_i];
}
for (var _a = 0, src_1 = src; _a < src_1.length; _a++) {
var s = src_1[_a];
dest = deepMerge_(dest, s);
}
return dest;
}
exports.mergeDeep = mergeDeep;
// recursively merges src into dest
function deepMerge_(dest, src) {
if (typeof src !== 'object' || src === null) {
return dest;
}
for (var p in src) {
if (!src.hasOwnProperty(p)) {
continue;
}
if (src[p] === undefined) {
continue;
}
if (typeof src[p] !== 'object' || vega_util_1.isArray(src[p]) || src[p] === null) {
dest[p] = src[p];
}
else if (typeof dest[p] !== 'object' || dest[p] === null) {
dest[p] = mergeDeep(vega_util_1.isArray(src[p].constructor) ? [] : {}, src[p]);
}
else {
mergeDeep(dest[p], src[p]);
}
}
return dest;
}
function unique(values, f) {
var results = [];
var u = {};
var v;
for (var _i = 0, values_1 = values; _i < values_1.length; _i++) {
var val = values_1[_i];
v = f(val);
if (v in u) {
continue;
}
u[v] = 1;
results.push(val);
}
return results;
}
exports.unique = unique;
/**
* Returns true if the two dictionaries disagree. Applies only to defined values.
*/
function differ(dict, other) {
for (var key in dict) {
if (dict.hasOwnProperty(key)) {
if (other[key] && dict[key] && other[key] !== dict[key]) {
return true;
}
}
}
return false;
}
exports.differ = differ;
function hasIntersection(a, b) {
for (var key in a) {
if (key in b) {
return true;
}
}
return false;
}
exports.hasIntersection = hasIntersection;
function differArray(array, other) {
if (array.length !== other.length) {
return true;
}
array.sort();
other.sort();
for (var i = 0; i < array.length; i++) {
if (other[i] !== array[i]) {
return true;
}
}
return false;
}
exports.differArray = differArray;
exports.keys = Object.keys;
function vals(x) {
var _vals = [];
for (var k in x) {
if (x.hasOwnProperty(k)) {
_vals.push(x[k]);
}
}
return _vals;
}
exports.vals = vals;
function flagKeys(f) {
return exports.keys(f);
}
exports.flagKeys = flagKeys;
function duplicate(obj) {
return JSON.parse(JSON.stringify(obj));
}
exports.duplicate = duplicate;
function isBoolean(b) {
return b === true || b === false;
}
exports.isBoolean = isBoolean;
/**
* Convert a string into a valid variable name
*/
function varName(s) {
// Replace non-alphanumeric characters (anything besides a-zA-Z0-9_) with _
var alphanumericS = s.replace(/\W/g, '_');
// Add _ if the string has leading numbers.
return (s.match(/^\d+/) ? '_' : '') + alphanumericS;
}
exports.varName = varName;
function logicalExpr(op, cb) {
if (logical_1.isLogicalNot(op)) {
return '!(' + logicalExpr(op.not, cb) + ')';
}
else if (logical_1.isLogicalAnd(op)) {
return '(' + op.and.map(function (and) { return logicalExpr(and, cb); }).join(') && (') + ')';
}
else if (logical_1.isLogicalOr(op)) {
return '(' + op.or.map(function (or) { return logicalExpr(or, cb); }).join(') || (') + ')';
}
else {
return cb(op);
}
}
exports.logicalExpr = logicalExpr;
/**
* Delete nested property of an object, and delete the ancestors of the property if they become empty.
*/
function deleteNestedProperty(obj, orderedProps) {
var isEmpty = true;
while (orderedProps.length > 0 && isEmpty) {
var o = obj;
for (var i = 0; i < orderedProps.length - 1; i++) {
o = o[orderedProps[i]];
}
delete o[orderedProps.pop()];
if (exports.keys(o).length !== 0) {
isEmpty = false;
}
}
}
exports.deleteNestedProperty = deleteNestedProperty;
},{"./logical":102,"json-stable-stringify":1,"vega-util":7}],115:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var mark_1 = require("./mark");
var mark_2 = require("./mark");
var util_1 = require("./util");
/**
* Required Encoding Channels for each mark type
*/
exports.DEFAULT_REQUIRED_CHANNEL_MAP = {
text: ['text'],
line: ['x', 'y'],
area: ['x', 'y']
};
/**
* Supported Encoding Channel for each mark type
*/
exports.DEFAULT_SUPPORTED_CHANNEL_TYPE = {
bar: util_1.toSet(['row', 'column', 'x', 'y', 'size', 'color', 'detail']),
line: util_1.toSet(['row', 'column', 'x', 'y', 'color', 'detail']),
area: util_1.toSet(['row', 'column', 'x', 'y', 'color', 'detail']),
tick: util_1.toSet(['row', 'column', 'x', 'y', 'color', 'detail']),
circle: util_1.toSet(['row', 'column', 'x', 'y', 'color', 'size', 'detail']),
square: util_1.toSet(['row', 'column', 'x', 'y', 'color', 'size', 'detail']),
point: util_1.toSet(['row', 'column', 'x', 'y', 'color', 'size', 'detail', 'shape']),
text: util_1.toSet(['row', 'column', 'size', 'color', 'text']) // TODO(#724) revise
};
// TODO: consider if we should add validate method and
// requires ZSchema in the main vega-lite repo
/**
* Further check if encoding mapping of a spec is invalid and
* return error if it is invalid.
*
* This checks if
* (1) all the required encoding channels for the mark type are specified
* (2) all the specified encoding channels are supported by the mark type
* @param {[type]} spec [description]
* @param {RequiredChannelMap = DefaultRequiredChannelMap} requiredChannelMap
* @param {SupportedChannelMap = DefaultSupportedChannelMap} supportedChannelMap
* @return {String} Return one reason why the encoding is invalid,
* or null if the encoding is valid.
*/
function getEncodingMappingError(spec, requiredChannelMap, supportedChannelMap) {
if (requiredChannelMap === void 0) { requiredChannelMap = exports.DEFAULT_REQUIRED_CHANNEL_MAP; }
if (supportedChannelMap === void 0) { supportedChannelMap = exports.DEFAULT_SUPPORTED_CHANNEL_TYPE; }
var mark = mark_1.isMarkDef(spec.mark) ? spec.mark.type : spec.mark;
var encoding = spec.encoding;
var requiredChannels = requiredChannelMap[mark];
var supportedChannels = supportedChannelMap[mark];
for (var i in requiredChannels) {
if (!(requiredChannels[i] in encoding)) {
return 'Missing encoding channel \"' + requiredChannels[i] +
'\" for mark \"' + mark + '\"';
}
}
for (var channel in encoding) {
if (!supportedChannels[channel]) {
return 'Encoding channel \"' + channel +
'\" is not supported by mark type \"' + mark + '\"';
}
}
if (mark === mark_2.BAR && !encoding.x && !encoding.y) {
return 'Missing both x and y for bar';
}
return null;
}
exports.getEncodingMappingError = getEncodingMappingError;
},{"./mark":103,"./util":114}],116:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var util_1 = require("./util");
function isVgSignalRef(o) {
return !!o['signal'];
}
exports.isVgSignalRef = isVgSignalRef;
function isVgRangeStep(range) {
return !!range['step'];
}
exports.isVgRangeStep = isVgRangeStep;
function isDataRefUnionedDomain(domain) {
if (!util_1.isArray(domain)) {
return 'fields' in domain && !('data' in domain);
}
return false;
}
exports.isDataRefUnionedDomain = isDataRefUnionedDomain;
function isFieldRefUnionDomain(domain) {
if (!util_1.isArray(domain)) {
return 'fields' in domain && 'data' in domain;
}
return false;
}
exports.isFieldRefUnionDomain = isFieldRefUnionDomain;
function isDataRefDomain(domain) {
if (!util_1.isArray(domain)) {
return 'field' in domain && 'data' in domain;
}
return false;
}
exports.isDataRefDomain = isDataRefDomain;
function isSignalRefDomain(domain) {
if (!util_1.isArray(domain)) {
return 'signal' in domain;
}
return false;
}
exports.isSignalRefDomain = isSignalRefDomain;
},{"./util":114}]},{},[99])(99)
});
//# sourceMappingURL=vega-lite.js.map