Skip to content

Instantly share code, notes, and snippets.

@Andrew-Reid
Last active October 9, 2022 11:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Andrew-Reid/960819e98873bbaf035bbf6bd2774b40 to your computer and use it in GitHub Desktop.
Save Andrew-Reid/960819e98873bbaf035bbf6bd2774b40 to your computer and use it in GitHub Desktop.
Nested Enter/Update/Exit with id
<html>
<head>
<script src="https://d3js.org/d3.v4.js"></script>
</head>
<body>
<script>
// starter data:
var data = [
{id:0, children: d3.range(10)},
{id:1, children: d3.range(6)},
{id:2, children: d3.range(9)},
];
var index = 3; // current parent index.
var t = 1000;
var svg = d3.select("body")
.append("svg")
.attr("width",600)
.attr("height",400)
// .on("click",update);
update();
function update() {
manipulateData();
var parents = svg.selectAll(".parentGroup")
.data(data, function(d) { return d.id; });
// used for spacing:
var exiting = parents.exit().size();
// transition child rects from parents that are exiting:
parents.exit()
.select(".childGroup")
.selectAll("rect")
.transition()
.attr("height",0)
.duration(t);
parents.exit().transition().style("fill","white").duration(t).remove();
// enter new parents:
var parentsEnter = parents.enter()
.append("g")
.attr("class","parentGroup")
.attr("transform",function(d,i) {
return "translate(10,"+((i+exiting)*24+20)+")";
})
.style("fill", function(d) { return d3.schemeCategory20[d.id%20]; });
// add child elements only to parents that were just entered:
parentsEnter.append("text")
.text(function(d) { return d.id; });
parentsEnter.append("g")
.attr("class","childGroup")
// merge entered parents with pre-existing:
parents = parentsEnter.merge(parents);
// update all:
parents.transition().attr("transform",function(d,i) { return "translate(10,"+(i*24+20)+")"; }).duration(t);
// Select a child group in each parent:
var children = parents.select(".childGroup");
// do an enter/exit/update cycle with the child's datum:
var childRects = children.selectAll("rect")
.data(function(d) { return d.children; }, function(d) { return d; });
// rects removed individually:
childRects.exit()
.transition()
.attr("width",0)
.attr("height",0)
.duration(t)
.remove();
// enter:
var childRectsEnter = childRects.enter()
.append("rect")
.attr("x", function(d,i) { return i * 24 + 30 })
.attr("y", 4)
.attr("height",0)
.attr("width",20)
.transition()
.attr("height",20)
.attr("y",-16)
.duration(t);
// update pre-existing child rects:
childRects
.transition()
.attr("x", function(d,i) { return i * 24 + 30 })
.duration(t);
}
setInterval(update,1200);
// modify data array in some randomish way:
function manipulateData() {
data.forEach(function(d,i) {
var r = Math.random();
// remove parent sometimes
if (r > 0.8 && data.length > 2) {
data.splice(i,1);
}
// modify children sometimes (remove random element):
else if (r > 0.5) {
var length = d.children.length;
var remove = Math.floor(Math.random() * length);
d.children.splice(remove,1);
}
// modify children sometimes (add random element):
else if (r > 0.2) {
var max = d3.max(d.children, function(d) { return d; });
d.children.push(max+1);
}
// add new parent sometimes:
else {
var n = Math.floor(Math.random()*10)+1;
data.push({
id: index++, children: d3.range(n)
})
}
})
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment