I'm new to D3 and I'm doing a simple example trying to understand how the data binding works.
Basically I've an array of colors, a function for adda color and a function to remove a color from index. What is not working is the remove action. If I set 0 as index to remove, I see that D3 set the last element as element to remove. If I use the key accessor d => d
, it works. I've a lot of question.
Here my code:
const data = {
colors: ["Black", "White", "Brown"],
addColor(color) {
this.colors.push(color);
},
removeColorByIndex(index) {
this.colors.splice(index, 1);
}
};
const root = d3.select("#root");
const barsContainer = d3.select("#bars-container");
const addButton = d3.select("#add-button");
const removeButton = d3.select("#remove-button");
addButton.on("click", () => {
const newColor = d3.select("#color-input").node().value;
data.addColor(newColor);
update();
});
removeButton.on("click", () => {
const index = d3.select("#index-input").node().value;
data.removeColorByIndex(index);
update();
});
function update() {
barsContainer
.selectAll("div")
.data(data.countries, (d, i) => {
console.log({ i, d });
return i;
})
.join(
(enter) => {
console.log("enter:", enter);
return enter
.append("div")
.text((d) => d)
.classed("bar", true)
.classed("added", true);
},
(update) => {
console.log("update:", update);
return update.classed("update", true);
},
(exit) => {
console.log("exit:", exit);
return exit.classed("remove", true);
}
);
console.log("divs", barsContainer.selectAll("div")["_groups"][0]);
}
update();
.bar {
margin: 5px 0px 5px 0px;
max-width: 200px;
padding: 10px;
}
.added { background-color: lightgreen; }
.update { background-color: cornflowerblue; }
.remove { background-color: tomato; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="root">
<div>
<div>
<input type="text" id="color-input" />
<button id="add-button">Add color</button>
</div>
<div>
<input type="text" id="index-input" />
<button id="remove-button">Remove color by index</button>
</div>
</div>
<div id="bars-container"></div>
</div>
- Initially all the bars are green. That's because they are all in the enter selection.
- If I add a color using the UI button, then new bars appears, it's green and the old ones became blue.
- Then, If I try to remove the bar with index 0, the last bars became red, not the first one, why?
If I imagine the behind logic, it would be:
Step # | Action | Enter selection | Update selection | Exit selection | Join return selection (enter + update) |
---|---|---|---|---|---|
0 | / | [black, white, brown] | [] | [] | black, white, brown |
1 | Add 'Yellow' color | [yellow] | black, white, brown] | [] | black, white, brown, yellow] ? |
2 | Remove element with index 0 | [] | [yellow] | [black] | [yellow] |
But it seems is not right, what I'm wrong?
I knwow that doing data(myData, (d, i) => i)
is the same of data(myData)
and that means that D3 is matching data/DOM nodes by index. So why if I look at the __data__
property of the binded elements, they have __data__ = black/white/brown
and not __data__ = 0/1/2
?
I'm very confused and I didn't find anything that can help me..
I read D3 documentation and also this question.
from Understanding D3 data binding key accessor
No comments:
Post a Comment