使用D3.JS

时间:2015-10-17 04:38:26

标签: javascript d3.js force-layout

不同半径的小圆圈以较大的圆圈分组

以下是我到目前为止的内容 - 一个圈子:http://jsfiddle.net/dmitrychuba/hqy6q6qv/

(function () {
var rand = function (min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
};

var width = 400,
    height = 400,
    root = {
        "name": "A",
            "size": 12323,
            "children": [{
            "name": "B",
                "size": 3938
        }, {
            "name": "C",
                "size": 3812
        }, {
            "name": "D",
                "size": 6714
        }, {
            "name": "E",
                "size": 743
        }, {
            "name": "B1",
                "size": 3938
        }, {
            "name": "C1",
                "size": 3812
        }, {
            "name": "D1",
                "size": 6714
        }, {
            "name": "E1",
                "size": 743
        }, {
            "name": "B1",
                "size": 3938
        }, {
            "name": "C1",
                "size": 3812
        }, {
            "name": "D1",
                "size": 6714
        }, {
            "name": "E1",
                "size": 743
        }, {
            "name": "B1",
                "size": 3938
        }, {
            "name": "C1",
                "size": 3812
        }, {
            "name": "D1",
                "size": 6714
        }, {
            "name": "E1",
                "size": 743
        }, {
            "name": "B1",
                "size": 3938
        }, {
            "name": "C1",
                "size": 3812
        }, {
            "name": "D1",
                "size": 6714
        }, {
            "name": "E1",
                "size": 743
        }, {
            "name": "B1",
                "size": 3938
        }, {
            "name": "C1",
                "size": 3812
        }, {
            "name": "D1",
                "size": 6714
        }, {
            "name": "E1",
                "size": 743
        }, {
            "name": "B1",
                "size": 3938
        }, {
            "name": "C1",
                "size": 3812
        }, {
            "name": "D1",
                "size": 6714
        }, {
            "name": "E1",
                "size": 743
        }, {
            "name": "B1",
                "size": 3938
        }, {
            "name": "C1",
                "size": 3812
        }, {
            "name": "D1",
                "size": 6714
        }, {
            "name": "E1",
                "size": 743
        }, {
            "name": "B1",
                "size": 3938
        }, {
            "name": "C1",
                "size": 3812
        }, {
            "name": "D1",
                "size": 6714
        }, {
            "name": "E1",
                "size": 743
        }, {
            "name": "B1",
                "size": 3938
        }, {
            "name": "C1",
                "size": 3812
        }, {
            "name": "D1",
                "size": 6714
        }, {
            "name": "E1",
                "size": 743
        }, {
            "name": "B1",
                "size": 3938
        }, {
            "name": "C1",
                "size": 3812
        },

        ]
    };
var force = d3.layout.force()
    .linkDistance(function (d) {
    return 100;
}) // link distance between the nodes
.charge(-200) // charge that repel nodes from each other
.gravity(0.1)
    .size([width, height])
    .on("tick", tick);

var svg = d3.select("#main-container").append("svg")
    .attr("width", width)
    .attr("height", height);

var link = svg.selectAll(".link"),
    node = svg.selectAll(".node");
//Fix the position of the nodes and doesnt allow them to move out of the screen
flatten(root); //to set ids

update();

function update() {
    var nodes = flatten(root),
        links = d3.layout.tree().links(nodes);
    // Restart the force layout.
    force.nodes(nodes)
        .links(links)
        .start();


    // Update nodes.
    node = node.data(nodes, function (d) {
        return d.id;
    });

    node.exit().remove();

    var nodeEnter = node.enter().append("g")
        .attr("class", "node");

    //Adjusting the node sizes according to the children
    nodeEnter.append("circle")
        .style("display", function (d) {
        return d.children ? "none" : "";
    })
        .attr("stroke", 'black')
        .attr("r", function (d) {
        var r = rand(6, 18);
        return d._children ? d.size ? 14 : 18 : d.children ? 24 : r;
    });

    nodeEnter.append("text")
        .attr("dy", ".35em")
        .text(function (d) {
        return d.name;
    }).style("display", function (d) {
        return d.children ? "none" : "";
    })
        .style("font-size", function (d) {
        return 10;
    });

    node.select("circle")
        .style("fill", color);
}

function tick() {
    link.attr("x1", function (d) {
        return d.source.x;
    })
        .attr("y1", function (d) {
        return d.source.y;
    })
        .attr("x2", function (d) {
        return d.target.x;
    })
        .attr("y2", function (d) {
        return d.target.y;
    });

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

function color(d) {
    return "#fd8d3c";
}


// Returns a list of all nodes under the root.
function flatten(root) {
    var nodes = [],
        i = 0;

    function recurse(node) {
        if (node.children) node.children.forEach(recurse);
        if (!node.id) node.id = ++i;
        nodes.push(node);
    }

    recurse(root);
    return nodes;
}

setInterval(function () {
    force.alpha(.1);
}, 100);
})(); 

为了制作几个圈子,我只是为了#39;循环在这里:http://jsfiddle.net/dmitrychuba/hm72c74a/,但这样我有几个SVG元素,这不是很好,因为我不能让它们像上面的图像(彼此更接近)一样。而且我还需要一些较小的实心圆以及未来的放大/缩小功能。

所以我的问题是:有没有办法在同一个SVG上设置多组圆圈,并且几乎没有实心圆圈,并且能够放大/缩小?

由于 梅德

1 个答案:

答案 0 :(得分:2)

最好将所有圆组和单个圆放在一个组元素中,而不是将它们作为单独的SVG。尝试如下所示。

var rand = function(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
};

var width = 400,
  height = 400,
  root = {
    "name": "A",
    "size": 12323,
    "children": [{
        "name": "B",
        "size": 3938
      }, {
        "name": "C",
        "size": 3812
      }, {
        "name": "D",
        "size": 6714
      }, {
        "name": "E",
        "size": 743
      }, {
        "name": "B1",
        "size": 3938
      }, {
        "name": "C1",
        "size": 3812
      }, {
        "name": "D1",
        "size": 6714
      }, {
        "name": "E1",
        "size": 743
      }, {
        "name": "B1",
        "size": 3938
      }, {
        "name": "C1",
        "size": 3812
      }, {
        "name": "D1",
        "size": 6714
      }, {
        "name": "E1",
        "size": 743
      }, {
        "name": "B1",
        "size": 3938
      }, {
        "name": "C1",
        "size": 3812
      }, {
        "name": "D1",
        "size": 6714
      }, {
        "name": "E1",
        "size": 743
      }, {
        "name": "B1",
        "size": 3938
      }, {
        "name": "C1",
        "size": 3812
      }, {
        "name": "D1",
        "size": 6714
      }, {
        "name": "E1",
        "size": 743
      }, {
        "name": "B1",
        "size": 3938
      }, {
        "name": "C1",
        "size": 3812
      }, {
        "name": "D1",
        "size": 6714
      }, {
        "name": "E1",
        "size": 743
      }, {
        "name": "B1",
        "size": 3938
      }, {
        "name": "C1",
        "size": 3812
      }, {
        "name": "D1",
        "size": 6714
      }, {
        "name": "E1",
        "size": 743
      }, {
        "name": "B1",
        "size": 3938
      }, {
        "name": "C1",
        "size": 3812
      }, {
        "name": "D1",
        "size": 6714
      }, {
        "name": "E1",
        "size": 743
      }, {
        "name": "B1",
        "size": 3938
      }, {
        "name": "C1",
        "size": 3812
      }, {
        "name": "D1",
        "size": 6714
      }, {
        "name": "E1",
        "size": 743
      }, {
        "name": "B1",
        "size": 3938
      }, {
        "name": "C1",
        "size": 3812
      }, {
        "name": "D1",
        "size": 6714
      }, {
        "name": "E1",
        "size": 743
      }, {
        "name": "B1",
        "size": 3938
      }, {
        "name": "C1",
        "size": 3812
      },

    ]
  };

var zoom = d3.behavior.zoom()
  .scaleExtent([1, 10])
  .on("zoom", zoomed);
var color = d3.scale.category10();
var svg = d3.select("#main-container").append("svg")
  .attr("width", width * 3)
  .attr("height", height * 2)
  .call(zoom);
var mainContainer = svg.append("g");

function zoomed() {
  mainContainer.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
var positions = [
  [0, 0],
  [width, 0],
  [width * 2, 0],
  [width - 200, height],
  [width * 2 - 200, height]
];

function addCircle(x, y) {
  mainContainer.append("circle")
    .style("fill", "#3D91B2")
    .attr("cx", x)
    .attr("cy", y)
    .attr("r", 50);
}
addCircle(width, height - 70);
addCircle(width * 2, height - 70);


for (var i = 0; i < 5; i++)
  (function() {
    var force = d3.layout.force()
      .linkDistance(function(d) {
        return 100;
      }) // link distance between the nodes
      .charge(-200) // charge that repel nodes from each other
      .gravity(0.1)
      .size([width, height])
      .on("tick", tick);

    var gContainer = mainContainer.append("g")
      .attr("transform", "translate(" + positions[i][0] + "," + positions[i][1] + ")");

    var link = gContainer.selectAll(".link"),
      node = gContainer.selectAll(".node");
    //Fix the position of the nodes and doesnt allow them to move out of the screen
    flatten(root); //to set ids

    update(i);

    function update(colorIdx) {
      var nodes = flatten(root),
        links = d3.layout.tree().links(nodes);
      // Restart the force layout.
      force.nodes(nodes)
        .links(links)
        .start();


      // Update nodes.
      node = node.data(nodes, function(d) {
        return d.id;
      });

      node.exit().remove();

      var nodeEnter = node.enter().append("g")
        .attr("class", "node");

      //Adjusting the node sizes according to the children
      nodeEnter.append("circle")
        .style("display", function(d) {
          return d.children ? "none" : "";
        })
        .attr("stroke", 'black')
        .attr("r", function(d) {
          var r = rand(6, 18);
          return d._children ? d.size ? 14 : 18 : d.children ? 24 : r;
        });

      nodeEnter.append("text")
        .attr("dy", ".35em")
        .text(function(d) {
          return d.name;
        }).style("display", function(d) {
          return d.children ? "none" : "";
        })
        .style("font-size", function(d) {
          return 10;
        });
      node.select("circle")
        .style("fill", color(colorIdx));
    }

    function tick() {
      link.attr("x1", function(d) {
          return d.source.x;
        })
        .attr("y1", function(d) {
          return d.source.y;
        })
        .attr("x2", function(d) {
          return d.target.x;
        })
        .attr("y2", function(d) {
          return d.target.y;
        });

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


    // Returns a list of all nodes under the root.
    function flatten(root) {
      var nodes = [],
        i = 0;

      function recurse(node) {
        if (node.children) node.children.forEach(recurse);
        if (!node.id) node.id = ++i;
        nodes.push(node);
      }

      recurse(root);
      return nodes;
    }

  })();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="main-container"></div>