【问题标题】:Understanding D3 data binding key accessor了解 D3 数据绑定密钥访问器
【发布时间】:2021-03-02 11:30:57
【问题描述】:

我是 D3 的新手,我正在做一个简单的示例,试图了解数据绑定的工作原理。

基本上我有一个颜色数组、一个添加颜色的函数和一个从索引中删除颜色的函数。 不工作的是删除操作。 如果我将 0 设置为要删除的索引,我会看到 D3 将最后一个元素设置为要删除的元素。如果我使用密钥访问器d => d,它可以工作。 我有很多问题。

这是我的代码:

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>
  1. 最初所有的条都是绿色的。那是因为它们都在输入选择中。
  2. 如果我使用 UI 按钮添加颜色,则会出现新的条形图,它是绿色的,旧的条形图变成蓝色。
  3. 那么,如果我尝试删除索引为 0 的条,最后一个条变成红色,而不是第一个条,为什么?

如果我想象背后的逻辑,那将是:

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]

但是好像不对,我哪里错了?

我知道 data(myData, (d, i) =&gt; i)data(myData) 相同,这意味着 D3 按索引匹配数据/DOM 节点。那么为什么如果我查看绑定元素的__data__ 属性,它们有__data__ = black/white/brown 而不是__data__ = 0/1/2

我很困惑,我没有找到任何可以帮助我的东西..

我阅读了 D3 文档以及 this question

【问题讨论】:

    标签: javascript html d3.js


    【解决方案1】:

    如果我尝试删除索引为 0 的条,最后一个条变成红色 [退出],而不是第一个,为什么?

    key 函数返回的标识符既不存储在 DOM 节点上,也不存储在数据上。每次使用 .data() 时都会对其进行评估。每次使用 .data() 时,如果提供了 key 函数,将对选择中的每个节点进行评估(使用绑定数据 .__data__,它表示数据数组中的一个项目),然后 D3 遍历数据数组以查找与节点匹配的数据。如果未找到匹配节点,则将一个节点添加到具有该数据的输入选择中。如果匹配所有数据后,有多余的节点,则退出。

    您的关键功能是(d,i)=&gt;i - 通过删除数据数组中的第一项,数据数组中仍有一个索引为 0 的项。索引为 0 的数据数组项与选择中的第 0 个节点匹配。所以第一个节点不能退出:它在数据数组中还有对应的项。

    鉴于您的关键功能:这意味着最初在索引 1 处并与索引 1 处的节点配对的基准现在是索引 0 处的基准(拼接后),并将与索引 0 处的节点配对

    由于您的数据数组比原来短了一项,因此 DOM 中有一个多余的节点。最后一个节点的索引最高,没有匹配的数据数组项,所以退出最后一个节点。除了最后一个节点之外的所有节点都在更新选择中。

    通常你会使用一个键函数来引用数据本身,而不是它的位置/索引(因为排序或其他因素可能会改变,这会改变哪个数据绑定到哪个节点)。因此,如果您的数据包含唯一的颜色名称,您会希望使用:.data(data,d=&gt;d)注意:如果 d 是一个对象,键函数应该返回一个字符串)。这样,无论索引如何,相同的数据都与相同的节点配对。因此,从数组中拼接一个数据将删除它绑定到的相应节点。

    我已经创建了两次可视化键函数的尝试,一种是依赖于数据的键,另一种是基于索引的键。如果您在使用索引键匹配基准和元素时仔细观察,绑定到元素的基准会发生变化:键与基准无关。

    Key based on datum

    Key based on index

    块有点粗糙,我可能会在这里调整并合并到答案正文中

    【讨论】:

    • 谢谢安德鲁,但仍不清楚。 每次使用 .data() 时,都会为选择中的每个节点评估 key 函数(使用绑定数据 .__data__,它表示数据数组中的一个项目),然后D3 遍历数据数组以找到与节点匹配的数据。?也许一些 sn-ps 可以提供帮助
    • @whitecircle,将通过视觉 sn-p 进行澄清,不过可能需要一两天时间。
    • @whitecircle - 正如我所说,我没有忘记有点忙。我已经添加了一些 bl.ocks 帮助的链接,这些帮助应该/也许有助于可视化关键功能,尽管我有一些关于改进的想法,我可能希望做出改进。
    猜你喜欢
    • 2017-03-06
    • 1970-01-01
    • 2012-03-17
    • 1970-01-01
    • 2012-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-03
    相关资源
    最近更新 更多