(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vega-expression'), require('vega-dataflow'), require('vega-selections'), require('vega-statistics'), require('vega-time'), require('vega-util'), require('d3-array'), require('d3-color'), require('d3-format'), require('d3-time-format'), require('vega-scale'), require('d3-geo'), require('vega-scenegraph')) : typeof define === 'function' && define.amd ? define(['exports', 'vega-expression', 'vega-dataflow', 'vega-selections', 'vega-statistics', 'vega-time', 'vega-util', 'd3-array', 'd3-color', 'd3-format', 'd3-time-format', 'vega-scale', 'd3-geo', 'vega-scenegraph'], factory) : (global = global || self, factory(global.vega = {}, global.vega, global.vega, global.vega, global.vega, global.vega, global.vega, global.d3, global.d3, global.d3, global.d3, global.vega, global.d3, global.vega)); }(this, (function (exports, vegaExpression, vegaDataflow, vegaSelections, vegaStatistics, vegaTime, vegaUtil, d3Array, d3Color, d3Format, d3TimeFormat, vegaScale, d3Geo, vegaScenegraph) { 'use strict'; // https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef function channel_luminance_value(channelValue) { const val = channelValue / 255; if (val <= 0.03928) { return val / 12.92; } return Math.pow((val + 0.055) / 1.055, 2.4); } function luminance(color) { const c = d3Color.rgb(color), r = channel_luminance_value(c.r), g = channel_luminance_value(c.g), b = channel_luminance_value(c.b); return 0.2126 * r + 0.7152 * g + 0.0722 * b; } // https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef function contrast(color1, color2) { const lum1 = luminance(color1), lum2 = luminance(color2), lumL = Math.max(lum1, lum2), lumD = Math.min(lum1, lum2); return (lumL + 0.05) / (lumD + 0.05); } function data(name) { const data = this.context.data[name]; return data ? data.values.value : []; } function indata(name, field, value) { const index = this.context.data[name]['index:' + field], entry = index ? index.value.get(value) : undefined; return entry ? entry.count : entry; } function setdata(name, tuples) { const df = this.context.dataflow, data = this.context.data[name], input = data.input; df.pulse(input, df.changeset().remove(vegaUtil.truthy).insert(tuples)); return 1; } function encode(item, name, retval) { if (item) { const df = this.context.dataflow, target = item.mark.source; df.pulse(target, df.changeset().encode(item, name)); } return retval !== undefined ? retval : item; } const formatCache = {}; function formatter(type, method, specifier) { let k = type + ':' + specifier, e = formatCache[k]; if (!e || e[0] !== method) { formatCache[k] = (e = [method, method(specifier)]); } return e[1]; } function format(_, specifier) { return formatter('format', d3Format.format, specifier)(_); } function timeFormat(_, specifier) { return formatter('timeFormat', vegaTime.timeFormat, specifier)(_); } function utcFormat(_, specifier) { return formatter('utcFormat', vegaTime.utcFormat, specifier)(_); } function timeParse(_, specifier) { return formatter('timeParse', d3TimeFormat.timeParse, specifier)(_); } function utcParse(_, specifier) { return formatter('utcParse', d3TimeFormat.utcParse, specifier)(_); } var dateObj = new Date(2000, 0, 1); function time(month, day, specifier) { if (!Number.isInteger(month) || !Number.isInteger(day)) return ''; dateObj.setYear(2000); dateObj.setMonth(month); dateObj.setDate(day); return timeFormat(dateObj, specifier); } function monthFormat(month) { return time(month, 1, '%B'); } function monthAbbrevFormat(month) { return time(month, 1, '%b'); } function dayFormat(day) { return time(0, 2 + day, '%A'); } function dayAbbrevFormat(day) { return time(0, 2 + day, '%a'); } function getScale(name, ctx) { let s; return vegaUtil.isFunction(name) ? name : vegaUtil.isString(name) ? (s = ctx.scales[name]) && s.value : undefined; } function range(name, group) { const s = getScale(name, (group || this).context); return s && s.range ? s.range() : []; } function domain(name, group) { const s = getScale(name, (group || this).context); return s ? s.domain() : []; } function bandwidth(name, group) { const s = getScale(name, (group || this).context); return s && s.bandwidth ? s.bandwidth() : 0; } function bandspace(count, paddingInner, paddingOuter) { return vegaScale.bandSpace(count || 0, paddingInner || 0, paddingOuter || 0); } function copy(name, group) { const s = getScale(name, (group || this).context); return s ? s.copy() : undefined; } function scale(name, value, group) { const s = getScale(name, (group || this).context); return s && value !== undefined ? s(value) : undefined; } function invert(name, range, group) { const s = getScale(name, (group || this).context); return !s ? undefined : vegaUtil.isArray(range) ? (s.invertRange || s.invert)(range) : (s.invert || s.invertExtent)(range); } function geoMethod(methodName, globalMethod) { return function(projection, geojson, group) { if (projection) { // projection defined, use it const p = getScale(projection, (group || this).context); return p && p.path[methodName](geojson); } else { // projection undefined, use global method return globalMethod(geojson); } }; } const geoArea = geoMethod('area', d3Geo.geoArea); const geoBounds = geoMethod('bounds', d3Geo.geoBounds); const geoCentroid = geoMethod('centroid', d3Geo.geoCentroid); function inScope(item) { let group = this.context.group, value = false; if (group) while (item) { if (item === group) { value = true; break; } item = item.mark.group; } return value; } function intersect(b, opt, group) { if (!b) return []; const [u, v] = b, box = new vegaScenegraph.Bounds().set(u[0], u[1], v[0], v[1]), scene = group || this.context.dataflow.scenegraph().root; return vegaScenegraph.intersect(scene, box, filter(opt)); } function filter(opt) { let p = null; if (opt) { const types = vegaUtil.array(opt.marktype), names = vegaUtil.array(opt.markname); p = _ => (!types.length || types.some(t => _.marktype === t)) && (!names.length || names.some(s => _.name === s)); } return p; } function log(df, method, args) { try { df[method].apply(df, ['EXPRESSION'].concat([].slice.call(args))); } catch (err) { df.warn(err); } return args[args.length-1]; } function warn() { return log(this.context.dataflow, 'warn', arguments); } function info() { return log(this.context.dataflow, 'info', arguments); } function debug() { return log(this.context.dataflow, 'debug', arguments); } function merge() { var args = [].slice.call(arguments); args.unshift({}); return vegaUtil.extend.apply(null, args); } function equal(a, b) { return a === b || a !== a && b !== b ? true : vegaUtil.isArray(a) ? ( vegaUtil.isArray(b) && a.length === b.length ? equalArray(a, b) : false ) : vegaUtil.isObject(a) && vegaUtil.isObject(b) ? equalObject(a, b) : false; } function equalArray(a, b) { for (let i=0, n=a.length; i equalObject(props, _); } function modify(name, insert, remove, toggle, modify, values) { let df = this.context.dataflow, data = this.context.data[name], input = data.input, changes = data.changes, stamp = df.stamp(), predicate, key; if (df._trigger === false || !(input.value.length || insert || toggle)) { // nothing to do! return 0; } if (!changes || changes.stamp < stamp) { data.changes = (changes = df.changeset()); changes.stamp = stamp; df.runAfter(function() { data.modified = true; df.pulse(input, changes).run(); }, true, 1); } if (remove) { predicate = remove === true ? vegaUtil.truthy : (vegaUtil.isArray(remove) || vegaDataflow.isTuple(remove)) ? remove : removePredicate(remove); changes.remove(predicate); } if (insert) { changes.insert(insert); } if (toggle) { predicate = removePredicate(toggle); if (input.value.some(predicate)) { changes.remove(predicate); } else { changes.insert(toggle); } } if (modify) { for (key in values) { changes.modify(modify, key, values[key]); } } return 1; } function pinchDistance(event) { const t = event.touches, dx = t[0].clientX - t[1].clientX, dy = t[0].clientY - t[1].clientY; return Math.sqrt(dx * dx + dy * dy); } function pinchAngle(event) { const t = event.touches; return Math.atan2( t[0].clientY - t[1].clientY, t[0].clientX - t[1].clientX ); } function scaleGradient(scale, p0, p1, count, group) { scale = getScale(scale, (group || this).context); const gradient = vegaScenegraph.Gradient(p0, p1); let stops = scale.domain(), min = stops[0], max = vegaUtil.peek(stops), fraction = vegaUtil.identity; if (!(max - min)) { // expand scale if domain has zero span, fix #1479 scale = (scale.interpolator ? vegaScale.scale('sequential')().interpolator(scale.interpolator()) : vegaScale.scale('linear')().interpolate(scale.interpolate()).range(scale.range()) ).domain([min=0, max=1]); } else { fraction = vegaScale.scaleFraction(scale, min, max); } if (scale.ticks) { stops = scale.ticks(+count || 15); if (min !== stops[0]) stops.unshift(min); if (max !== vegaUtil.peek(stops)) stops.push(max); } stops.forEach(_ => gradient.stop(fraction(_), scale(_))); return gradient; } function geoShape(projection, geojson, group) { const p = getScale(projection, (group || this).context); return function(context) { return p ? p.path.context(context)(geojson) : ''; } } function pathShape(path) { let p = null; return function(context) { return context ? vegaScenegraph.pathRender(context, (p = p || vegaScenegraph.pathParse(path))) : path; }; } const EMPTY = {}; function datum(d) { return d.data; } function treeNodes(name, context) { const tree = data.call(context, name); return tree.root && tree.root.lookup || EMPTY; } function treePath(name, source, target) { const nodes = treeNodes(name, this), s = nodes[source], t = nodes[target]; return s && t ? s.path(t).map(datum) : undefined; } function treeAncestors(name, node) { const n = treeNodes(name, this)[node]; return n ? n.ancestors().map(datum) : undefined; } const _window = (typeof window !== 'undefined' && window) || null; function screen() { return _window ? _window.screen : {}; } function windowSize() { return _window ? [_window.innerWidth, _window.innerHeight] : [undefined, undefined]; } function containerSize() { const view = this.context.dataflow, el = view.container && view.container(); return el ? [el.clientWidth, el.clientHeight] : [undefined, undefined]; } const DataPrefix = ':'; const IndexPrefix = '@'; const ScalePrefix = '%'; const SignalPrefix = '$'; function dataVisitor(name, args, scope, params) { if (args[0].type !== vegaExpression.Literal) { vegaUtil.error('First argument to data functions must be a string literal.'); } const data = args[0].value, dataName = DataPrefix + data; if (!vegaUtil.hasOwnProperty(dataName, params)) { try { params[dataName] = scope.getData(data).tuplesRef(); } catch (err) { // if data set does not exist, there's nothing to track } } } function indataVisitor(name, args, scope, params) { if (args[0].type !== vegaExpression.Literal) vegaUtil.error('First argument to indata must be a string literal.'); if (args[1].type !== vegaExpression.Literal) vegaUtil.error('Second argument to indata must be a string literal.'); const data = args[0].value, field = args[1].value, indexName = IndexPrefix + field; if (!vegaUtil.hasOwnProperty(indexName, params)) { params[indexName] = scope.getData(data).indataRef(scope, field); } } function scaleVisitor(name, args, scope, params) { if (args[0].type === vegaExpression.Literal) { // add scale dependency addScaleDependency(scope, params, args[0].value); } else if (args[0].type === vegaExpression.Identifier) { // indirect scale lookup; add all scales as parameters for (name in scope.scales) { addScaleDependency(scope, params, name); } } } function addScaleDependency(scope, params, name) { const scaleName = ScalePrefix + name; if (!vegaUtil.hasOwnProperty(params, scaleName)) { try { params[scaleName] = scope.scaleRef(name); } catch (err) { // TODO: error handling? warning? } } } // Expression function context object const functionContext = { random: function() { return vegaStatistics.random(); }, // override default cumulativeNormal: vegaStatistics.cumulativeNormal, cumulativeLogNormal: vegaStatistics.cumulativeLogNormal, cumulativeUniform: vegaStatistics.cumulativeUniform, densityNormal: vegaStatistics.densityNormal, densityLogNormal: vegaStatistics.densityLogNormal, densityUniform: vegaStatistics.densityUniform, quantileNormal: vegaStatistics.quantileNormal, quantileLogNormal: vegaStatistics.quantileLogNormal, quantileUniform: vegaStatistics.quantileUniform, sampleNormal: vegaStatistics.sampleNormal, sampleLogNormal: vegaStatistics.sampleLogNormal, sampleUniform: vegaStatistics.sampleUniform, isArray: vegaUtil.isArray, isBoolean: vegaUtil.isBoolean, isDate: vegaUtil.isDate, isDefined: function(_) { return _ !== undefined; }, isNumber: vegaUtil.isNumber, isObject: vegaUtil.isObject, isRegExp: vegaUtil.isRegExp, isString: vegaUtil.isString, isTuple: vegaDataflow.isTuple, isValid: function(_) { return _ != null && _ === _; }, toBoolean: vegaUtil.toBoolean, toDate: vegaUtil.toDate, toNumber: vegaUtil.toNumber, toString: vegaUtil.toString, flush: vegaUtil.flush, lerp: vegaUtil.lerp, merge, pad: vegaUtil.pad, peek: vegaUtil.peek, span: vegaUtil.span, inrange: vegaUtil.inrange, truncate: vegaUtil.truncate, rgb: d3Color.rgb, lab: d3Color.lab, hcl: d3Color.hcl, hsl: d3Color.hsl, luminance, contrast, sequence: d3Array.range, format, utcFormat, utcParse, utcOffset: vegaTime.utcOffset, utcSequence: vegaTime.utcSequence, timeFormat, timeParse, timeOffset: vegaTime.timeOffset, timeSequence: vegaTime.timeSequence, timeUnitSpecifier: vegaTime.timeUnitSpecifier, monthFormat, monthAbbrevFormat, dayFormat, dayAbbrevFormat, quarter: vegaUtil.quarter, utcquarter: vegaUtil.utcquarter, warn, info, debug, extent: vegaUtil.extent, inScope, intersect, clampRange: vegaUtil.clampRange, pinchDistance, pinchAngle, screen, containerSize, windowSize, bandspace, setdata, pathShape, panLinear: vegaUtil.panLinear, panLog: vegaUtil.panLog, panPow: vegaUtil.panPow, panSymlog: vegaUtil.panSymlog, zoomLinear: vegaUtil.zoomLinear, zoomLog: vegaUtil.zoomLog, zoomPow: vegaUtil.zoomPow, zoomSymlog: vegaUtil.zoomSymlog, encode, modify }; const eventFunctions = ['view', 'item', 'group', 'xy', 'x', 'y'], // event functions eventPrefix = 'event.vega.', // event function prefix thisPrefix = 'this.', // function context prefix astVisitors = {}; // AST visitors for dependency analysis // Build expression function registry function buildFunctions(codegen) { const fn = vegaExpression.functions(codegen); eventFunctions.forEach(name => fn[name] = eventPrefix + name); for (let name in functionContext) { fn[name] = thisPrefix + name; } return fn; } // Register an expression function function expressionFunction(name, fn, visitor) { if (arguments.length === 1) { return functionContext[name]; } // register with the functionContext functionContext[name] = fn; // if there is an astVisitor register that, too if (visitor) astVisitors[name] = visitor; // if the code generator has already been initialized, // we need to also register the function with it if (codeGenerator) codeGenerator.functions[name] = thisPrefix + name; return this; } // register expression functions with ast visitors expressionFunction('bandwidth', bandwidth, scaleVisitor); expressionFunction('copy', copy, scaleVisitor); expressionFunction('domain', domain, scaleVisitor); expressionFunction('range', range, scaleVisitor); expressionFunction('invert', invert, scaleVisitor); expressionFunction('scale', scale, scaleVisitor); expressionFunction('gradient', scaleGradient, scaleVisitor); expressionFunction('geoArea', geoArea, scaleVisitor); expressionFunction('geoBounds', geoBounds, scaleVisitor); expressionFunction('geoCentroid', geoCentroid, scaleVisitor); expressionFunction('geoShape', geoShape, scaleVisitor); expressionFunction('indata', indata, indataVisitor); expressionFunction('data', data, dataVisitor); expressionFunction('treePath', treePath, dataVisitor); expressionFunction('treeAncestors', treeAncestors, dataVisitor); // register Vega-Lite selection functions expressionFunction('vlSelectionTest', vegaSelections.selectionTest, vegaSelections.selectionVisitor); expressionFunction('vlSelectionResolve', vegaSelections.selectionResolve, vegaSelections.selectionVisitor); // Export code generator and parameters const codegenParams = { blacklist: ['_'], whitelist: ['datum', 'event', 'item'], fieldvar: 'datum', globalvar: function(id) { return '_[' + vegaUtil.stringValue(SignalPrefix + id) + ']'; }, functions: buildFunctions, constants: vegaExpression.constants, visitors: astVisitors }; var codeGenerator = vegaExpression.codegen(codegenParams); Object.defineProperty(exports, 'formatLocale', { enumerable: true, get: function () { return d3Format.formatDefaultLocale; } }); Object.defineProperty(exports, 'timeFormatLocale', { enumerable: true, get: function () { return d3TimeFormat.timeFormatDefaultLocale; } }); exports.DataPrefix = DataPrefix; exports.IndexPrefix = IndexPrefix; exports.ScalePrefix = ScalePrefix; exports.SignalPrefix = SignalPrefix; exports.bandspace = bandspace; exports.bandwidth = bandwidth; exports.codeGenerator = codeGenerator; exports.codegenParams = codegenParams; exports.containerSize = containerSize; exports.contrast = contrast; exports.copy = copy; exports.data = data; exports.dataVisitor = dataVisitor; exports.dayAbbrevFormat = dayAbbrevFormat; exports.dayFormat = dayFormat; exports.debug = debug; exports.domain = domain; exports.encode = encode; exports.expressionFunction = expressionFunction; exports.format = format; exports.functionContext = functionContext; exports.geoArea = geoArea; exports.geoBounds = geoBounds; exports.geoCentroid = geoCentroid; exports.geoShape = geoShape; exports.inScope = inScope; exports.indata = indata; exports.indataVisitor = indataVisitor; exports.info = info; exports.invert = invert; exports.luminance = luminance; exports.merge = merge; exports.modify = modify; exports.monthAbbrevFormat = monthAbbrevFormat; exports.monthFormat = monthFormat; exports.pathShape = pathShape; exports.pinchAngle = pinchAngle; exports.pinchDistance = pinchDistance; exports.range = range; exports.scale = scale; exports.scaleGradient = scaleGradient; exports.scaleVisitor = scaleVisitor; exports.screen = screen; exports.setdata = setdata; exports.timeFormat = timeFormat; exports.timeParse = timeParse; exports.treeAncestors = treeAncestors; exports.treePath = treePath; exports.utcFormat = utcFormat; exports.utcParse = utcParse; exports.warn = warn; exports.windowSize = windowSize; Object.defineProperty(exports, '__esModule', { value: true }); })));