d3-state-visualizer
Advanced tools
Comparing version 1.3.1 to 1.3.2
@@ -23,13 +23,7 @@ 'use strict'; | ||
if (obj && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object') { | ||
var _ret = function () { | ||
var tObj = {}; | ||
Object.keys(obj).sort().forEach(function (key) { | ||
return tObj[key] = sortObject(obj[key]); | ||
}); | ||
return { | ||
v: tObj | ||
}; | ||
}(); | ||
if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v; | ||
var tObj = {}; | ||
Object.keys(obj).sort().forEach(function (key) { | ||
return tObj[key] = sortObject(obj[key]); | ||
}); | ||
return tObj; | ||
} | ||
@@ -36,0 +30,0 @@ |
@@ -10,22 +10,21 @@ 'use strict'; | ||
var _deepmerge = (0, _deepmerge3.default)(defaultOptions, options); | ||
var _deepmerge = (0, _deepmerge3.default)(defaultOptions, options), | ||
id = _deepmerge.id, | ||
style = _deepmerge.style, | ||
size = _deepmerge.size, | ||
aspectRatio = _deepmerge.aspectRatio, | ||
initialZoom = _deepmerge.initialZoom, | ||
margin = _deepmerge.margin, | ||
isSorted = _deepmerge.isSorted, | ||
widthBetweenNodesCoeff = _deepmerge.widthBetweenNodesCoeff, | ||
heightBetweenNodesCoeff = _deepmerge.heightBetweenNodesCoeff, | ||
transitionDuration = _deepmerge.transitionDuration, | ||
blinkDuration = _deepmerge.blinkDuration, | ||
state = _deepmerge.state, | ||
rootKeyName = _deepmerge.rootKeyName, | ||
pushMethod = _deepmerge.pushMethod, | ||
tree = _deepmerge.tree, | ||
tooltipOptions = _deepmerge.tooltipOptions, | ||
onClickText = _deepmerge.onClickText; | ||
var id = _deepmerge.id; | ||
var style = _deepmerge.style; | ||
var size = _deepmerge.size; | ||
var aspectRatio = _deepmerge.aspectRatio; | ||
var initialZoom = _deepmerge.initialZoom; | ||
var margin = _deepmerge.margin; | ||
var isSorted = _deepmerge.isSorted; | ||
var widthBetweenNodesCoeff = _deepmerge.widthBetweenNodesCoeff; | ||
var heightBetweenNodesCoeff = _deepmerge.heightBetweenNodesCoeff; | ||
var transitionDuration = _deepmerge.transitionDuration; | ||
var state = _deepmerge.state; | ||
var rootKeyName = _deepmerge.rootKeyName; | ||
var pushMethod = _deepmerge.pushMethod; | ||
var tree = _deepmerge.tree; | ||
var tooltipOptions = _deepmerge.tooltipOptions; | ||
var onClickText = _deepmerge.onClickText; | ||
var width = size - margin.left - margin.right; | ||
@@ -52,5 +51,5 @@ var height = size * aspectRatio - margin.top - margin.bottom; | ||
var vis = root.append('svg').attr(attr).style(_extends({ cursor: '-webkit-grab' }, style)).call(zoom.on('zoom', function () { | ||
var _d3$event = _d4.default.event; | ||
var translate = _d3$event.translate; | ||
var scale = _d3$event.scale; | ||
var _d3$event = _d4.default.event, | ||
translate = _d3$event.translate, | ||
scale = _d3$event.scale; | ||
@@ -71,2 +70,29 @@ vis.attr('transform', 'translate(' + translate + ')scale(' + scale + ')'); | ||
// previousNodePositionsById stores node x and y | ||
// as well as hierarchy (id / parentId); | ||
// helps animating transitions | ||
var previousNodePositionsById = { | ||
root: { | ||
id: 'root', | ||
parentId: null, | ||
x: height / 2, | ||
y: 0 | ||
} | ||
// traverses a map with node positions by going through the chain | ||
// of parent ids; once a parent that matches the given filter is found, | ||
// the parent position gets returned | ||
};function findParentNodePosition(nodePositionsById, nodeId, filter) { | ||
var currentPosition = nodePositionsById[nodeId]; | ||
while (currentPosition) { | ||
currentPosition = nodePositionsById[currentPosition.parentId]; | ||
if (!currentPosition) { | ||
return null; | ||
} | ||
if (!filter || filter(currentPosition)) { | ||
return currentPosition; | ||
} | ||
} | ||
} | ||
return function renderChart() { | ||
@@ -84,15 +110,20 @@ var nextState = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : tree || state; | ||
// nodes are assigned with string ids, which reflect their location | ||
// within the hierarcy; e.g. "root|branch|subBranch|subBranch[0]|property" | ||
// top-level elemnt always has id "root" | ||
(0, _utils.visit)(data, function (node) { | ||
return maxLabelLength = Math.max(node.name.length, maxLabelLength); | ||
maxLabelLength = Math.max(node.name.length, maxLabelLength); | ||
node.id = node.id || 'root'; | ||
}, function (node) { | ||
return node.children && node.children.length > 0 ? node.children : null; | ||
return node.children && node.children.length > 0 ? node.children.map(function (c) { | ||
c.id = (node.id || '') + '|' + c.name; | ||
return c; | ||
}) : null; | ||
}); | ||
data.x0 = height / 2; | ||
data.y0 = 0; | ||
/*eslint-disable*/ | ||
update(data); | ||
update(); | ||
/*eslint-enable*/ | ||
function update(source) { | ||
function update() { | ||
// path generator for links | ||
@@ -114,2 +145,15 @@ var diagonal = _d4.default.svg.diagonal().projection(function (d) { | ||
var nodePositions = nodes.map(function (n) { | ||
return { | ||
parentId: n.parent && n.parent.id, | ||
id: n.id, | ||
x: n.x, | ||
y: n.y | ||
}; | ||
}); | ||
var nodePositionsById = {}; | ||
nodePositions.forEach(function (node) { | ||
return nodePositionsById[node.id] = node; | ||
}); | ||
// process the node selection | ||
@@ -121,7 +165,10 @@ var node = vis.selectAll('g.node').property('__oldData__', function (d) { | ||
}); | ||
var nodeEnter = node.enter().append('g').attr({ | ||
'class': 'node', | ||
transform: function transform(d) { | ||
return 'translate(' + source.y0 + ',' + source.x0 + ')'; | ||
var position = findParentNodePosition(nodePositionsById, d.id, function (n) { | ||
return previousNodePositionsById[n.id]; | ||
}); | ||
var previousPosition = position && previousNodePositionsById[position.id] || previousNodePositionsById.root; | ||
return 'translate(' + previousPosition.y + ',' + previousPosition.x + ')'; | ||
} | ||
@@ -132,3 +179,3 @@ }).style({ | ||
}).on({ | ||
mouseover: function mouseover(d, i) { | ||
mouseover: function mouseover() { | ||
_d4.default.select(this).style({ | ||
@@ -138,3 +185,3 @@ fill: style.text.colors.hover | ||
}, | ||
mouseout: function mouseout(d, i) { | ||
mouseout: function mouseout() { | ||
_d4.default.select(this).style({ | ||
@@ -152,13 +199,20 @@ fill: style.text.colors.default | ||
nodeEnter.append('circle').attr({ | ||
'class': 'nodeCircle' | ||
// g inside node contains circle and text | ||
// this extra wrapper helps run d3 transitions in parallel | ||
var nodeEnterInnerGroup = nodeEnter.append('g'); | ||
nodeEnterInnerGroup.append('circle').attr({ | ||
'class': 'nodeCircle', | ||
r: 0 | ||
}).on({ | ||
click: function click(clickedNode) { | ||
if (_d4.default.event.defaultPrevented) return; | ||
update((0, _utils.toggleChildren)(clickedNode)); | ||
(0, _utils.toggleChildren)(clickedNode); | ||
update(); | ||
} | ||
}); | ||
nodeEnter.append('text').attr({ | ||
nodeEnterInnerGroup.append('text').attr({ | ||
'class': 'nodeText', | ||
'text-anchor': 'middle', | ||
'transform': 'translate(0,0)', | ||
dy: '.35em' | ||
@@ -174,10 +228,3 @@ }).style({ | ||
// update the text to reflect whether node has children or not | ||
node.select('text').attr({ | ||
x: function x(d) { | ||
return d.children || d._children ? -(style.node.radius + 10) : style.node.radius + 10; | ||
}, | ||
'text-anchor': function textAnchor(d) { | ||
return d.children || d._children ? 'end' : 'start'; | ||
} | ||
}).text(function (d) { | ||
node.select('text').text(function (d) { | ||
return d.name; | ||
@@ -187,5 +234,3 @@ }); | ||
// change the circle fill depending on whether it has children and is collapsed | ||
node.select('circle.nodeCircle').attr({ | ||
r: style.node.radius | ||
}).style({ | ||
node.select('circle').style({ | ||
stroke: 'black', | ||
@@ -205,10 +250,15 @@ 'stroke-width': '1.5px', | ||
// fade the text in | ||
nodeUpdate.select('text').style('fill-opacity', 1); | ||
// ensure circle radius is correct | ||
nodeUpdate.select('circle').attr('r', style.node.radius); | ||
// restore the circle | ||
nodeUpdate.select('circle').attr('r', 7); | ||
// fade the text in and align it | ||
nodeUpdate.select('text').style('fill-opacity', 1).attr({ | ||
transform: function transform(d) { | ||
var x = (d.children || d._children ? -1 : 1) * (this.getBBox().width / 2 + style.node.radius + 5); | ||
return 'translate(' + x + ',0)'; | ||
} | ||
}); | ||
// blink updated nodes | ||
nodeUpdate.filter(function flick(d) { | ||
node.filter(function flick(d) { | ||
// test whether the relevant properties of d match | ||
@@ -218,4 +268,4 @@ // the equivalent property of the oldData | ||
// to catch the entering elements! | ||
return !this.__oldData__ || d.value !== this.__oldData__.value; | ||
}).style('fill-opacity', '0.3').transition().duration(100).style('fill-opacity', '1'); | ||
return this.__oldData__ && d.value !== this.__oldData__.value; | ||
}).select('g').style('opacity', '0.3').transition().duration(blinkDuration).style('opacity', '1'); | ||
@@ -225,3 +275,7 @@ // transition exiting nodes to the parent's new position | ||
transform: function transform(d) { | ||
return 'translate(' + source.y + ',' + source.x + ')'; | ||
var position = findParentNodePosition(previousNodePositionsById, d.id, function (n) { | ||
return nodePositionsById[n.id]; | ||
}); | ||
var futurePosition = position && nodePositionsById[position.id] || nodePositionsById.root; | ||
return 'translate(' + futurePosition.y + ',' + futurePosition.x + ')'; | ||
} | ||
@@ -243,9 +297,9 @@ }).remove(); | ||
d: function d(_d) { | ||
var o = { | ||
x: source.x0, | ||
y: source.y0 | ||
}; | ||
var position = findParentNodePosition(nodePositionsById, _d.target.id, function (n) { | ||
return previousNodePositionsById[n.id]; | ||
}); | ||
var previousPosition = position && previousNodePositionsById[position.id] || previousNodePositionsById.root; | ||
return diagonal({ | ||
source: o, | ||
target: o | ||
source: previousPosition, | ||
target: previousPosition | ||
}); | ||
@@ -263,9 +317,9 @@ } | ||
d: function d(_d2) { | ||
var o = { | ||
x: source.x, | ||
y: source.y | ||
}; | ||
var position = findParentNodePosition(previousNodePositionsById, _d2.target.id, function (n) { | ||
return nodePositionsById[n.id]; | ||
}); | ||
var futurePosition = position && nodePositionsById[position.id] || nodePositionsById.root; | ||
return diagonal({ | ||
source: o, | ||
target: o | ||
source: futurePosition, | ||
target: futurePosition | ||
}); | ||
@@ -279,6 +333,3 @@ } | ||
// stash the old positions for transition | ||
nodes.forEach(function (d) { | ||
d.x0 = d.x; | ||
d.y0 = d.y; | ||
}); | ||
previousNodePositionsById = nodePositionsById; | ||
} | ||
@@ -323,3 +374,3 @@ }; | ||
}, | ||
radius: 5 | ||
radius: 7 | ||
}, | ||
@@ -350,2 +401,3 @@ text: { | ||
transitionDuration: 750, | ||
blinkDuration: 100, | ||
onClickText: function onClickText() {}, | ||
@@ -352,0 +404,0 @@ tooltipOptions: { |
@@ -89,4 +89,4 @@ 'use strict'; | ||
function getTooltipString(node, i, _ref) { | ||
var _ref$indentationSize = _ref.indentationSize; | ||
var indentationSize = _ref$indentationSize === undefined ? 4 : _ref$indentationSize; | ||
var _ref$indentationSize = _ref.indentationSize, | ||
indentationSize = _ref$indentationSize === undefined ? 4 : _ref$indentationSize; | ||
@@ -93,0 +93,0 @@ if (!(0, _ramda.is)(Object, node)) return ''; |
{ | ||
"name": "d3-state-visualizer", | ||
"version": "1.3.1", | ||
"version": "1.3.2", | ||
"description": "Visualize your app state with a range of reusable charts", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
@@ -5,3 +5,3 @@ d3-state-visualizer | ||
[Demo](http://romseguy.github.io/d3-state-visualizer) | ||
[Demo](http://reduxjs.github.io/d3-state-visualizer) | ||
@@ -8,0 +8,0 @@ ## Installation |
@@ -21,3 +21,3 @@ import d3 from 'd3' | ||
}, | ||
radius: 5 | ||
radius: 7 | ||
}, | ||
@@ -48,2 +48,3 @@ text: { | ||
transitionDuration: 750, | ||
blinkDuration: 100, | ||
onClickText: () => {}, | ||
@@ -74,2 +75,3 @@ tooltipOptions: { | ||
transitionDuration, | ||
blinkDuration, | ||
state, | ||
@@ -125,2 +127,30 @@ rootKeyName, | ||
// previousNodePositionsById stores node x and y | ||
// as well as hierarchy (id / parentId); | ||
// helps animating transitions | ||
let previousNodePositionsById = { | ||
root: { | ||
id: 'root', | ||
parentId: null, | ||
x: height / 2, | ||
y: 0 | ||
} | ||
} | ||
// traverses a map with node positions by going through the chain | ||
// of parent ids; once a parent that matches the given filter is found, | ||
// the parent position gets returned | ||
function findParentNodePosition(nodePositionsById, nodeId, filter) { | ||
let currentPosition = nodePositionsById[nodeId] | ||
while (currentPosition) { | ||
currentPosition = nodePositionsById[currentPosition.parentId] | ||
if (!currentPosition) { | ||
return null | ||
} | ||
if (!filter || filter(currentPosition)) { | ||
return currentPosition | ||
} | ||
} | ||
} | ||
return function renderChart(nextState = tree || state) { | ||
@@ -136,14 +166,21 @@ data = !tree ? map2tree(nextState, {key: rootKeyName, pushMethod}) : nextState | ||
// nodes are assigned with string ids, which reflect their location | ||
// within the hierarcy; e.g. "root|branch|subBranch|subBranch[0]|property" | ||
// top-level elemnt always has id "root" | ||
visit(data, | ||
node => maxLabelLength = Math.max(node.name.length, maxLabelLength), | ||
node => node.children && node.children.length > 0 ? node.children : null | ||
node => { | ||
maxLabelLength = Math.max(node.name.length, maxLabelLength) | ||
node.id = node.id || 'root' | ||
}, | ||
node => node.children && node.children.length > 0 ? node.children.map((c) => { | ||
c.id = `${node.id || ''}|${c.name}` | ||
return c | ||
}) : null | ||
) | ||
data.x0 = height / 2 | ||
data.y0 = 0 | ||
/*eslint-disable*/ | ||
update(data) | ||
update() | ||
/*eslint-enable*/ | ||
function update(source) { | ||
function update() { | ||
// path generator for links | ||
@@ -161,2 +198,11 @@ const diagonal = d3.svg.diagonal().projection(d => [d.y, d.x]) | ||
const nodePositions = nodes.map(n => ({ | ||
parentId: n.parent && n.parent.id, | ||
id: n.id, | ||
x: n.x, | ||
y: n.y | ||
})) | ||
const nodePositionsById = {} | ||
nodePositions.forEach(node => nodePositionsById[node.id] = node) | ||
// process the node selection | ||
@@ -166,7 +212,10 @@ let node = vis.selectAll('g.node') | ||
.data(nodes, d => d.id || (d.id = ++nodeIndex)) | ||
let nodeEnter = node.enter().append('g') | ||
.attr({ | ||
'class': 'node', | ||
transform: d => `translate(${source.y0},${source.x0})` | ||
transform: d => { | ||
const position = findParentNodePosition(nodePositionsById, d.id, (n) => previousNodePositionsById[n.id]) | ||
const previousPosition = position && previousNodePositionsById[position.id] || previousNodePositionsById.root | ||
return `translate(${previousPosition.y},${previousPosition.x})` | ||
} | ||
}) | ||
@@ -178,3 +227,3 @@ .style({ | ||
.on({ | ||
mouseover: function mouseover(d, i) { | ||
mouseover: function mouseover() { | ||
d3.select(this).style({ | ||
@@ -184,3 +233,3 @@ fill: style.text.colors.hover | ||
}, | ||
mouseout: function mouseout(d, i) { | ||
mouseout: function mouseout() { | ||
d3.select(this).style({ | ||
@@ -199,5 +248,9 @@ fill: style.text.colors.default | ||
nodeEnter.append('circle') | ||
// g inside node contains circle and text | ||
// this extra wrapper helps run d3 transitions in parallel | ||
const nodeEnterInnerGroup = nodeEnter.append('g') | ||
nodeEnterInnerGroup.append('circle') | ||
.attr({ | ||
'class': 'nodeCircle' | ||
'class': 'nodeCircle', | ||
r: 0 | ||
}) | ||
@@ -207,9 +260,12 @@ .on({ | ||
if (d3.event.defaultPrevented) return | ||
update(toggleChildren(clickedNode)) | ||
toggleChildren(clickedNode) | ||
update() | ||
} | ||
}) | ||
nodeEnter.append('text') | ||
nodeEnterInnerGroup.append('text') | ||
.attr({ | ||
'class': 'nodeText', | ||
'text-anchor': 'middle', | ||
'transform': `translate(0,0)`, | ||
dy: '.35em' | ||
@@ -227,13 +283,6 @@ }) | ||
node.select('text') | ||
.attr({ | ||
x: d => d.children || d._children ? -(style.node.radius + 10) : style.node.radius + 10, | ||
'text-anchor': d => d.children || d._children ? 'end' : 'start' | ||
}) | ||
.text(d => d.name) | ||
// change the circle fill depending on whether it has children and is collapsed | ||
node.select('circle.nodeCircle') | ||
.attr({ | ||
r: style.node.radius | ||
}) | ||
node.select('circle') | ||
.style({ | ||
@@ -252,11 +301,18 @@ stroke: 'black', | ||
// fade the text in | ||
// ensure circle radius is correct | ||
nodeUpdate.select('circle') | ||
.attr('r', style.node.radius) | ||
// fade the text in and align it | ||
nodeUpdate.select('text') | ||
.style('fill-opacity', 1) | ||
.attr({ | ||
transform: function transform(d) { | ||
const x = (d.children || d._children ? -1 : 1) * (this.getBBox().width / 2 + style.node.radius + 5) | ||
return `translate(${x},0)` | ||
} | ||
}) | ||
// restore the circle | ||
nodeUpdate.select('circle').attr('r', 7) | ||
// blink updated nodes | ||
nodeUpdate.filter(function flick(d) { | ||
node.filter(function flick(d) { | ||
// test whether the relevant properties of d match | ||
@@ -266,6 +322,7 @@ // the equivalent property of the oldData | ||
// to catch the entering elements! | ||
return (!this.__oldData__ || d.value !== this.__oldData__.value) | ||
return (this.__oldData__ && d.value !== this.__oldData__.value) | ||
}) | ||
.style('fill-opacity', '0.3').transition() | ||
.duration(100).style('fill-opacity', '1') | ||
.select('g') | ||
.style('opacity', '0.3').transition() | ||
.duration(blinkDuration).style('opacity', '1') | ||
@@ -276,3 +333,7 @@ // transition exiting nodes to the parent's new position | ||
.attr({ | ||
transform: d => `translate(${source.y},${source.x})` | ||
transform: d => { | ||
const position = findParentNodePosition(previousNodePositionsById, d.id, (n) => nodePositionsById[n.id]) | ||
const futurePosition = position && nodePositionsById[position.id] || nodePositionsById.root | ||
return `translate(${futurePosition.y},${futurePosition.x})` | ||
} | ||
}) | ||
@@ -296,9 +357,7 @@ .remove() | ||
d: d => { | ||
let o = { | ||
x: source.x0, | ||
y: source.y0 | ||
} | ||
const position = findParentNodePosition(nodePositionsById, d.target.id, (n) => previousNodePositionsById[n.id]) | ||
const previousPosition = position && previousNodePositionsById[position.id] || previousNodePositionsById.root | ||
return diagonal({ | ||
source: o, | ||
target: o | ||
source: previousPosition, | ||
target: previousPosition | ||
}) | ||
@@ -317,13 +376,12 @@ } | ||
// transition exiting nodes to the parent's new position | ||
link.exit().transition() | ||
link.exit() | ||
.transition() | ||
.duration(transitionDuration) | ||
.attr({ | ||
d: d => { | ||
let o = { | ||
x: source.x, | ||
y: source.y | ||
} | ||
const position = findParentNodePosition(previousNodePositionsById, d.target.id, (n) => nodePositionsById[n.id]) | ||
const futurePosition = position && nodePositionsById[position.id] || nodePositionsById.root | ||
return diagonal({ | ||
source: o, | ||
target: o | ||
source: futurePosition, | ||
target: futurePosition | ||
}) | ||
@@ -338,8 +396,5 @@ } | ||
// stash the old positions for transition | ||
nodes.forEach(d => { | ||
d.x0 = d.x | ||
d.y0 = d.y | ||
}) | ||
previousNodePositionsById = nodePositionsById | ||
} | ||
} | ||
} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
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
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
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
994025
22427
1