Reputation: 400
I have the following data, using which i plotted a d3 tree, where each node is a rectangle. Now, I want to draw n circles on each rectangle(where n is value of 'minor'
in each node(see data), but not sure what's the easiest way to achieve this.
// Data
{
"minor": 1,
"critical": 0,
"children": [{
"minor": 2,
"critical": 0,
"children": [{
"minor": 3,
"critical": 0,
},
{
"minor": 2,
"critical": 1,
},
{
"minor": 1,
"critical": 1,
}]
}]
}
// JS
const nodeEnter = node.enter()
.append('g')
.attr('class', 'node')
.style('font-size', '12px')
.attr("transform", function (d) {
return "translate(" + source.y0 + "," + source.x0 + ")";
})
.on('click', click);
// Add Rectangle for the nodes
nodeEnter.append('rect')
.attr('class', 'node')
.attr("width", function (d) { return d.children || d._children ? 150 : 350 })
.attr("height", 70)
.attr('stroke', '#ccc')
.attr('stroke-width', '1');
Upvotes: 0
Views: 309
Reputation: 13129
You can use d3.range
to create an array of a specific length. Then you can treat this array just like any other d3 data structure.
const nCircles = 5;
const radius = 8;
const padding = 2;
d3.select('svg')
.selectAll('circle')
.data(d3.range(nCircles))
.enter()
.append('circle')
.attr('cx', function(_, i) {
return radius + padding + i * 2 * (radius + padding);
})
.attr('cy', radius + padding)
.attr('r', radius)
.attr('fill', 'darkred');
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>
Alternatively, you can use a fully ES6 solution, but it's unnecessarily complex:
const array = new Array(nCircles).fill(undefined).map(function(_, i) { return i; });
From your data, I gather that each node has the attributes minor
and critical
. Now, to update the balls of your newly inserted nodes, you can use
nodeEnter
.selectAll('.minor')
// Here you take the data from the node and transform it into
// the data for the circles. This is what makes it generic.
.data(function(d) { d3.range(d.minor))
.enter()
.append('circle')
.classed('minor', true)
.attr('cx', function(_, i) {
return radius + padding + i * 2 * (radius + padding);
})
.attr('cy', radius + padding)
.attr('r', radius)
.attr('fill', 'darkyellow');
// And for critical messages:
nodeEnter
.selectAll('.critical')
.data(function(d) { d3.range(d.critical))
.enter()
.append('circle')
.classed('critical', true)
.attr('cx', function(_, i) {
// To position it next to the minor circles, we need to
// know how many there are
const nMinorCircles = d3.select(this).select('.minor').size();
return radius + padding + 2 * (radius + padding) * (i + nMinorCircles);
})
.attr('cy', radius + padding)
.attr('r', radius)
.attr('fill', 'darkred');
Upvotes: 1