(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vega-dataflow'), require('vega-util'), require('d3-hierarchy')) : typeof define === 'function' && define.amd ? define(['exports', 'vega-dataflow', 'vega-util', 'd3-hierarchy'], factory) : (global = global || self, factory((global.vega = global.vega || {}, global.vega.transforms = {}), global.vega, global.vega, global.d3)); }(this, function (exports, vegaDataflow, vegaUtil, d3Hierarchy) { 'use strict'; // Build lookup table mapping tuple keys to tree node instances function lookup(tree, key, filter) { var map = {}; tree.each(function(node) { var t = node.data; if (filter(t)) map[key(t)] = node; }); tree.lookup = map; return tree; } /** * Nest tuples into a tree structure, grouped by key values. * @constructor * @param {object} params - The parameters for this operator. * @param {Array} params.keys - The key fields to nest by, in order. * @param {boolean} [params.generate=false] - A boolean flag indicating if * non-leaf nodes generated by this transform should be included in the * output. The default (false) includes only the input data (leaf nodes) * in the data stream. */ function Nest(params) { vegaDataflow.Transform.call(this, null, params); } Nest.Definition = { "type": "Nest", "metadata": {"treesource": true, "changes": true}, "params": [ { "name": "keys", "type": "field", "array": true }, { "name": "generate", "type": "boolean" } ] }; var prototype = vegaUtil.inherits(Nest, vegaDataflow.Transform); function children(n) { return n.values; } prototype.transform = function(_, pulse) { if (!pulse.source) { vegaUtil.error('Nest transform requires an upstream data source.'); } var gen = _.generate, mod = _.modified(), out = pulse.clone(), tree = this.value; if (!tree || mod || pulse.changed()) { // collect nodes to remove if (tree) { tree.each(node => { if (node.children && vegaDataflow.isTuple(node.data)) { out.rem.push(node.data); } }); } // generate new tree structure this.value = tree = d3Hierarchy.hierarchy({ values: vegaUtil.array(_.keys) .reduce((n, k) => { n.key(k); return n; }, nest()) .entries(out.source) }, children); // collect nodes to add if (gen) { tree.each(node => { if (node.children) { node = vegaDataflow.ingest(node.data); out.add.push(node); out.source.push(node); } }); } // build lookup table lookup(tree, vegaDataflow.tupleid, vegaDataflow.tupleid); } out.source.root = tree; return out; }; function nest() { var keys = [], nest; function apply(array, depth) { if (depth >= keys.length) { return array; } var i = -1, n = array.length, key = keys[depth++], keyValue, value, valuesByKey = {}, values, result = {}; while (++i < n) { keyValue = key(value = array[i]) + ''; if (values = valuesByKey[keyValue]) { values.push(value); } else { valuesByKey[keyValue] = [value]; } } for (keyValue in valuesByKey) { result[keyValue] = apply(valuesByKey[keyValue], depth); } return result; } function entries(map, depth) { if (++depth > keys.length) return map; var array = [], k; for (k in map) { array.push({key: k, values: entries(map[k], depth)}); } return array; } return nest = { entries: array => entries(apply(array, 0), 0), key: d => { keys.push(d); return nest; } }; } /** * Abstract class for tree layout. * @constructor * @param {object} params - The parameters for this operator. */ function HierarchyLayout(params) { vegaDataflow.Transform.call(this, null, params); } var prototype$1 = vegaUtil.inherits(HierarchyLayout, vegaDataflow.Transform); prototype$1.transform = function(_, pulse) { if (!pulse.source || !pulse.source.root) { vegaUtil.error(this.constructor.name + ' transform requires a backing tree data source.'); } var layout = this.layout(_.method), fields = this.fields, root = pulse.source.root, as = _.as || fields; if (_.field) root.sum(_.field); else root.count(); if (_.sort) root.sort(vegaDataflow.stableCompare(_.sort, d => d.data)); setParams(layout, this.params, _); if (layout.separation) { layout.separation(_.separation !== false ? defaultSeparation : vegaUtil.one); } try { this.value = layout(root); } catch (err) { vegaUtil.error(err); } root.each(function(node) { setFields(node, fields, as); }); return pulse.reflow(_.modified()).modifies(as).modifies('leaf'); }; function setParams(layout, params, _) { for (var p, i=0, n=params.length; i