d3.js:使用“join”进行更新的嵌套选择

Nei*_*eil 7 d3.js

我是 d3.js 的新手,并尝试复制类似于选择连接的东西,支持使用嵌套选择进行更新。我在早期版本中看到过这个问题,并带有明确的enter/exit并尝试对其进行调整。但是,我无法完全弄清楚这段代码的内部绑定。例如,顶部迭代的n-1小写字母在后续间隔中是粉红色的,而不是在迭代中不变的字母。代码笔

const main = d3.select("main");

function updateOld() {
  content = randomUpper().map(u => {
    return {
      header: u,
      list: randomLower()
    };
  });

  let outer = main.selectAll("div")
    .data(content, d => d.header)
  outer.exit().remove();

  const outerEnter = outer.enter()
    .append("div")
    .style("color", "green")
    .text(d => d.header);

  outer = outerEnter.merge(outer.style("color", "gray"));

  inner = outer.selectAll("h6")
    .data(d => d.list);
  inner.exit().remove();

  inner.enter()
    .append("h6")
    .style("color", "blue")
    .merge(inner.style("color", "pink"))
    .text(d => d);
}

setInterval(updateOld, 2000);
updateOld();

function randomUpper() {
  return d3.shuffle("ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""))
    .slice(0, Math.floor(6 + Math.random() * 20))
    .sort();
}

function randomLower() {
  return randomUpper().map(u => u.toLowerCase())
}
Run Code Online (Sandbox Code Playgroud)
main {
  display: flex;
}

div {
  width: 40px;
}

h6 {
  margin: 5px 0;
}
Run Code Online (Sandbox Code Playgroud)
<main></main>
<script src="https://d3js.org/d3.v6.js"></script>
Run Code Online (Sandbox Code Playgroud)

理想情况下,我想对其进行调整以利用 v6 join(如果可能)。这是我得到的最接近的结果,但无法完全找出管理数据绑定和选择的正确方法。

function updateV6() {
  content = randomUpper().map(u => {
    return { header: u, list: randomLower() };
  });

  main.selectAll("div")
    .data(content, d => d.header)
    .join(
      enter => {
        root = enter.append("div")
        
        root.append("h3")
          .style("color", "green")
          .text(d => d.header);
        
        root.selectAll("h6")
          .data(d => d.list)
          .join("h6")
            .style("color", "blue")
            .text(d => d);
      },
      update => {
        update.selectAll("h3")
          .style("color", "gray")

        // How to add the newly introduced h6 elements corresponding
        // to each h3 and change color of others that remain across iterations?
      }
    );
}
Run Code Online (Sandbox Code Playgroud)

Rub*_*oot 5

您可以通过确保从 中返回enter来组合这些不同的操作(在和之后) 。返回选择允许它们被合并,之后您可以对它们进行相同的处理:update.join()

  • 输入新值使它们变成粉红色
  • 更新现有值使其变为蓝色
  • 为所有值提供正确的文本

编辑:我认为您在第二部分中缺少一个关键函数.data(),这将使 d3 查看字母的值,而不是它们的索引。我cycle也使用了你的功能来使其更清晰。

const main = d3.select("main");

const cycle = [
  [{
      header: "B",
      list: ["a", "b", "c"]
    },
    {
      header: "C",
      list: ["c"]
    },
  ],
  [{
      header: "B",
      list: ["a", "c", "d", "e"]
    }, // remove [b], add [d,e]
    {
      header: "D",
      list: ["a", "b", "c", "d"]
    },
  ],
  [{
      header: "D",
      list: ["b", "c", "e"]
    }, // remove [a, d], add [e]
    {
      header: "E",
      list: ["a", "b", "c"]
    },
  ],
]

var counter = 0;

function updateV6() {
  content = cycle[counter % cycle.length];
  counter++;

  main.selectAll("div")
    .data(content, d => d.header)
    .join(
      enter => {
        root = enter.append("div")
        root.append("h3")
          .style("color", "green")
          .text(d => d.header);
        return root;
      },
      update => {
        update.selectAll("h3")
          .style("color", "gray");
        return update;
      }
    )
    .selectAll("h6")
    .data(d => d.list, d => d)
    .join(
      enter => enter.append('h6').style("color", "blue"),
      update => update.style("color", "pink")
    )
    .text(d => d);
}

setInterval(updateV6, 2000);
updateV6();
Run Code Online (Sandbox Code Playgroud)
main {
  display: flex;
}

div {
  width: 40px;
}

h6 {
  margin: 5px 0;
}
Run Code Online (Sandbox Code Playgroud)
<main></main>
<script src="https://d3js.org/d3.v6.js"></script>
Run Code Online (Sandbox Code Playgroud)