我试图通过将新鲜的Date对象传递到data()函数中,然后通过join()更新页面,来使D3每秒更新一次SVG元素。我实际上是在使用Promises.tick()Observable笔记本中执行此操作的,但是我认为下面的代码(full source)是相关位的粗略近似。我的最终目标是打个钟,但是这里的代码是我所遇到问题的最小演示。

此代码的问题在于,永远不会调用update中的join()函数-每次循环时都会调用enter函数,这导致每次都附加一个新的text。因为我有一个基准和一个元素,所以我希望调用joinupdate,而不是enter。我知道data()example)上的键函数对于确定已更改的内容很重要,但我的理解是默认键为数组索引,此处应始终为0。无论如何,指定一个不同的键函数(从标识函数到返回常量)都无济于事。

while (true) {
  var data = [new Date()];

  svg
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    .selectAll("text")
    .data(data)
    .join(
      enter => enter.append("text").text(d => "enter: " + d),
      update => update.text(d => "update: " + d)
    );

  await new Promise(resolve => setTimeout(resolve, 1000));
}

最佳答案

看这个:

svg
  .append("g")
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
  //etc...


您每次运行循环时都会添加一个新的<g>元素,此后所有选定的元素(文本或其他内容)都将引用该新添加的组,即selectAll选择该新添加的内部的所有文本组。显然没有。这就是为什么您始终只有一个Enter选择,却没有更新选择的原因。

看一下这个演示,重现您的问题:



var body = d3.select("body");

function foo(data) {
  var div = body.append("div")
    .selectAll("p")
    .data(data)
    .join(
      enter => enter.append("p").html(d => "enter: " + d),
      update => update.html(d => "update: " + d)
    );
};

foo([Math.random()]);
d3.interval(function() {
  foo([Math.random()])
}, 1000)

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.8.0/d3.min.js"></script>





假设您只想追加一次组,则可以执行以下操作:

var g = svg.selectAll(".myGroup")
  .data([true]);

g = g.append("g")
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
  .merge(g);

g.selectAll("text")
  .data(data)
  .join(
    enter => enter.append("text").text(d => "enter: " + d),
    update => update.text(d => "update: " + d)
  );


在这里,data([true])表示数据本身无关紧要,它只是用于附加单个组元素的单个真实值。

这是展示其工作原理的演示:



var body = d3.select("body");

function foo(data) {
  var div = body.selectAll(".myDiv")
    .data([true]);

  div = div.enter()
    .append("div")
    .attr("class", "myDiv")
    .merge(div);

  div.selectAll("p")
    .data(data)
    .join(
      enter => enter.append("p").html(d => "enter: " + d),
      update => update.html(d => "update: " + d)
    );
};

foo([Math.random()])
d3.interval(function() {
  foo([Math.random()])
}, 1000)

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.8.0/d3.min.js"></script>

关于javascript - d3.join()输入被调用而不是更新?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58322806/

10-12 12:40
查看更多