vega-hierarchy
Advanced tools
Comparing version 2.1.2 to 3.0.0
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vega-dataflow'), require('vega-util'), require('d3-collection'), require('d3-hierarchy')) : | ||
typeof define === 'function' && define.amd ? define(['exports', 'vega-dataflow', 'vega-util', 'd3-collection', 'd3-hierarchy'], factory) : | ||
(factory((global.vega = global.vega || {}, global.vega.transforms = global.vega.transforms || {}),global.vega,global.vega,global.d3,global.d3)); | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vega-dataflow'), require('vega-util'), require('d3-collection'), require('d3-hierarchy')) : | ||
typeof define === 'function' && define.amd ? define(['exports', 'vega-dataflow', 'vega-util', 'd3-collection', 'd3-hierarchy'], factory) : | ||
(factory((global.vega = global.vega || {}, global.vega.transforms = {}),global.vega,global.vega,global.d3,global.d3)); | ||
}(this, (function (exports,vegaDataflow,vegaUtil,d3Collection,d3Hierarchy) { 'use strict'; | ||
/** | ||
* Nest tuples into a tree structure, grouped by key values. | ||
* @constructor | ||
* @param {object} params - The parameters for this operator. | ||
* @param {Array<function(object): *>} params.keys - The key fields to nest by, in order. | ||
* @param {function(object): *} [params.key] - Unique key field for each tuple. | ||
* If not provided, the tuple id field is used. | ||
* @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); | ||
} | ||
// 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.Definition = { | ||
"type": "Nest", | ||
"metadata": {"treesource": true, "changes": true}, | ||
"params": [ | ||
{ "name": "keys", "type": "field", "array": true }, | ||
{ "name": "key", "type": "field" }, | ||
{ "name": "generate", "type": "boolean" } | ||
] | ||
}; | ||
/** | ||
* Nest tuples into a tree structure, grouped by key values. | ||
* @constructor | ||
* @param {object} params - The parameters for this operator. | ||
* @param {Array<function(object): *>} 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); | ||
} | ||
var prototype = vegaUtil.inherits(Nest, vegaDataflow.Transform); | ||
Nest.Definition = { | ||
"type": "Nest", | ||
"metadata": {"treesource": true, "changes": true}, | ||
"params": [ | ||
{ "name": "keys", "type": "field", "array": true }, | ||
{ "name": "generate", "type": "boolean" } | ||
] | ||
}; | ||
function children(n) { | ||
return n.values; | ||
} | ||
var prototype = vegaUtil.inherits(Nest, vegaDataflow.Transform); | ||
prototype.transform = function(_, pulse) { | ||
if (!pulse.source) { | ||
vegaUtil.error('Nest transform requires an upstream data source.'); | ||
function children(n) { | ||
return n.values; | ||
} | ||
var key = _.key || vegaDataflow.tupleid, | ||
gen = _.generate, | ||
mod = _.modified(), | ||
out = pulse.clone(), | ||
root, tree$$1, map; | ||
if (!this.value || mod || pulse.changed()) { | ||
// collect nodes to remove | ||
if (gen && this.value) { | ||
this.value.each(function(node) { | ||
if (node.children) out.rem.push(node); | ||
}); | ||
prototype.transform = function(_, pulse) { | ||
if (!pulse.source) { | ||
vegaUtil.error('Nest transform requires an upstream data source.'); | ||
} | ||
// generate new tree structure | ||
root = vegaUtil.array(_.keys) | ||
.reduce(function(n, k) { n.key(k); return n; }, d3Collection.nest()) | ||
.entries(out.source); | ||
this.value = tree$$1 = d3Hierarchy.hierarchy({values: root}, children); | ||
var gen = _.generate, | ||
mod = _.modified(), | ||
out = pulse.clone(), | ||
tree = this.value; | ||
// collect nodes to add | ||
if (gen) { | ||
tree$$1.each(function(node) { | ||
if (node.children) { | ||
node = vegaDataflow.ingest(node.data); | ||
out.add.push(node); | ||
out.source.push(node); | ||
} | ||
}); | ||
} | ||
if (!tree || mod || pulse.changed()) { | ||
// collect nodes to remove | ||
if (tree) { | ||
tree.each(function(node) { | ||
if (node.children && vegaDataflow.isTuple(node.data)) { | ||
out.rem.push(node.data); | ||
} | ||
}); | ||
} | ||
// build lookup table | ||
map = tree$$1.lookup = {}; | ||
tree$$1.each(function(node) { | ||
if (vegaDataflow.tupleid(node.data) != null) { | ||
map[key(node.data)] = node; | ||
// generate new tree structure | ||
this.value = tree = d3Hierarchy.hierarchy({ | ||
values: vegaUtil.array(_.keys) | ||
.reduce(function(n, k) { n.key(k); return n; }, d3Collection.nest()) | ||
.entries(out.source) | ||
}, children); | ||
// collect nodes to add | ||
if (gen) { | ||
tree.each(function(node) { | ||
if (node.children) { | ||
node = vegaDataflow.ingest(node.data); | ||
out.add.push(node); | ||
out.source.push(node); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
out.source.root = this.value; | ||
return out; | ||
}; | ||
// build lookup table | ||
lookup(tree, vegaDataflow.tupleid, vegaDataflow.tupleid); | ||
} | ||
/** | ||
* Abstract class for tree layout. | ||
* @constructor | ||
* @param {object} params - The parameters for this operator. | ||
*/ | ||
function HierarchyLayout(params) { | ||
vegaDataflow.Transform.call(this, null, params); | ||
} | ||
out.source.root = tree; | ||
return out; | ||
}; | ||
var prototype$2 = vegaUtil.inherits(HierarchyLayout, vegaDataflow.Transform); | ||
prototype$2.transform = function(_, pulse) { | ||
if (!pulse.source || !pulse.source.root) { | ||
vegaUtil.error(this.constructor.name | ||
+ ' transform requires a backing tree data source.'); | ||
/** | ||
* Abstract class for tree layout. | ||
* @constructor | ||
* @param {object} params - The parameters for this operator. | ||
*/ | ||
function HierarchyLayout(params) { | ||
vegaDataflow.Transform.call(this, null, params); | ||
} | ||
var layout = this.layout(_.method), | ||
fields = this.fields, | ||
root = pulse.source.root, | ||
as = _.as || fields; | ||
var prototype$1 = vegaUtil.inherits(HierarchyLayout, vegaDataflow.Transform); | ||
if (_.field) root.sum(_.field); | ||
if (_.sort) root.sort(_.sort); | ||
prototype$1.transform = function(_, pulse) { | ||
if (!pulse.source || !pulse.source.root) { | ||
vegaUtil.error(this.constructor.name | ||
+ ' transform requires a backing tree data source.'); | ||
} | ||
setParams(layout, this.params, _); | ||
try { | ||
this.value = layout(root); | ||
} catch (err) { | ||
vegaUtil.error(err); | ||
} | ||
root.each(function(node) { setFields(node, fields, as); }); | ||
var layout = this.layout(_.method), | ||
fields = this.fields, | ||
root = pulse.source.root, | ||
as = _.as || fields; | ||
return pulse.reflow(_.modified()).modifies(as).modifies('leaf'); | ||
}; | ||
if (_.field) root.sum(_.field); | ||
if (_.sort) root.sort(_.sort); | ||
function setParams(layout, params, _) { | ||
for (var p, i=0, n=params.length; i<n; ++i) { | ||
p = params[i]; | ||
if (p in _) layout[p](_[p]); | ||
setParams(layout, this.params, _); | ||
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<n; ++i) { | ||
p = params[i]; | ||
if (p in _) layout[p](_[p]); | ||
} | ||
} | ||
} | ||
function setFields(node, fields, as) { | ||
var t = node.data; | ||
for (var i=0, n=fields.length-1; i<n; ++i) { | ||
t[as[i]] = node[fields[i]]; | ||
function setFields(node, fields, as) { | ||
var t = node.data; | ||
for (var i=0, n=fields.length-1; i<n; ++i) { | ||
t[as[i]] = node[fields[i]]; | ||
} | ||
t[as[n]] = node.children ? node.children.length : 0; | ||
} | ||
t[as[n]] = node.children ? node.children.length : 0; | ||
} | ||
var Output = ['x', 'y', 'r', 'depth', 'children']; | ||
var Output = ['x', 'y', 'r', 'depth', 'children']; | ||
/** | ||
* Packed circle tree layout. | ||
* @constructor | ||
* @param {object} params - The parameters for this operator. | ||
* @param {function(object): *} params.field - The value field to size nodes. | ||
*/ | ||
function Pack(params) { | ||
HierarchyLayout.call(this, params); | ||
} | ||
/** | ||
* Packed circle tree layout. | ||
* @constructor | ||
* @param {object} params - The parameters for this operator. | ||
* @param {function(object): *} params.field - The value field to size nodes. | ||
*/ | ||
function Pack(params) { | ||
HierarchyLayout.call(this, params); | ||
} | ||
Pack.Definition = { | ||
"type": "Pack", | ||
"metadata": {"tree": true, "modifies": true}, | ||
"params": [ | ||
{ "name": "field", "type": "field" }, | ||
{ "name": "sort", "type": "compare" }, | ||
{ "name": "padding", "type": "number", "default": 0 }, | ||
{ "name": "radius", "type": "field", "default": null }, | ||
{ "name": "size", "type": "number", "array": true, "length": 2 }, | ||
{ "name": "as", "type": "string", "array": true, "length": 3, "default": Output } | ||
] | ||
}; | ||
Pack.Definition = { | ||
"type": "Pack", | ||
"metadata": {"tree": true, "modifies": true}, | ||
"params": [ | ||
{ "name": "field", "type": "field" }, | ||
{ "name": "sort", "type": "compare" }, | ||
{ "name": "padding", "type": "number", "default": 0 }, | ||
{ "name": "radius", "type": "field", "default": null }, | ||
{ "name": "size", "type": "number", "array": true, "length": 2 }, | ||
{ "name": "as", "type": "string", "array": true, "length": 3, "default": Output } | ||
] | ||
}; | ||
var prototype$1 = vegaUtil.inherits(Pack, HierarchyLayout); | ||
var prototype$2 = vegaUtil.inherits(Pack, HierarchyLayout); | ||
prototype$1.layout = d3Hierarchy.pack; | ||
prototype$2.layout = d3Hierarchy.pack; | ||
prototype$1.params = ['size', 'padding']; | ||
prototype$2.params = ['size', 'padding']; | ||
prototype$1.fields = Output; | ||
prototype$2.fields = Output; | ||
var Output$1 = ["x0", "y0", "x1", "y1", "depth", "children"]; | ||
var Output$1 = ["x0", "y0", "x1", "y1", "depth", "children"]; | ||
/** | ||
* Partition tree layout. | ||
* @constructor | ||
* @param {object} params - The parameters for this operator. | ||
* @param {function(object): *} params.field - The value field to size nodes. | ||
*/ | ||
function Partition(params) { | ||
HierarchyLayout.call(this, params); | ||
} | ||
/** | ||
* Partition tree layout. | ||
* @constructor | ||
* @param {object} params - The parameters for this operator. | ||
* @param {function(object): *} params.field - The value field to size nodes. | ||
*/ | ||
function Partition(params) { | ||
HierarchyLayout.call(this, params); | ||
} | ||
Partition.Definition = { | ||
"type": "Partition", | ||
"metadata": {"tree": true, "modifies": true}, | ||
"params": [ | ||
{ "name": "field", "type": "field" }, | ||
{ "name": "sort", "type": "compare" }, | ||
{ "name": "padding", "type": "number", "default": 0 }, | ||
{ "name": "round", "type": "boolean", "default": false }, | ||
{ "name": "size", "type": "number", "array": true, "length": 2 }, | ||
{ "name": "as", "type": "string", "array": true, "length": 4, "default": Output$1 } | ||
] | ||
}; | ||
Partition.Definition = { | ||
"type": "Partition", | ||
"metadata": {"tree": true, "modifies": true}, | ||
"params": [ | ||
{ "name": "field", "type": "field" }, | ||
{ "name": "sort", "type": "compare" }, | ||
{ "name": "padding", "type": "number", "default": 0 }, | ||
{ "name": "round", "type": "boolean", "default": false }, | ||
{ "name": "size", "type": "number", "array": true, "length": 2 }, | ||
{ "name": "as", "type": "string", "array": true, "length": 4, "default": Output$1 } | ||
] | ||
}; | ||
var prototype$3 = vegaUtil.inherits(Partition, HierarchyLayout); | ||
var prototype$3 = vegaUtil.inherits(Partition, HierarchyLayout); | ||
prototype$3.layout = d3Hierarchy.partition; | ||
prototype$3.layout = d3Hierarchy.partition; | ||
prototype$3.params = ['size', 'round', 'padding']; | ||
prototype$3.params = ['size', 'round', 'padding']; | ||
prototype$3.fields = Output$1; | ||
prototype$3.fields = Output$1; | ||
/** | ||
* Stratify a collection of tuples into a tree structure based on | ||
* id and parent id fields. | ||
* @constructor | ||
* @param {object} params - The parameters for this operator. | ||
* @param {function(object): *} params.key - Unique key field for each tuple. | ||
* @param {function(object): *} params.parentKey - Field with key for parent tuple. | ||
*/ | ||
function Stratify(params) { | ||
vegaDataflow.Transform.call(this, null, params); | ||
} | ||
/** | ||
* Stratify a collection of tuples into a tree structure based on | ||
* id and parent id fields. | ||
* @constructor | ||
* @param {object} params - The parameters for this operator. | ||
* @param {function(object): *} params.key - Unique key field for each tuple. | ||
* @param {function(object): *} params.parentKey - Field with key for parent tuple. | ||
*/ | ||
function Stratify(params) { | ||
vegaDataflow.Transform.call(this, null, params); | ||
} | ||
Stratify.Definition = { | ||
"type": "Stratify", | ||
"metadata": {"treesource": true}, | ||
"params": [ | ||
{ "name": "key", "type": "field", "required": true }, | ||
{ "name": "parentKey", "type": "field", "required": true } | ||
] | ||
}; | ||
Stratify.Definition = { | ||
"type": "Stratify", | ||
"metadata": {"treesource": true}, | ||
"params": [ | ||
{ "name": "key", "type": "field", "required": true }, | ||
{ "name": "parentKey", "type": "field", "required": true } | ||
] | ||
}; | ||
var prototype$4 = vegaUtil.inherits(Stratify, vegaDataflow.Transform); | ||
var prototype$4 = vegaUtil.inherits(Stratify, vegaDataflow.Transform); | ||
prototype$4.transform = function(_, pulse) { | ||
if (!pulse.source) { | ||
vegaUtil.error('Stratify transform requires an upstream data source.'); | ||
} | ||
prototype$4.transform = function(_, pulse) { | ||
if (!pulse.source) { | ||
vegaUtil.error('Stratify transform requires an upstream data source.'); | ||
} | ||
var mod = _.modified(), tree$$1, map, | ||
out = pulse.fork(pulse.ALL).materialize(pulse.SOURCE), | ||
run = !this.value | ||
|| mod | ||
|| pulse.changed(pulse.ADD_REM) | ||
|| pulse.modified(_.key.fields) | ||
|| pulse.modified(_.parentKey.fields); | ||
var mod = _.modified(), | ||
out = pulse.fork(pulse.ALL).materialize(pulse.SOURCE), | ||
run = !this.value | ||
|| mod | ||
|| pulse.changed(pulse.ADD_REM) | ||
|| pulse.modified(_.key.fields) | ||
|| pulse.modified(_.parentKey.fields); | ||
// prevent upstream source pollution | ||
out.source = out.source.slice(); | ||
// prevent upstream source pollution | ||
out.source = out.source.slice(); | ||
if (run) { | ||
tree$$1 = d3Hierarchy.stratify().id(_.key).parentId(_.parentKey)(out.source); | ||
map = tree$$1.lookup = {}; | ||
tree$$1.each(function(node) { map[_.key(node.data)] = node; }); | ||
this.value = tree$$1; | ||
} | ||
if (run) { | ||
this.value = lookup( | ||
d3Hierarchy.stratify().id(_.key).parentId(_.parentKey)(out.source), | ||
_.key, vegaUtil.truthy | ||
); | ||
} | ||
out.source.root = this.value; | ||
return out; | ||
}; | ||
out.source.root = this.value; | ||
return out; | ||
}; | ||
var Layouts = { | ||
tidy: d3Hierarchy.tree, | ||
cluster: d3Hierarchy.cluster | ||
}; | ||
var Layouts = { | ||
tidy: d3Hierarchy.tree, | ||
cluster: d3Hierarchy.cluster | ||
}; | ||
var Output$2 = ["x", "y", "depth", "children"]; | ||
var Output$2 = ["x", "y", "depth", "children"]; | ||
/** | ||
* Tree layout. Depending on the method parameter, performs either | ||
* Reingold-Tilford 'tidy' layout or dendrogram 'cluster' layout. | ||
* @constructor | ||
* @param {object} params - The parameters for this operator. | ||
*/ | ||
function Tree(params) { | ||
HierarchyLayout.call(this, params); | ||
} | ||
/** | ||
* Tree layout. Depending on the method parameter, performs either | ||
* Reingold-Tilford 'tidy' layout or dendrogram 'cluster' layout. | ||
* @constructor | ||
* @param {object} params - The parameters for this operator. | ||
*/ | ||
function Tree(params) { | ||
HierarchyLayout.call(this, params); | ||
} | ||
Tree.Definition = { | ||
"type": "Tree", | ||
"metadata": {"tree": true, "modifies": true}, | ||
"params": [ | ||
{ "name": "field", "type": "field" }, | ||
{ "name": "sort", "type": "compare" }, | ||
{ "name": "method", "type": "enum", "default": "tidy", "values": ["tidy", "cluster"] }, | ||
{ "name": "size", "type": "number", "array": true, "length": 2 }, | ||
{ "name": "nodeSize", "type": "number", "array": true, "length": 2 }, | ||
{ "name": "as", "type": "string", "array": true, "length": 4, "default": Output$2 } | ||
] | ||
}; | ||
Tree.Definition = { | ||
"type": "Tree", | ||
"metadata": {"tree": true, "modifies": true}, | ||
"params": [ | ||
{ "name": "field", "type": "field" }, | ||
{ "name": "sort", "type": "compare" }, | ||
{ "name": "method", "type": "enum", "default": "tidy", "values": ["tidy", "cluster"] }, | ||
{ "name": "size", "type": "number", "array": true, "length": 2 }, | ||
{ "name": "nodeSize", "type": "number", "array": true, "length": 2 }, | ||
{ "name": "as", "type": "string", "array": true, "length": 4, "default": Output$2 } | ||
] | ||
}; | ||
var prototype$5 = vegaUtil.inherits(Tree, HierarchyLayout); | ||
var prototype$5 = vegaUtil.inherits(Tree, HierarchyLayout); | ||
/** | ||
* Tree layout generator. Supports both 'tidy' and 'cluster' layouts. | ||
*/ | ||
prototype$5.layout = function(method) { | ||
var m = method || 'tidy'; | ||
if (Layouts.hasOwnProperty(m)) return Layouts[m](); | ||
else vegaUtil.error('Unrecognized Tree layout method: ' + m); | ||
}; | ||
/** | ||
* Tree layout generator. Supports both 'tidy' and 'cluster' layouts. | ||
*/ | ||
prototype$5.layout = function(method) { | ||
var m = method || 'tidy'; | ||
if (Layouts.hasOwnProperty(m)) return Layouts[m](); | ||
else vegaUtil.error('Unrecognized Tree layout method: ' + m); | ||
}; | ||
prototype$5.params = ['size', 'nodeSize', 'separation']; | ||
prototype$5.params = ['size', 'nodeSize', 'separation']; | ||
prototype$5.fields = Output$2; | ||
prototype$5.fields = Output$2; | ||
/** | ||
* Generate tuples representing links between tree nodes. | ||
* The resulting tuples will contain 'source' and 'target' fields, | ||
* which point to parent and child node tuples, respectively. | ||
* @constructor | ||
* @param {object} params - The parameters for this operator. | ||
* @param {function(object): *} [params.key] - Unique key field for each tuple. | ||
* If not provided, the tuple id field is used. | ||
*/ | ||
function TreeLinks(params) { | ||
vegaDataflow.Transform.call(this, {}, params); | ||
} | ||
/** | ||
* Generate tuples representing links between tree nodes. | ||
* The resulting tuples will contain 'source' and 'target' fields, | ||
* which point to parent and child node tuples, respectively. | ||
* @constructor | ||
* @param {object} params - The parameters for this operator. | ||
*/ | ||
function TreeLinks(params) { | ||
vegaDataflow.Transform.call(this, [], params); | ||
} | ||
TreeLinks.Definition = { | ||
"type": "TreeLinks", | ||
"metadata": {"tree": true, "generates": true, "changes": true}, | ||
"params": [ | ||
{ "name": "key", "type": "field" } | ||
] | ||
}; | ||
TreeLinks.Definition = { | ||
"type": "TreeLinks", | ||
"metadata": {"tree": true, "generates": true, "changes": true}, | ||
"params": [] | ||
}; | ||
var prototype$6 = vegaUtil.inherits(TreeLinks, vegaDataflow.Transform); | ||
var prototype$6 = vegaUtil.inherits(TreeLinks, vegaDataflow.Transform); | ||
function parentTuple(node) { | ||
var p; | ||
return node.parent | ||
&& (p=node.parent.data) | ||
&& (vegaDataflow.tupleid(p) != null) && p; | ||
} | ||
prototype$6.transform = function(_, pulse) { | ||
var links = this.value, | ||
tree = pulse.source && pulse.source.root, | ||
out = pulse.fork(pulse.NO_SOURCE), | ||
lut = {}; | ||
prototype$6.transform = function(_, pulse) { | ||
if (!pulse.source || !pulse.source.root) { | ||
vegaUtil.error('TreeLinks transform requires a backing tree data source.'); | ||
} | ||
if (!tree) vegaUtil.error('TreeLinks transform requires a tree data source.'); | ||
var root = pulse.source.root, | ||
nodes = root.lookup, | ||
links = this.value, | ||
key = _.key || vegaDataflow.tupleid, | ||
mods = {}, | ||
out = pulse.fork(); | ||
if (pulse.changed(pulse.ADD_REM)) { | ||
// remove previous links | ||
out.rem = links; | ||
function modify(id) { | ||
var link = links[id]; | ||
if (link) { | ||
mods[id] = 1; | ||
out.mod.push(link); | ||
} | ||
} | ||
// build lookup table of valid tuples | ||
pulse.visit(pulse.SOURCE, function(t) { lut[vegaDataflow.tupleid(t)] = 1; }); | ||
// process removed tuples | ||
// assumes that if a parent node is removed the child will be, too. | ||
pulse.visit(pulse.REM, function(t) { | ||
var id = key(t), | ||
link = links[id]; | ||
if (link) { | ||
delete links[id]; | ||
out.rem.push(link); | ||
// generate links for all edges incident on valid tuples | ||
tree.each(function(node) { | ||
var t = node.data, | ||
p = node.parent && node.parent.data; | ||
if (p && lut[vegaDataflow.tupleid(t)] && lut[vegaDataflow.tupleid(p)]) { | ||
out.add.push(vegaDataflow.ingest({source: p, target: t})); | ||
} | ||
}); | ||
this.value = out.add; | ||
} | ||
}); | ||
// create new link instances for added nodes with valid parents | ||
pulse.visit(pulse.ADD, function(t) { | ||
var id = key(t), p; | ||
if (p = parentTuple(nodes[id])) { | ||
out.add.push(links[id] = vegaDataflow.ingest({source: p, target: t})); | ||
mods[id] = 1; | ||
} | ||
}); | ||
else if (pulse.changed(pulse.MOD)) { | ||
// build lookup table of modified tuples | ||
pulse.visit(pulse.MOD, function(t) { lut[vegaDataflow.tupleid(t)] = 1; }); | ||
// process modified nodes and their children | ||
pulse.visit(pulse.MOD, function(t) { | ||
var id = key(t), | ||
node = nodes[id], | ||
kids = node.children; | ||
modify(id); | ||
if (kids) for (var i=0, n=kids.length; i<n; ++i) { | ||
if (!mods[(id=key(kids[i].data))]) modify(id); | ||
// gather links incident on modified tuples | ||
links.forEach(function(link) { | ||
if (lut[vegaDataflow.tupleid(link.source)] || lut[vegaDataflow.tupleid(link.target)]) { | ||
out.mod.push(link); | ||
} | ||
}); | ||
} | ||
}); | ||
return out; | ||
}; | ||
return out; | ||
}; | ||
var Tiles = { | ||
binary: d3Hierarchy.treemapBinary, | ||
dice: d3Hierarchy.treemapDice, | ||
slice: d3Hierarchy.treemapSlice, | ||
slicedice: d3Hierarchy.treemapSliceDice, | ||
squarify: d3Hierarchy.treemapSquarify, | ||
resquarify: d3Hierarchy.treemapResquarify | ||
}; | ||
var Tiles = { | ||
binary: d3Hierarchy.treemapBinary, | ||
dice: d3Hierarchy.treemapDice, | ||
slice: d3Hierarchy.treemapSlice, | ||
slicedice: d3Hierarchy.treemapSliceDice, | ||
squarify: d3Hierarchy.treemapSquarify, | ||
resquarify: d3Hierarchy.treemapResquarify | ||
}; | ||
var Output$3 = ["x0", "y0", "x1", "y1", "depth", "children"]; | ||
var Output$3 = ["x0", "y0", "x1", "y1", "depth", "children"]; | ||
/** | ||
* Treemap layout. | ||
* @constructor | ||
* @param {object} params - The parameters for this operator. | ||
* @param {function(object): *} params.field - The value field to size nodes. | ||
*/ | ||
function Treemap(params) { | ||
HierarchyLayout.call(this, params); | ||
} | ||
/** | ||
* Treemap layout. | ||
* @constructor | ||
* @param {object} params - The parameters for this operator. | ||
* @param {function(object): *} params.field - The value field to size nodes. | ||
*/ | ||
function Treemap(params) { | ||
HierarchyLayout.call(this, params); | ||
} | ||
Treemap.Definition = { | ||
"type": "Treemap", | ||
"metadata": {"tree": true, "modifies": true}, | ||
"params": [ | ||
{ "name": "field", "type": "field" }, | ||
{ "name": "sort", "type": "compare" }, | ||
{ "name": "method", "type": "enum", "default": "squarify", | ||
"values": ["squarify", "resquarify", "binary", "dice", "slice", "slicedice"] }, | ||
{ "name": "padding", "type": "number", "default": 0 }, | ||
{ "name": "paddingInner", "type": "number", "default": 0 }, | ||
{ "name": "paddingOuter", "type": "number", "default": 0 }, | ||
{ "name": "paddingTop", "type": "number", "default": 0 }, | ||
{ "name": "paddingRight", "type": "number", "default": 0 }, | ||
{ "name": "paddingBottom", "type": "number", "default": 0 }, | ||
{ "name": "paddingLeft", "type": "number", "default": 0 }, | ||
{ "name": "ratio", "type": "number", "default": 1.618033988749895 }, | ||
{ "name": "round", "type": "boolean", "default": false }, | ||
{ "name": "size", "type": "number", "array": true, "length": 2 }, | ||
{ "name": "as", "type": "string", "array": true, "length": 4, "default": Output$3 } | ||
] | ||
}; | ||
Treemap.Definition = { | ||
"type": "Treemap", | ||
"metadata": {"tree": true, "modifies": true}, | ||
"params": [ | ||
{ "name": "field", "type": "field" }, | ||
{ "name": "sort", "type": "compare" }, | ||
{ "name": "method", "type": "enum", "default": "squarify", | ||
"values": ["squarify", "resquarify", "binary", "dice", "slice", "slicedice"] }, | ||
{ "name": "padding", "type": "number", "default": 0 }, | ||
{ "name": "paddingInner", "type": "number", "default": 0 }, | ||
{ "name": "paddingOuter", "type": "number", "default": 0 }, | ||
{ "name": "paddingTop", "type": "number", "default": 0 }, | ||
{ "name": "paddingRight", "type": "number", "default": 0 }, | ||
{ "name": "paddingBottom", "type": "number", "default": 0 }, | ||
{ "name": "paddingLeft", "type": "number", "default": 0 }, | ||
{ "name": "ratio", "type": "number", "default": 1.618033988749895 }, | ||
{ "name": "round", "type": "boolean", "default": false }, | ||
{ "name": "size", "type": "number", "array": true, "length": 2 }, | ||
{ "name": "as", "type": "string", "array": true, "length": 4, "default": Output$3 } | ||
] | ||
}; | ||
var prototype$7 = vegaUtil.inherits(Treemap, HierarchyLayout); | ||
var prototype$7 = vegaUtil.inherits(Treemap, HierarchyLayout); | ||
/** | ||
* Treemap layout generator. Adds 'method' and 'ratio' parameters | ||
* to configure the underlying tile method. | ||
*/ | ||
prototype$7.layout = function() { | ||
var x = d3Hierarchy.treemap(); | ||
x.ratio = function(_) { | ||
var t = x.tile(); | ||
if (t.ratio) x.tile(t.ratio(_)); | ||
/** | ||
* Treemap layout generator. Adds 'method' and 'ratio' parameters | ||
* to configure the underlying tile method. | ||
*/ | ||
prototype$7.layout = function() { | ||
var x = d3Hierarchy.treemap(); | ||
x.ratio = function(_) { | ||
var t = x.tile(); | ||
if (t.ratio) x.tile(t.ratio(_)); | ||
}; | ||
x.method = function(_) { | ||
if (Tiles.hasOwnProperty(_)) x.tile(Tiles[_]); | ||
else vegaUtil.error('Unrecognized Treemap layout method: ' + _); | ||
}; | ||
return x; | ||
}; | ||
x.method = function(_) { | ||
if (Tiles.hasOwnProperty(_)) x.tile(Tiles[_]); | ||
else vegaUtil.error('Unrecognized Treemap layout method: ' + _); | ||
}; | ||
return x; | ||
}; | ||
prototype$7.params = [ | ||
'method', 'ratio', 'size', 'round', | ||
'padding', 'paddingInner', 'paddingOuter', | ||
'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft' | ||
]; | ||
prototype$7.params = [ | ||
'method', 'ratio', 'size', 'round', | ||
'padding', 'paddingInner', 'paddingOuter', | ||
'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft' | ||
]; | ||
prototype$7.fields = Output$3; | ||
prototype$7.fields = Output$3; | ||
exports.nest = Nest; | ||
exports.pack = Pack; | ||
exports.partition = Partition; | ||
exports.stratify = Stratify; | ||
exports.tree = Tree; | ||
exports.treelinks = TreeLinks; | ||
exports.treemap = Treemap; | ||
exports.nest = Nest; | ||
exports.pack = Pack; | ||
exports.partition = Partition; | ||
exports.stratify = Stratify; | ||
exports.tree = Tree; | ||
exports.treelinks = TreeLinks; | ||
exports.treemap = Treemap; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
}))); |
@@ -1,1 +0,1 @@ | ||
!function(e,a){"object"==typeof exports&&"undefined"!=typeof module?a(exports,require("vega-dataflow"),require("vega-util"),require("d3-collection"),require("d3-hierarchy")):"function"==typeof define&&define.amd?define(["exports","vega-dataflow","vega-util","d3-collection","d3-hierarchy"],a):a((e.vega=e.vega||{},e.vega.transforms=e.vega.transforms||{}),e.vega,e.vega,e.d3,e.d3)}(this,function(e,a,t,r,n){"use strict";function i(e){a.Transform.call(this,null,e)}function o(e){return e.values}function s(e){a.Transform.call(this,null,e)}function d(e,a,t){for(var r,n=0,i=a.length;n<i;++n)(r=a[n])in t&&e[r](t[r])}function u(e,a,t){for(var r=e.data,n=0,i=a.length-1;n<i;++n)r[t[n]]=e[a[n]];r[t[i]]=e.children?e.children.length:0}function l(e){s.call(this,e)}function f(e){s.call(this,e)}function m(e){a.Transform.call(this,null,e)}function p(e){s.call(this,e)}function c(e){a.Transform.call(this,{},e)}function y(e){var t;return e.parent&&(t=e.parent.data)&&null!=a.tupleid(t)&&t}function h(e){s.call(this,e)}i.Definition={type:"Nest",metadata:{treesource:!0,changes:!0},params:[{name:"keys",type:"field",array:!0},{name:"key",type:"field"},{name:"generate",type:"boolean"}]},t.inherits(i,a.Transform).transform=function(e,i){i.source||t.error("Nest transform requires an upstream data source.");var s,d,u,l=e.key||a.tupleid,f=e.generate,m=e.modified(),p=i.clone();return(!this.value||m||i.changed())&&(f&&this.value&&this.value.each(function(e){e.children&&p.rem.push(e)}),s=t.array(e.keys).reduce(function(e,a){return e.key(a),e},r.nest()).entries(p.source),this.value=d=n.hierarchy({values:s},o),f&&d.each(function(e){e.children&&(e=a.ingest(e.data),p.add.push(e),p.source.push(e))}),u=d.lookup={},d.each(function(e){null!=a.tupleid(e.data)&&(u[l(e.data)]=e)})),p.source.root=this.value,p},t.inherits(s,a.Transform).transform=function(e,a){a.source&&a.source.root||t.error(this.constructor.name+" transform requires a backing tree data source.");var r=this.layout(e.method),n=this.fields,i=a.source.root,o=e.as||n;e.field&&i.sum(e.field),e.sort&&i.sort(e.sort),d(r,this.params,e);try{this.value=r(i)}catch(e){t.error(e)}return i.each(function(e){u(e,n,o)}),a.reflow(e.modified()).modifies(o).modifies("leaf")};var g=["x","y","r","depth","children"];l.Definition={type:"Pack",metadata:{tree:!0,modifies:!0},params:[{name:"field",type:"field"},{name:"sort",type:"compare"},{name:"padding",type:"number",default:0},{name:"radius",type:"field",default:null},{name:"size",type:"number",array:!0,length:2},{name:"as",type:"string",array:!0,length:3,default:g}]};var v=t.inherits(l,s);v.layout=n.pack,v.params=["size","padding"],v.fields=g;var b=["x0","y0","x1","y1","depth","children"];f.Definition={type:"Partition",metadata:{tree:!0,modifies:!0},params:[{name:"field",type:"field"},{name:"sort",type:"compare"},{name:"padding",type:"number",default:0},{name:"round",type:"boolean",default:!1},{name:"size",type:"number",array:!0,length:2},{name:"as",type:"string",array:!0,length:4,default:b}]};var k=t.inherits(f,s);k.layout=n.partition,k.params=["size","round","padding"],k.fields=b,m.Definition={type:"Stratify",metadata:{treesource:!0},params:[{name:"key",type:"field",required:!0},{name:"parentKey",type:"field",required:!0}]},t.inherits(m,a.Transform).transform=function(e,a){a.source||t.error("Stratify transform requires an upstream data source.");var r,i,o=e.modified(),s=a.fork(a.ALL).materialize(a.SOURCE),d=!this.value||o||a.changed(a.ADD_REM)||a.modified(e.key.fields)||a.modified(e.parentKey.fields);return s.source=s.source.slice(),d&&(r=n.stratify().id(e.key).parentId(e.parentKey)(s.source),i=r.lookup={},r.each(function(a){i[e.key(a.data)]=a}),this.value=r),s.source.root=this.value,s};var q={tidy:n.tree,cluster:n.cluster},T=["x","y","depth","children"];p.Definition={type:"Tree",metadata:{tree:!0,modifies:!0},params:[{name:"field",type:"field"},{name:"sort",type:"compare"},{name:"method",type:"enum",default:"tidy",values:["tidy","cluster"]},{name:"size",type:"number",array:!0,length:2},{name:"nodeSize",type:"number",array:!0,length:2},{name:"as",type:"string",array:!0,length:4,default:T}]};var D=t.inherits(p,s);D.layout=function(e){var a=e||"tidy";if(q.hasOwnProperty(a))return q[a]();t.error("Unrecognized Tree layout method: "+a)},D.params=["size","nodeSize","separation"],D.fields=T,c.Definition={type:"TreeLinks",metadata:{tree:!0,generates:!0,changes:!0},params:[{name:"key",type:"field"}]},t.inherits(c,a.Transform).transform=function(e,r){function n(e){var a=o[e];a&&(d[e]=1,u.mod.push(a))}r.source&&r.source.root||t.error("TreeLinks transform requires a backing tree data source.");var i=r.source.root.lookup,o=this.value,s=e.key||a.tupleid,d={},u=r.fork();return r.visit(r.REM,function(e){var a=s(e),t=o[a];t&&(delete o[a],u.rem.push(t))}),r.visit(r.ADD,function(e){var t,r=s(e);(t=y(i[r]))&&(u.add.push(o[r]=a.ingest({source:t,target:e})),d[r]=1)}),r.visit(r.MOD,function(e){var a=s(e),t=i[a].children;if(n(a),t)for(var r=0,o=t.length;r<o;++r)d[a=s(t[r].data)]||n(a)}),u};var z={binary:n.treemapBinary,dice:n.treemapDice,slice:n.treemapSlice,slicedice:n.treemapSliceDice,squarify:n.treemapSquarify,resquarify:n.treemapResquarify},x=["x0","y0","x1","y1","depth","children"];h.Definition={type:"Treemap",metadata:{tree:!0,modifies:!0},params:[{name:"field",type:"field"},{name:"sort",type:"compare"},{name:"method",type:"enum",default:"squarify",values:["squarify","resquarify","binary","dice","slice","slicedice"]},{name:"padding",type:"number",default:0},{name:"paddingInner",type:"number",default:0},{name:"paddingOuter",type:"number",default:0},{name:"paddingTop",type:"number",default:0},{name:"paddingRight",type:"number",default:0},{name:"paddingBottom",type:"number",default:0},{name:"paddingLeft",type:"number",default:0},{name:"ratio",type:"number",default:1.618033988749895},{name:"round",type:"boolean",default:!1},{name:"size",type:"number",array:!0,length:2},{name:"as",type:"string",array:!0,length:4,default:x}]};var S=t.inherits(h,s);S.layout=function(){var e=n.treemap();return e.ratio=function(a){var t=e.tile();t.ratio&&e.tile(t.ratio(a))},e.method=function(a){z.hasOwnProperty(a)?e.tile(z[a]):t.error("Unrecognized Treemap layout method: "+a)},e},S.params=["method","ratio","size","round","padding","paddingInner","paddingOuter","paddingTop","paddingRight","paddingBottom","paddingLeft"],S.fields=x,e.nest=i,e.pack=l,e.partition=f,e.stratify=m,e.tree=p,e.treelinks=c,e.treemap=h,Object.defineProperty(e,"__esModule",{value:!0})}); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("vega-dataflow"),require("vega-util"),require("d3-collection"),require("d3-hierarchy")):"function"==typeof define&&define.amd?define(["exports","vega-dataflow","vega-util","d3-collection","d3-hierarchy"],t):t((e.vega=e.vega||{},e.vega.transforms={}),e.vega,e.vega,e.d3,e.d3)}(this,function(e,o,d,s,u){"use strict";function l(e,a,r){var n={};return e.each(function(e){var t=e.data;r(t)&&(n[a(t)]=e)}),e.lookup=n,e}function t(e){o.Transform.call(this,null,e)}function f(e){return e.values}function a(e){o.Transform.call(this,null,e)}t.Definition={type:"Nest",metadata:{treesource:!0,changes:!0},params:[{name:"keys",type:"field",array:!0},{name:"generate",type:"boolean"}]},d.inherits(t,o.Transform).transform=function(e,t){t.source||d.error("Nest transform requires an upstream data source.");var a=e.generate,r=e.modified(),n=t.clone(),i=this.value;return(!i||r||t.changed())&&(i&&i.each(function(e){e.children&&o.isTuple(e.data)&&n.rem.push(e.data)}),this.value=i=u.hierarchy({values:d.array(e.keys).reduce(function(e,t){return e.key(t),e},s.nest()).entries(n.source)},f),a&&i.each(function(e){e.children&&(e=o.ingest(e.data),n.add.push(e),n.source.push(e))}),l(i,o.tupleid,o.tupleid)),n.source.root=i,n},d.inherits(a,o.Transform).transform=function(e,t){t.source&&t.source.root||d.error(this.constructor.name+" transform requires a backing tree data source.");var a=this.layout(e.method),r=this.fields,n=t.source.root,i=e.as||r;e.field&&n.sum(e.field),e.sort&&n.sort(e.sort),function(e,t,a){for(var r,n=0,i=t.length;n<i;++n)(r=t[n])in a&&e[r](a[r])}(a,this.params,e);try{this.value=a(n)}catch(e){d.error(e)}return n.each(function(e){!function(e,t,a){for(var r=e.data,n=0,i=t.length-1;n<i;++n)r[a[n]]=e[t[n]];r[a[i]]=e.children?e.children.length:0}(e,r,i)}),t.reflow(e.modified()).modifies(i).modifies("leaf")};var r=["x","y","r","depth","children"];function n(e){a.call(this,e)}n.Definition={type:"Pack",metadata:{tree:!0,modifies:!0},params:[{name:"field",type:"field"},{name:"sort",type:"compare"},{name:"padding",type:"number",default:0},{name:"radius",type:"field",default:null},{name:"size",type:"number",array:!0,length:2},{name:"as",type:"string",array:!0,length:3,default:r}]};var i=d.inherits(n,a);i.layout=u.pack,i.params=["size","padding"],i.fields=r;var m=["x0","y0","x1","y1","depth","children"];function p(e){a.call(this,e)}p.Definition={type:"Partition",metadata:{tree:!0,modifies:!0},params:[{name:"field",type:"field"},{name:"sort",type:"compare"},{name:"padding",type:"number",default:0},{name:"round",type:"boolean",default:!1},{name:"size",type:"number",array:!0,length:2},{name:"as",type:"string",array:!0,length:4,default:m}]};var c=d.inherits(p,a);function y(e){o.Transform.call(this,null,e)}c.layout=u.partition,c.params=["size","round","padding"],c.fields=m,y.Definition={type:"Stratify",metadata:{treesource:!0},params:[{name:"key",type:"field",required:!0},{name:"parentKey",type:"field",required:!0}]},d.inherits(y,o.Transform).transform=function(e,t){t.source||d.error("Stratify transform requires an upstream data source.");var a=e.modified(),r=t.fork(t.ALL).materialize(t.SOURCE),n=!this.value||a||t.changed(t.ADD_REM)||t.modified(e.key.fields)||t.modified(e.parentKey.fields);return r.source=r.source.slice(),n&&(this.value=l(u.stratify().id(e.key).parentId(e.parentKey)(r.source),e.key,d.truthy)),r.source.root=this.value,r};var h={tidy:u.tree,cluster:u.cluster},g=["x","y","depth","children"];function v(e){a.call(this,e)}v.Definition={type:"Tree",metadata:{tree:!0,modifies:!0},params:[{name:"field",type:"field"},{name:"sort",type:"compare"},{name:"method",type:"enum",default:"tidy",values:["tidy","cluster"]},{name:"size",type:"number",array:!0,length:2},{name:"nodeSize",type:"number",array:!0,length:2},{name:"as",type:"string",array:!0,length:4,default:g}]};var b=d.inherits(v,a);function k(e){o.Transform.call(this,[],e)}b.layout=function(e){var t=e||"tidy";if(h.hasOwnProperty(t))return h[t]();d.error("Unrecognized Tree layout method: "+t)},b.params=["size","nodeSize","separation"],b.fields=g,k.Definition={type:"TreeLinks",metadata:{tree:!0,generates:!0,changes:!0},params:[]},d.inherits(k,o.Transform).transform=function(e,t){var a=this.value,r=t.source&&t.source.root,n=t.fork(t.NO_SOURCE),i={};return r||d.error("TreeLinks transform requires a tree data source."),t.changed(t.ADD_REM)?(n.rem=a,t.visit(t.SOURCE,function(e){i[o.tupleid(e)]=1}),r.each(function(e){var t=e.data,a=e.parent&&e.parent.data;a&&i[o.tupleid(t)]&&i[o.tupleid(a)]&&n.add.push(o.ingest({source:a,target:t}))}),this.value=n.add):t.changed(t.MOD)&&(t.visit(t.MOD,function(e){i[o.tupleid(e)]=1}),a.forEach(function(e){(i[o.tupleid(e.source)]||i[o.tupleid(e.target)])&&n.mod.push(e)})),n};var q={binary:u.treemapBinary,dice:u.treemapDice,slice:u.treemapSlice,slicedice:u.treemapSliceDice,squarify:u.treemapSquarify,resquarify:u.treemapResquarify},T=["x0","y0","x1","y1","depth","children"];function D(e){a.call(this,e)}D.Definition={type:"Treemap",metadata:{tree:!0,modifies:!0},params:[{name:"field",type:"field"},{name:"sort",type:"compare"},{name:"method",type:"enum",default:"squarify",values:["squarify","resquarify","binary","dice","slice","slicedice"]},{name:"padding",type:"number",default:0},{name:"paddingInner",type:"number",default:0},{name:"paddingOuter",type:"number",default:0},{name:"paddingTop",type:"number",default:0},{name:"paddingRight",type:"number",default:0},{name:"paddingBottom",type:"number",default:0},{name:"paddingLeft",type:"number",default:0},{name:"ratio",type:"number",default:1.618033988749895},{name:"round",type:"boolean",default:!1},{name:"size",type:"number",array:!0,length:2},{name:"as",type:"string",array:!0,length:4,default:T}]};var z=d.inherits(D,a);z.layout=function(){var a=u.treemap();return a.ratio=function(e){var t=a.tile();t.ratio&&a.tile(t.ratio(e))},a.method=function(e){q.hasOwnProperty(e)?a.tile(q[e]):d.error("Unrecognized Treemap layout method: "+e)},a},z.params=["method","ratio","size","round","padding","paddingInner","paddingOuter","paddingTop","paddingRight","paddingBottom","paddingLeft"],z.fields=T,e.nest=t,e.pack=n,e.partition=p,e.stratify=y,e.tree=v,e.treelinks=k,e.treemap=D,Object.defineProperty(e,"__esModule",{value:!0})}); |
{ | ||
"name": "vega-hierarchy", | ||
"version": "2.1.2", | ||
"version": "3.0.0", | ||
"description": "Hierarchical layout transforms for Vega dataflows.", | ||
@@ -34,13 +34,14 @@ "keywords": [ | ||
"dependencies": { | ||
"d3-collection": "1", | ||
"d3-hierarchy": "1", | ||
"vega-dataflow": "^3.1", | ||
"vega-util": "1" | ||
"d3-collection": "^1.0.4", | ||
"d3-hierarchy": "^1.1.6", | ||
"vega-dataflow": "^4.0.0", | ||
"vega-util": "^1.7.0" | ||
}, | ||
"devDependencies": { | ||
"eslint": "4", | ||
"rollup": "0.43", | ||
"rollup": "0.58.2", | ||
"tape": "4", | ||
"uglify-js": "3" | ||
"uglify-js": "3", | ||
"vega-transforms": "^2.0.0" | ||
} | ||
} |
@@ -1,2 +0,3 @@ | ||
import {ingest, Transform, tupleid} from 'vega-dataflow'; | ||
import lookup from './lookup'; | ||
import {ingest, isTuple, Transform, tupleid} from 'vega-dataflow'; | ||
import {array, error, inherits} from 'vega-util'; | ||
@@ -11,4 +12,2 @@ import {nest} from 'd3-collection'; | ||
* @param {Array<function(object): *>} params.keys - The key fields to nest by, in order. | ||
* @param {function(object): *} [params.key] - Unique key field for each tuple. | ||
* If not provided, the tuple id field is used. | ||
* @param {boolean} [params.generate=false] - A boolean flag indicating if | ||
@@ -28,3 +27,2 @@ * non-leaf nodes generated by this transform should be included in the | ||
{ "name": "keys", "type": "field", "array": true }, | ||
{ "name": "key", "type": "field" }, | ||
{ "name": "generate", "type": "boolean" } | ||
@@ -45,13 +43,14 @@ ] | ||
var key = _.key || tupleid, | ||
gen = _.generate, | ||
var gen = _.generate, | ||
mod = _.modified(), | ||
out = pulse.clone(), | ||
root, tree, map; | ||
tree = this.value; | ||
if (!this.value || mod || pulse.changed()) { | ||
if (!tree || mod || pulse.changed()) { | ||
// collect nodes to remove | ||
if (gen && this.value) { | ||
this.value.each(function(node) { | ||
if (node.children) out.rem.push(node); | ||
if (tree) { | ||
tree.each(function(node) { | ||
if (node.children && isTuple(node.data)) { | ||
out.rem.push(node.data); | ||
} | ||
}); | ||
@@ -61,6 +60,7 @@ } | ||
// generate new tree structure | ||
root = array(_.keys) | ||
.reduce(function(n, k) { n.key(k); return n; }, nest()) | ||
.entries(out.source); | ||
this.value = tree = hierarchy({values: root}, children); | ||
this.value = tree = hierarchy({ | ||
values: array(_.keys) | ||
.reduce(function(n, k) { n.key(k); return n; }, nest()) | ||
.entries(out.source) | ||
}, children); | ||
@@ -79,12 +79,7 @@ // collect nodes to add | ||
// build lookup table | ||
map = tree.lookup = {}; | ||
tree.each(function(node) { | ||
if (tupleid(node.data) != null) { | ||
map[key(node.data)] = node; | ||
} | ||
}); | ||
lookup(tree, tupleid, tupleid); | ||
} | ||
out.source.root = this.value; | ||
out.source.root = tree; | ||
return out; | ||
}; |
@@ -0,3 +1,4 @@ | ||
import lookup from './lookup'; | ||
import {Transform} from 'vega-dataflow'; | ||
import {error, inherits} from 'vega-util'; | ||
import {error, inherits, truthy} from 'vega-util'; | ||
import {stratify} from 'd3-hierarchy'; | ||
@@ -33,3 +34,3 @@ | ||
var mod = _.modified(), tree, map, | ||
var mod = _.modified(), | ||
out = pulse.fork(pulse.ALL).materialize(pulse.SOURCE), | ||
@@ -46,6 +47,6 @@ run = !this.value | ||
if (run) { | ||
tree = stratify().id(_.key).parentId(_.parentKey)(out.source); | ||
map = tree.lookup = {}; | ||
tree.each(function(node) { map[_.key(node.data)] = node; }); | ||
this.value = tree; | ||
this.value = lookup( | ||
stratify().id(_.key).parentId(_.parentKey)(out.source), | ||
_.key, truthy | ||
); | ||
} | ||
@@ -52,0 +53,0 @@ |
@@ -1,2 +0,2 @@ | ||
import {Transform, tupleid, ingest} from 'vega-dataflow'; | ||
import {ingest, tupleid, Transform} from 'vega-dataflow'; | ||
import {error, inherits} from 'vega-util'; | ||
@@ -10,7 +10,5 @@ | ||
* @param {object} params - The parameters for this operator. | ||
* @param {function(object): *} [params.key] - Unique key field for each tuple. | ||
* If not provided, the tuple id field is used. | ||
*/ | ||
export default function TreeLinks(params) { | ||
Transform.call(this, {}, params); | ||
Transform.call(this, [], params); | ||
} | ||
@@ -21,5 +19,3 @@ | ||
"metadata": {"tree": true, "generates": true, "changes": true}, | ||
"params": [ | ||
{ "name": "key", "type": "field" } | ||
] | ||
"params": [] | ||
}; | ||
@@ -29,62 +25,41 @@ | ||
function parentTuple(node) { | ||
var p; | ||
return node.parent | ||
&& (p=node.parent.data) | ||
&& (tupleid(p) != null) && p; | ||
} | ||
prototype.transform = function(_, pulse) { | ||
if (!pulse.source || !pulse.source.root) { | ||
error('TreeLinks transform requires a backing tree data source.'); | ||
} | ||
var links = this.value, | ||
tree = pulse.source && pulse.source.root, | ||
out = pulse.fork(pulse.NO_SOURCE), | ||
lut = {}; | ||
var root = pulse.source.root, | ||
nodes = root.lookup, | ||
links = this.value, | ||
key = _.key || tupleid, | ||
mods = {}, | ||
out = pulse.fork(); | ||
if (!tree) error('TreeLinks transform requires a tree data source.'); | ||
function modify(id) { | ||
var link = links[id]; | ||
if (link) { | ||
mods[id] = 1; | ||
out.mod.push(link); | ||
} | ||
} | ||
if (pulse.changed(pulse.ADD_REM)) { | ||
// remove previous links | ||
out.rem = links; | ||
// process removed tuples | ||
// assumes that if a parent node is removed the child will be, too. | ||
pulse.visit(pulse.REM, function(t) { | ||
var id = key(t), | ||
link = links[id]; | ||
if (link) { | ||
delete links[id]; | ||
out.rem.push(link); | ||
} | ||
}); | ||
// build lookup table of valid tuples | ||
pulse.visit(pulse.SOURCE, function(t) { lut[tupleid(t)] = 1; }); | ||
// create new link instances for added nodes with valid parents | ||
pulse.visit(pulse.ADD, function(t) { | ||
var id = key(t), p; | ||
if (p = parentTuple(nodes[id])) { | ||
out.add.push(links[id] = ingest({source: p, target: t})); | ||
mods[id] = 1; | ||
} | ||
}); | ||
// generate links for all edges incident on valid tuples | ||
tree.each(function(node) { | ||
var t = node.data, | ||
p = node.parent && node.parent.data; | ||
if (p && lut[tupleid(t)] && lut[tupleid(p)]) { | ||
out.add.push(ingest({source: p, target: t})); | ||
} | ||
}); | ||
this.value = out.add; | ||
} | ||
// process modified nodes and their children | ||
pulse.visit(pulse.MOD, function(t) { | ||
var id = key(t), | ||
node = nodes[id], | ||
kids = node.children; | ||
else if (pulse.changed(pulse.MOD)) { | ||
// build lookup table of modified tuples | ||
pulse.visit(pulse.MOD, function(t) { lut[tupleid(t)] = 1; }); | ||
modify(id); | ||
if (kids) for (var i=0, n=kids.length; i<n; ++i) { | ||
if (!mods[(id=key(kids[i].data))]) modify(id); | ||
} | ||
}); | ||
// gather links incident on modified tuples | ||
links.forEach(function(link) { | ||
if (lut[tupleid(link.source)] || lut[tupleid(link.target)]) { | ||
out.mod.push(link); | ||
} | ||
}); | ||
} | ||
return out; | ||
}; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
16
38079
5
770
+ Addednode-fetch@2.7.0(transitive)
+ Addedtr46@0.0.3(transitive)
+ Addedvega-dataflow@4.1.0(transitive)
+ Addedvega-loader@3.1.0(transitive)
+ Addedwebidl-conversions@3.0.1(transitive)
+ Addedwhatwg-url@5.0.0(transitive)
- Removedd3-dispatch@1.0.6(transitive)
- Removedd3-request@1.0.6(transitive)
- Removedvega-dataflow@3.1.0(transitive)
- Removedvega-loader@2.1.0(transitive)
- Removedxmlhttprequest@1.8.0(transitive)
Updatedd3-collection@^1.0.4
Updatedd3-hierarchy@^1.1.6
Updatedvega-dataflow@^4.0.0
Updatedvega-util@^1.7.0