D3 .merge功能

Har*_*mer 12 javascript data-visualization d3.js

尽管经过无数次读取D3 API,我仍在努力理解D3中的合并功能.

API说:"此方法通常用于在数据连接后合并输入和更新选择.单独修改输入和更新元素后,您可以合并这两个选项并在两者上执行操作而无需重复代码."

这是一个在力导向图表中直截了当地使用它的例子,其中每个勾号都会调用勾选的函数:

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?

    }
Run Code Online (Sandbox Code Playgroud)

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

Tee*_*eez 8

该文档很好地解释了该函数的作用,因此它所做的不是你必须这样做

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);
Run Code Online (Sandbox Code Playgroud)

你可以打电话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)
Run Code Online (Sandbox Code Playgroud)

它将设置属性cxcy两者u- 更新选择和u.enter()输入选择

为什么有必要删除多余的物体与退出选择?

因为出口选择包含未绑定到您传递给的数组中的元素的任何额外DOM元素data(),所以您可以在退出捕获上执行任何操作,例如通过调用u.exit().style(...)等设置样式,而不是调用remove删除它们来自DOM


Ger*_*ado 5

您实际上在这里有两个问题:

  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;
        })
}
Run Code Online (Sandbox Code Playgroud)

这里是运行代码:

function ticked() {
    u.attr('cx', function(d) {
            return d.x;
        })
        .attr('cy', function(d) {
            return d.y;
        })
}
Run Code Online (Sandbox Code Playgroud)
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;
    })
}
Run Code Online (Sandbox Code Playgroud)