I'm trying to change the alignment of the circle so that I can see the text in the middle Just like in this image.
I need help on how to align all the circles towards the circumference of the outer circle. I tried to add the text but it is overlapping with the circle in the center. Is it possible to change the alignment of the circle?
My code is mentioned below.
var root = {
"name": "flare",
"threat_level": "High",
"size": 15000,
"children": [{
"name": "Ghost",
"threat_level": "High",
"size": 1200
},
{
"name": "Wiper",
"threat_level": "Medium",
"size": 1330
},
{
"name": "PowerLiks",
"threat_level": "Medium",
"size": 1333
},
{
"name": "Fareit",
"threat_level": "Medium",
"size": 1300
},
{
"name": "Tribe",
"threat_level": "High",
"size": 1330
},
{
"name": "Oilrig",
"threat_level": "High",
"size": 1330
}
]
}
var svg = d3.select("svg"),
margin = 20,
diameter = +svg.attr("width"),
g = svg.append("g").attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");
const color = (type) => type == 'High' ? '#F72047' : (type == 'Medium' ? '#FFFFFF' : '#fff0') //colorScale
var defs = svg.append("defs");
var levels = ['High', 'Medium', 'Low']
levels.forEach((d) => {
//Create a radial Sun-like gradient
defs.append("radialGradient")
.attr("id", "sun-gradient_" + d)
.selectAll("stop")
.data([{
offset: "0%",
color: "#1A1D27"
},
{
offset: "80%",
color: "#1A1D27"
},
{
offset: "100%",
color: d == 'High' ? "#CB1F40" : "#959595"
}
])
.enter().append("stop")
.attr("offset", function (d) {
return d.offset;
})
.attr("stop-color", function (d) {
return d.color;
});
// .interpolate(d3.interpolateHcl);
})
var pack = d3.pack()
.size([diameter - margin, diameter - margin])
.padding(50);
root = d3.hierarchy(root)
.sum(function (d) {
return d.size;
})
.sort(function (a, b) {
return b.value - a.value;
});
var focus = root,
nodes = pack(root).descendants(),
view;
var circle = g.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("class", function (d) {
return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root";
})
.style("fill", (d) => `url(#${'sun-gradient_' + d.data.threat_level})`)
.style('stroke', (d) => color(d.data.threat_level))
.style('stroke-width', 1)
.on("click", function (e, d) {
if (focus !== d) zoom(d);
e.stopPropagation();
});
var text = g.selectAll("text")
.data(nodes)
.enter().append("text")
.attr("class", "label")
.text(function (d) {
return d.parent === root ? d.data.name : d.data.size;
})
.style('font-family', 'Metropolis Bold')
.style('font-size', (d) => d.parent === root ? '12px' : '24px')
.style('text-anchor', 'middle')
.style('fill', (d) => d.parent === root ? '#FFFFFF' : '#F72047')
.style('text-transform', 'uppercase')
var node = g.selectAll("circle,text");
svg
.style("background", color(-1))
.on("click", function () {
zoom(root);
});
zoomTo([root.x, root.y, root.r * 2 + margin]);
function zoom(d) {
var focus0 = focus;
focus = d;
var transition = d3.transition()
.duration(750)
.tween("zoom", function (d) {
var i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2 + margin]);
return function (t) {
zoomTo(i(t));
};
});
transition.selectAll("text")
.filter(function (d) {
return d.parent === focus || this.style.display === "inline";
})
.style("fill-opacity", function (d) {
return d.parent === focus ? 1 : 0;
})
.on("start", function (d) {
if (d.parent === focus) this.style.display = "inline";
})
.on("end", function (d) {
if (d.parent !== focus) this.style.display = "none";
});
}
function zoomTo(v) {
var k = diameter / v[2];
view = v;
node.attr("transform", function (d) {
return "translate(" + (d.x - v[0]) * k + "," + (d.y - v[1]) * k + ")";
});
circle.attr("r", function (d) {
return d.r * k;
});
}
<svg width="600" height="600"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
The packed circle layout is designed to take a group of objects and pack them as tightly as possible within a circle. So this isn't what you want.
If you want to arrange a set of objects evenly around the circumference of a circle with a given radius, you want something similar to a "radial tree layout". You can see an example of that in Chapter 6 of the book you linked to (Tree, Cluster, and Radial Layouts), though you'll not want the lines between the nodes.
There's also an example given in the answer to this question: d3.js - how to arrange the `squre` box around the `circle` properly
sin
and cos
Alternatively, you can divide the circumference of the circle by the number of objects you want to place, then use sin
and cos
to calculate their center point x and y manually.
There's an example of that here: d3.js radially position elements around an object
And a variation here: https://spin.atomicobject.com/2015/06/12/objects-around-svg-circle-d3-js/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With