Reputation: 165
I have an "add dataset" button, and once I click it the legend should show the changed dataset, this is all good. I also have a click event with the legend, so when I click the legend, the dataset get deleted, and I put a line through to the style, and here is the problem, when I use the add button to add another dataset, the deleted dataset legend should be changed to the new dataset number. The console shows the data is correct, but the legend is not changing. I have followed some tutorial and I completely followed it, but still get this, I have been working on this for several hours, I would like some help, thank you
let jsonObj = [{
category: "Jan",
values: [{
value: 9,
source: "dataset1",
},
{
value: 8,
source: "dataset2",
},
],
},
{
category: "Feb",
values: [{
value: 15,
source: "dataset1",
},
{
value: 21,
source: "dataset2",
},
],
},
];
// function for adding data
let counter = 2;
const add_set = (arr) => {
const ran = () => Math.floor(Math.random() * 15 + 1);
const add = (arr) => {
counter++;
arr.map((i) =>
i.values.push({
value: ran(),
source: `dataset${counter}`
})
);
};
add(arr);
};
//initial variables
let svg, totalWidth, totalHeight, legend;
const setup = () => {
totalWidth = 100;
totalHeight = 100;
svg = d3
.select("body")
.append("svg")
.attr("width", totalWidth)
.attr("height", totalHeight);
};
const draw = (data) => {
//No.6 set lengend
legend = svg
.selectAll(".legend")
.data(data[0].values.map((d) => d.source));
console.log(data[0].values.map((d) => d.source));
let entering = legend.enter();
let newLegend = entering
.append("g")
.attr("class", "legend")
.attr("transform", (d, i) => "translate(0," + i * 20 + ")")
.append("text")
.attr("x", totalWidth)
.attr("y", 9)
.style("text-anchor", "end")
.text((d) => d);
entering.text((d) => d);
let exiting = legend.exit();
exiting.remove();
newLegend.on("click", function(e, d) {
jsonObj.forEach((i) => {
i.values = i.values.filter((s) => s.source != d);
});
newLegend
.filter((x) => x === d)
.style("text-decoration", "line-through");
});
};
setup();
draw(jsonObj);
const update = () => {
add_set(jsonObj);
draw(jsonObj);
};
<script src="https://d3js.org/d3.v6.min.js"></script>
<button onclick="update()">Add dataset</button>
Upvotes: 1
Views: 87
Reputation: 13129
The following solution is exactly what you asked for. I don't remove any nodes, because you always re-use them.
There is also a difference between the entering
nodes and the newLegend
nodes - one has actual content, the other is just a sort of empty array.
let jsonObj = [{
category: "Jan",
values: [{
value: 9,
source: "dataset1",
},
{
value: 8,
source: "dataset2",
},
],
},
{
category: "Feb",
values: [{
value: 15,
source: "dataset1",
},
{
value: 21,
source: "dataset2",
},
],
},
];
// function for adding data
let counter = 2;
const add_set = (arr) => {
const ran = () => Math.floor(Math.random() * 15 + 1);
const add = (arr) => {
counter++;
arr.map((i) =>
i.values.push({
value: ran(),
source: `dataset${counter}`
})
);
};
add(arr);
};
//initial variables
let svg, totalWidth, totalHeight, legend;
const setup = () => {
totalWidth = 100;
totalHeight = 100;
svg = d3
.select("body")
.append("svg")
.attr("width", totalWidth)
.attr("height", totalHeight);
};
const draw = (data) => {
//No.6 set lengend
legend = svg
.selectAll(".legend")
.data(data[0].values.map((d) => d.source));
console.log(data[0].values.map((d) => d.source));
legend.exit().remove();
let newLegend = legend.enter()
.append("g")
.attr("class", "legend")
.attr("transform", (d, i) => "translate(0," + i * 20 + ")");
newLegend
.append("text")
.datum((d) => d)
.attr("x", totalWidth)
.attr("y", 9)
.style("text-anchor", "end")
.on("click", function(e, d) {
jsonObj.forEach((i) => {
i.values = i.values.filter((s) => s.source != d);
});
newLegend
.filter((x) => x === d)
.style("text-decoration", "line-through");
});
legend = newLegend.merge(legend);
legend
.style("text-decoration", null)
.select("text")
.text((d) => d);
};
setup();
draw(jsonObj);
const update = () => {
add_set(jsonObj);
draw(jsonObj);
};
<script src="https://d3js.org/d3.v6.min.js"></script>
<button onclick="update()">Add dataset</button>
Upvotes: 1