d3 pack布局圆圈在移动/尺寸转换后重叠

时间:2013-06-01 12:58:16

标签: javascript svg d3.js transition circle-pack

我使用数据集定期更新半径,使用包布局排列圆圈。

我开始使用的代码是气泡图的标准示例:http://bl.ocks.org/mbostock/4063269

enter image description here

每当圆圈大小发生变化时,它们就会转换。通常当圆圈生长时,它们会移动到与其他圆圈重叠。我不希望它们相互重叠。

我仍然是d3的新手,已经将代码移动了很多并尝试了我能想到的一切,但没有运气。

函数makeBubbles以原始Json传递(见下文)。

function makeBubbles(root){
  var diameter = $(window).width(),
      diameterh = $(window).height(),
      format = d3.format(",d"),
      color = d3.scale.category20();

  var bubble = d3.layout.pack()
      .sort(null)
      .size([diameter, diameterh])
      .value(function(d){return d.value; })
      .padding(1.5);

  var svg = d3.select("svg")
      .attr("width", diameter)
      .attr("height", diameterh)
      .attr("class", "bubble");

  var node = svg.selectAll(".node")
      .data(bubble.nodes(classes(root)).filter(function(d) { return !d.children; }),     function(d){  console.log(d); return d.className; });


  node.append("title")
      .text(function(d) { return d.className + ": " + format(d.value); });

  node.append("circle")
      .style("fill", function(d) { return color(d.packageName); })
      .on("click", function(d) { window.location = d.url; })
      .attr("r", 0)
      .transition()
      .duration(1000)
      .attr("r", function(d) { return d.r; });

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

  node.enter().append("g")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

  node.exit().transition().duration(200).attr("transform", "scale(0.001)").remove();

  node.append("text")
      .attr("dy", ".3em")
      .style("text-anchor", "middle")
      .text(function(d) { return d.className.substring(0, d.r / 6); })
      .attr("opacity",0)
      .transition().duration(1000)
      .attr("opacity",1);

// Returns a flattened hierarchy containing all leaf nodes under the root.
  function classes(root) {
    var classes = [];

    function recurse(name, node) {
      if (node.children) node.children.forEach(function(child) { recurse(node.name, child);     });
      else classes.push({packageName: name, className: node.name, value: node.size, url: node.url});
    }

    recurse(null, root);
    return {children: classes};
  }

  d3.select(self.frameElement).style("height", diameterh + "px");
}

传递的数据看起来像这样(随着数据集的更新而变化):

{"name":"bubbles","children":[{"name":"tourism","children":[{"name":"tourism","children":[{"name":"practical","children":[{"name":"ACCOMM","size":13,"url":"#"},{"name":"HIRE","size":2,"url":"#"}]},{"name":"activity","children":[{"name":"EVENT","size":6,"url":"#"},{"name":"TOUR","size":3,"url":"#"}]},{"name":"leisure","children":[{"name":"RESTAURANT","size":168,"url":"#"},{"name":"ATTRACTION","size":8,"url":"#"}]}]}]}]} 

1 个答案:

答案 0 :(得分:1)

我遇到了类似的问题。

我稍微修改了(大部分简化了)您的代码,here您可以找到工作示例。

我的方法不是使用转换。没有它们,代码看起来更易读和可维护。所以,我提出了一个简单的解决方案,我希望你可以在你的情况下使用它。

标签。过渡可能不是最好的,但你可以改变它。

在jsfiddle上,它无法集成json文件,因此数据在javascript中。在你的代码中,你需要处理加载json,但是我的例子中的核心思想可以不加改变地应用。

关键功能是:

function updateVis() {

    if (dataSource == 0)
        pack.value(function(d) { return d.size; });
    if (dataSource == 1)
        pack.value(function(d) { return 100; });
    if (dataSource == 2)
        pack.value(function(d) { return 1 +
                 Math.floor(Math.random()*501); });

    var data1 = pack.nodes(data);

    titles.attr("x", function(d) { return d.x; })
        .attr("y", function(d) { return d.y; })
        .text(function(d) {
            return (d.children ? "" : d.name + ": " + format(d.value));
        });

    circles.transition()
        .duration(5000)
        .attr("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; })
        .attr("r", function(d) { return d.r; });

    labels.transition()
        .duration(5000)
        .attr("opacity", 0) 
        .attr("x", function(d) { return d.x; })
        .attr("y", function(d) { return d.y; })
        .each("end", function(d){
            d3.select(this).text(function(d) {
                    return d.children ? "" : d.name.substring(0, d.r / 4);
                });
            d3.select(this).transition()
                .duration(1000)
                .attr("opacity", 1);
        });

};