D3 .merge函数

新手上路,请多包涵

尽管无数次阅读了 D3 API,但我仍在努力理解 D3 中的合并功能。

API 说:“此方法通常用于合并数据连接后的输入和更新选择。分别修改输入和更新元素后,您可以合并两个选择并对两者执行操作,而无需重复代码。”

这是一个在力导向图表中假定直接使用它的示例,其中每次报价都会调用 ticked 函数:

 var simulation = d3.forceSimulation(nodes)
    .force("charge", chargeForce)
    .force("center", centerForce)
    .on("tick", ticked);

    function ticked() {

    var u = d3.select("svg").selectAll("circle").data(nodes)

    u.enter().append("circle").attr("r",5)
        .merge(u) // What is the merge function doing here?
        .attr("cx", d => d.x)
        .attr("cy", d => d.y)

    u.exit().remove() // Why is it necessary to remove excess objects w/ the exit selection?

    }

我了解数据绑定的工作原理,以及 enter() 和 exit() 选择的工作原理。但是,我以前从未使用过“合并”,而且我不明白它在这里做什么。如果有人可以逐步简要介绍此功能中发生的事情,那将非常有用。我相信其他人也有类似的问题。

原文由 Harrison Cramer 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 800
2 个回答

该文档很好地解释了该功能的作用,所以它所做的是而不是你必须这样做

u.attr("cx", d => d.x)
 .attr("cy", d => d.y);

u.enter().append("circle").attr("r",5)
        .attr("cx", d => d.x)
        .attr("cy", d => d.y);

你可以打电话 attr 一次

u.enter().append("circle").attr("r",5)
        .merge(u) // after this point, any updates will apply to both u and u.enter() selections
        .attr("cx", d => d.x)
        .attr("cy", d => d.y)

It will set attributes cx and cy on both u -the update selection and u.enter() -the enter selection

为什么需要通过退出选择移除多余的对象?

因为出口选择包含任何额外的 DOM 元素,这些元素未绑定到您传递给 data() 的数组中的元素,所以您可以在出口集合上做任何您需要的事情,例如通过调用设置样式 u.exit().style(...) 等,而不是调用 remove 从 DOM 中删除它们

原文由 Trash Can 发布,翻译遵循 CC BY-SA 3.0 许可协议

你实际上有两个问题:

  1. 了解 merge() 方法;
  2. 了解您共享的那段代码;

关于#1,您已经收到了答复。关于#2,这是我的两分钱:该代码 没有 意义。

这个很容易理解: ticked 函数每秒运行几十次。 如果数据没有改变,你为什么要重新绑定数据并重新分配更新、进入和退出选择每秒几十次? (值得一提的是,那段代码的作者是一个优秀的程序员,这里发生了一些奇怪的事情……毕竟,我们都会犯错)

ticked 函数只需要计算元素的位置,仅此而已。

这是您与 ticked 函数链接的相同代码,简化为:

 function ticked() {
    u.attr('cx', function(d) {
            return d.x;
        })
        .attr('cy', function(d) {
            return d.y;
        })
}

这里是运行代码:

 var width = 600,
  height = 400;

var colorScale = ['orange', 'lightblue', '#B19CD9'];
var xCenter = [100, 300, 500]

var numNodes = 100;
var nodes = d3.range(numNodes).map(function(d, i) {
  return {
    radius: Math.random() * 25,
    category: i % 3
  }
});

var u = d3.select('svg g')
  .selectAll('circle')
  .data(nodes);

var enter = u.enter()
  .append('circle')
  .attr('r', function(d) {
    return d.radius;
  })
  .style('fill', function(d) {
    return colorScale[d.category];
  });

u = enter.merge(u);

u.exit().remove();

var simulation = d3.forceSimulation(nodes)
  .force('charge', d3.forceManyBody().strength(5))
  .force('x', d3.forceX().x(function(d) {
    return xCenter[d.category];
  }))
  .force('collision', d3.forceCollide().radius(function(d) {
    return d.radius;
  }))
  .on('tick', ticked);

function ticked() {
  u.attr('cx', function(d) {
      return d.x;
    })
    .attr('cy', function(d) {
      return d.y;
    })
}
 <script src="https://d3js.org/d3.v4.min.js"></script>
<div id="content">
  <svg width="700" height="400">
    <g transform="translate(50, 200)"></g>
  </svg>
</div>

原文由 Gerardo Furtado 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题