未能使用 d3 更新图例数据,已更改数据的输入为空

failed to use d3 to update legend data, entering is empty for changed data

我有一个“添加数据集”按钮,单击它后图例应显示更改后的数据集,一切都很好。我还有一个带有图例的点击事件,所以当我点击图例时,数据集被删除,我在样式上加上一条线,这就是问题所在,当我使用添加按钮添加另一个数据集时,删除的数据集图例应更改为新的数据集编号。控制台显示数据正确,但图例没有变化。我已经遵循了一些教程并且完全遵循了它,但仍然明白这一点,我已经为此工作了几个小时,我需要一些帮助,谢谢

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>

以下解决方案正是您所要求的。 我不删除任何节点,因为您总是 re-use 它们。

entering节点和newLegend节点之间也有区别——一个有实际内容,另一个只是一种空数组。

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>