简体   繁体   English

D3圆形包装-动态标签更新

[英]D3 circle pack - dynamic label update

I'm pretty new to coding in D3. 我对D3编码很陌生。 I'm working on a near real-time circle pack chart that gets its underlying data from an ajax call and resizes the nodes based on changes in data values. 我正在研究一个接近实时的圆形包装图,该图表从ajax调用获取其基础数据,并根据数据值的变化来调整节点的大小。 The challenge I'm facing is likely to be dreadfully simple, but I've not yet found a similar-enough example online to leverage as a solution. 我面临的挑战可能非常简单,但我还没有在网上找到足够类似的示例来用作解决方案。

When I run this code, I know that the text values are actually being passed properly as the data changes. 当我运行此代码时,我知道随着数据的更改,文本值实际上已正确传递。 However, what's happening is that the code keeps appending text tags to the svg "g" nodes (with the updated values) rather than changing the existing element to reflect the updated value. 但是,正在发生的事情是,代码不断将文本标签附加到svg“ g”节点(具有更新的值),而不是更改现有元素以反映更新的值。 The result is a layered text mess in the middle of an otherwise attractive bubble. 结果是在原本诱人的气泡中间出现了分层的文本混乱。

I have tried using d3.exit().remove() to no avail - it's possible that I misused it and that it's actually the appropriate technique to apply. 我尝试使用d3.exit().remove()无济于事-可能是我滥用了它,实际上这是适用的适当技术。

Would someone be willing to provide some guidance on how I should accomplish 2 specific things: 有人愿意就我应该如何完成两件特定的事情提供一些指导:

1) I'd like to re-use existing "text" elements rather than remove + append unless it's not practical. 1)除非不切实际,否则我想重用现有的“文本”元素,而不是删除+附加。

2) I'd like to update the values of an existing "text" element with new data without refreshing the page. 2)我想用新数据更新现有“文本”元素的值,而不刷新页面。

The full code for the .js file is here below. .js文件的完整代码如下。 I'm aware that I can use "svg" instead of "svg:svg", etc. but I haven't gotten to the tidying-up stage on this file yet. 我知道我可以使用“ svg”代替“ svg:svg”等,但是我还没有进入该文件的整理阶段。

var Devices = {
  setup_devices : function() {
  var r = 500,
    format = d3.format(",d"),
    fill = d3.scale.category10();

  var bubble = d3.layout.pack()
    .sort(null)
    .size([r, r])
    .padding(1.5);

  var chart = d3.select("#device_info").append("svg:svg")
    .attr("width", r)
    .attr("height", r)
    .attr("class", "bubble")
    .append("svg:g")
    .attr("transform", "translate(2, 2)");

  var tip = d3.tip()
    .attr('class', 'd3-tip')
    .offset([-10, 0])
    .html(function(d) {
      return "<strong>Device:</strong> <span style='color:red'>" + d.name + "</span>";
    });

  chart.call(tip);

  setInterval(function() {

    console.log("Devices Refreshing");

    $.ajax({
      type: "GET",
      url: "/devices",
      dataType: "json",
      beforeSend: function() {
      },
      error: function( jqXHR, textStatus, thrownError ) {
        return true;
      },
      success: function(data) {
        update(data);
        return true;
      }
    });

    d3.timer.flush();

  }, 2000);


  function update(data) {

    var updated = chart.data([data]).selectAll("g.node")
      .data(bubble.nodes);

    updated.enter().append("svg:g")
      .attr("class", "node")
      .attr("transform", function(d) {
        return "translate(" + d.x + "," + d.y + ")";
      })
      .attr("data-name", function(d) {
        return d.name;
      })
      .attr("data-device", function(d) {
        return d.device_id;
      })
      .on('mouseover', tip.show)
      .on('mouseout', tip.hide)
      .append("svg:circle")
        .attr("r", function(d) { return d.r; })
        .style("fill", function(d) { return fill(d.name); })
        .attr("text-anchor", "middle")
        .attr("dy", ".3em")
        .text(function(d) { return d.value + "%" });

    updated.append("svg:text")
      .attr("text-anchor", "middle")
      .attr("dy", ".3em")
      .text(function(d) { return d.value + "%" });

    updated.transition()
      .duration(1000)
      .attr("class", "node")
      .attr("transform", function(d) {
        return "translate(" + d.x + "," + d.y + ")";
      });

    updated.select("circle").transition()
      .duration(1000)
      .attr("r", function(d) { return d.r; })
      .text(function(d) { return d.value + "%" });
    }
  }
}

You just need to handle the enter and update selections separately -- to the enter selection you append, for the update selection you reuse existing elements. 您只需要分别处理回车和更新选择-添加到回车选择,对于更新选择,您可以重复使用现有元素。

var enterGs = updated.enter().append("svg:g")
  .attr("class", "node")
  .attr("transform", function(d) {
    return "translate(" + d.x + "," + d.y + ")";
  })
  .attr("data-name", function(d) {
    return d.name;
  })
  .attr("data-device", function(d) {
    return d.device_id;
  })
  .on('mouseover', tip.show)
  .on('mouseout', tip.hide);

enterGs.append("circle");
enterGs.append("text")
  .attr("text-anchor", "middle")
  .attr("dy", ".3em");

updated.select("circle")
    .attr("r", function(d) { return d.r; })
    .style("fill", function(d) { return fill(d.name); });

updated.select("text")
    .text(function(d) { return d.value + "%" });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM