Skip to content

Instantly share code, notes, and snippets.

@EmbraceLife
Last active August 1, 2016 09:10
Show Gist options
  • Save EmbraceLife/efb531e68ce46c51cb1df2ca360348bb to your computer and use it in GitHub Desktop.
Save EmbraceLife/efb531e68ce46c51cb1df2ca360348bb to your computer and use it in GitHub Desktop.
8. update-enter-merge-exit
license: gpl-3.0

This example demonstrates D3’s general update pattern, where a data-join is followed by operations on the enter, update and exit selections. Entering elements are shown in green, while updating elements are shown in black. Exiting elements are removed immediately, so they're invisible.

This example does not use a key function for the data-join, so elements may change their associated letter. Entering elements are always added to the end: when the new data has more letters than the old data, new elements are entered to display the new letters. Likewise, exiting letters are always removed from the end when the new data has fewer letters than the old data.

Next: Key Functions

forked from mbostock's block: General Update Pattern, I

<!DOCTYPE html>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
text {
font: bold 48px monospace;
}
.enter {
fill: green;
}
.update {
fill: #333;
}
</style>
<svg width="960" height="500"></svg>
<script>
// svg's width and height is ultimate boundary for drawing
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
// var g is where drawing really begin
g = svg.append("g")
.attr("transform", "translate(32," + (height / 2) + ")");
// ---- split a string into string array
var alphabet = "abcdefghijklmnopqrstuvwxyz".split("");
// console.log(alphabet);
// ---- create a updating func -----------------------
function update(data) {
// ---- update new data with existing dom ---------------
// 1. bind data with all existing text dom
var text = g.selectAll("text")
.data(data);
// 2. inside text, there are 3 arrays of objs, only update groups is selected
// 2.1. _enter:
// array of NodeList: length => num of new data without previous dom to match
// 2.2. _exit:
// array of text: length => num of previous dom without new data to match
// 2.3. _groups: update group
// array of text: length => num of previous dom matched with new data
// 3. add class name to selection for update
text.attr("class", "update");
// console.log("check updated text: ", text);
// ---- step 7: select, create, attr entering dom with data -----------
// 1. select _enter array of NodeList storing datum from new dataset:
// code: var enterText = text.enter()
// 2. create a text array to replace NodeList
// code: var enterText = text.enter().append("text")
// outcome: elements of NodeList are replaced with texts
// 3. add attr: className, x, dy
// meaning: each letter's x position is depend on datum index
// code: .attr("x", function(d, i) { return i * 32; })
var enterText = text.enter().append("text")
.attr("class", "enter")
.attr("x", function(d, i) { return i * 32; })
.attr("dy", ".35em");
// console.log("Look at enterText: ", enterText);
// ---- step 8: merge with update selection -----------------------
// 1. let enterText merge with text (update selection): --
// code: var mergedText = enterText.merge(text)
// outcome: the merged doms are selected
// 2. add x attr to the merged selection: --
// meaning: x position depend on each datum's index
// 3. add label to each dom/text: --
// code: .text(function(d){return d;})
var mergedText = enterText
.merge(text)
.attr("x", function(d, i) { return i * 32; })
.text(function(d) { return d; });
// console.log("Look at mergedText: ", mergedText);
// ---- step 9: select exiting dom and remove them --------------------
// 1. select exiting dom: --
// code: text.exit()
// 2. remove exiting dom from elements view: --
// code: var exitText = text.exit().remove();
var exitText = text.exit().remove();
// console.log("Look at exiting texts: ", exitText);
}
// The initial display.
update(alphabet);
// ---- step 10: repetition and interval --------------------------
// 1. repeat after a certain interval: --
// code: d3.interval(function() {}, seconds);
// 2. shuffle data like shuffle cards: --
// code: d3.shuffle(array)
// 3. subset array: if Math.random() returns 0.5, then: --
// code: slice(0, 20)
// 4. Math.floor, Math.round, Math.random(), slice(first, last), sort(): --
// note: diff between Math.floor and Math.round
// search: w3schools
d3.interval(function() {
// it is update() function
// inside update(), we offer a random sample of letters and sort it in alphabet order
update(d3.shuffle(alphabet)
.slice(0, Math.floor(Math.random() * 26))
.sort());
}, 1000);
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment