Reputation: 312
Small circles with different radius grouped in bigger circles
Here is what I have so far - one circle: 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);
})();
In order to make several circles I just do 'for' loop here: http://jsfiddle.net/dmitrychuba/hm72c74a/, but this way I have several SVG elements, which is not very good as I can't get them position like on image above(closer to each other). And also I will need few smaller solid circles plus future ability to zoom-in/out.
So my question is: is there a way to have multiple sets of circles on same SVG and with few solid circles and with ability to zoom-in/out?
Thanks Dmitry
Upvotes: 0
Views: 1138
Reputation: 14591
It is better to put all circle groups and individual circles inside a group element rather than putting them as separate SVG. Try as shown below.
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>
Upvotes: 2