javascript - 数据绑定(bind)中的关键函数: objects vs strings

标签 javascript d3.js

使用d3.selectAll(...).data(mydata, key_fn)绑定(bind)数据时,我希望与先前绑定(bind)的数据匹配的所有键最终都会出现在更新中 选择(而不是 enter()exit()),但我发现如果先前绑定(bind)的数据是字符串而新绑定(bind)的数据则并非如此数据是一个对象。 这是预期的行为吗?如果是这样,有人可以解释为什么吗?

以下是我的意思的示例,在 Chrome JS 控制台中使用 D3.js v5.15.0:

// Setup some data arrays, one with strings and one with objects using the same string values
    strings_only = ['A','B','C'];
    objects_with_values = [{key:'A',value:1},{key:'B',value:2},{key:'C',value:3}];
    
    // Bind the string data to the DOM with string values as keys
    d3.select('body').selectAll('div.test')
        .data(strings_only, d => d)
        .enter()
        .append('div')
        .attr('class','test');

    // Bind again with the strings and I get the expected behavior
    selection_strings_only = d3.select('body').selectAll('div.test')
        .data(strings_only, d => d);
    console.log(selection_strings_only.size() == strings_only.length); // PASS
    console.log(selection_strings_only.enter().size() == 0); // PASS
    
    // Bind with the objects (same key value) and they end up in the enter() selection
    selection_objects_with_values = d3.select('body').selectAll('div.test')
        .data(objects_with_values, d => d.key);
    console.log(selection_objects_with_values.size() == strings_only.length); // FAIL
    console.log(selection_objects_with_values.enter().size() == 0); // FAIL
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

如果我的初始数据是对象数组而不是字符串(例如 [{key:'A'},{key:'B'},{key:C}]),那么新对象的更新按预期工作,因此我能够解决此问题,但我仍然对为什么我的初始方法不起作用感到困惑。

最佳答案

为了意识到这里的问题是什么,我们必须明白,当使用key function时,它被评估两次

  1. 针对元素进行评估...

This key function is evaluated for each selected element, in order, being passed the current datum (d), the current index (i), and the current group (nodes), with this as the current DOM element (nodes[i]); the returned string is the element’s key.

  • ...然后,再次对其进行评估,这次是针对数据:
  • The key function is then also evaluated for each new datum in data, being passed the current datum (d), the current index (i), and the group’s new data, with this as the group’s parent DOM element; the returned string is the datum’s key.

    有了这些信息,我们就可以理解这里发生了什么:将 objects_with_values 绑定(bind)为数据后,key 函数在针对元素运行时将返回 undefined,因为这些元素没有 key 属性。看看:

    strings_only = ['A', 'B', 'C'];
    objects_with_values = [{
      key: 'A',
      value: 1
    }, {
      key: 'B',
      value: 2
    }, {
      key: 'C',
      value: 3
    }];
    
    d3.select('body').selectAll('div.test')
      .data(strings_only, d => d)
      .enter()
      .append('div')
      .attr('class', 'test');
    
    selection_objects_with_values = d3.select('body').selectAll('div.test')
      .data(objects_with_values, d => {
        console.log(d.key);
        return d.key;
      });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

    正如预期的那样,您在 3 个 undefined 之后看到的 A、B、C 对应于关键函数的第二次运行。

    解决方案很简单:如果没有d.key,则仅查找d:

    .data(objects_with_values, d => d.key ? d.key : d);
    

    这是经过更改的代码:

    strings_only = ['A', 'B', 'C'];
    objects_with_values = [{
      key: 'A',
      value: 1
    }, {
      key: 'B',
      value: 2
    }, {
      key: 'C',
      value: 3
    }];
    
    // Bind the string data to the DOM with string values as keys
    d3.select('body').selectAll('div.test')
      .data(strings_only, d => d)
      .enter()
      .append('div')
      .attr('class', 'test');
    
    // Bind again with the strings and I get the expected behavior
    selection_strings_only = d3.select('body').selectAll('div.test')
      .data(strings_only, d => d);
    console.log(selection_strings_only.size() == strings_only.length); // PASS
    console.log(selection_strings_only.enter().size() == 0); // PASS
    
    // Bind with the objects (same key value) and they end up in the enter() selection
    selection_objects_with_values = d3.select('body').selectAll('div.test')
      .data(objects_with_values, d => d.key ? d.key : d);
    console.log(selection_objects_with_values.size() == strings_only.length); // FAIL
    console.log(selection_objects_with_values.enter().size() == 0);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

    关于javascript - 数据绑定(bind)中的关键函数: objects vs strings,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62685981/

    相关文章:

    javascript - 编译后操作模板

    javascript 返回两个单选按钮值

    javascript - 如何将 angular2 组件附加到 d3 选择?

    javascript - 如何为可滚动的 div 标签添加拉伸(stretch)效果

    javascript - namespace 对象如何在 JavaScript 中与 AMD 一起使用?

    javascript - 提供整个 D3 map 事件监听器

    javascript - 当我添加 .text() 时,简单的 d3.js 条形图会反转

    javascript - 下载的 d3 散点图图像中缺少线

    javascript - D3.js 输入/更新/退出未按预期添加元素

    java - 检查交易终止