Reputation: 716
I am attempting to position rectangles on d3js arcs at 0, 90, 180 and 270 degrees. Here is a simple example I put together that uses an arc generator to create 4 arcs and the arc.centroid function to place the rectangles at the center points of each arc:
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<title>Rotate rectangles to arc positions: 0, 90, 180 & 270 </title>
</head>
<style>
path {
fill: white;
stroke: black;
}
</style>
<body>
<svg width="700" height="220">
<g transform="translate(200, 110)"></g>
</svg>
<script src="https://d3js.org/d3.v5.min.js" charset="utf-8"></script>
<script>
// Create an arc generator with configuration
var arcGenerator = d3.arc()
.innerRadius(80)
.outerRadius(100);
var arcData = [
{startAngle: 0, endAngle: Math.PI * 2 / 4, degree: 0},
{startAngle: Math.PI * 2 / 4, endAngle: Math.PI, degree: 90},
{startAngle: Math.PI, endAngle: Math.PI * 3 / 2, degree: 180},
{startAngle: Math.PI * 3 / 2, endAngle: Math.PI * 2, degree: 270},
];
// Create a path element and set its d attribute
d3.select('g')
.selectAll('path')
.data(arcData)
.enter()
.append('path')
.attr('d', arcGenerator);
// Add labels, using .centroid() to position
d3.select('g')
.selectAll('rect')
.data(arcData)
.enter()
.append('rect')
.each(function(d) {
var centroid = arcGenerator.centroid(d);
d3.select(this)
.attr('x', centroid[0])
.attr('y', centroid[1])
.attr('width', 10)
.attr('height', 35)
});
</script>
</body>
</html>
Instead, I would like each rectangle to be placed at the start or end position of each arc and rotated so that each rectangle is portrait oriented (10 px wide and 35 px long).
Here is my: jsfiddle
Upvotes: 0
Views: 198
Reputation: 28713
Create arc data records for the angles you want and use the centroid()
for these dummy arcs
You have some illegal html after the g
element.
// Create an arc generator with configuration
var arcGenerator = d3.arc()
.innerRadius(80)
.outerRadius(100);
var arcData = [
{startAngle: 0, endAngle: Math.PI * 2 / 4, degree: 0},
{startAngle: Math.PI * 2 / 4, endAngle: Math.PI, degree: 90},
{startAngle: Math.PI, endAngle: Math.PI * 3 / 2, degree: 180},
{startAngle: Math.PI * 3 / 2, endAngle: Math.PI * 2, degree: 270},
];
var rectData = arcData.map(d => { return {startAngle: d.startAngle, endAngle:d.startAngle}; });
// Create a path element and set its d attribute
d3.select('g')
.selectAll('path')
.data(arcData)
.enter()
.append('path')
.attr('d', arcGenerator);
// Add labels, using .centroid() to position
d3.select('g')
.selectAll('.grect')
.data(rectData)
.enter()
.append('g')
.attr('class', 'grect')
.attr('transform', d => {
var centroid = arcGenerator.centroid(d);
return `translate(${centroid[0]},${centroid[1]})`;
})
.append('rect')
.attr('x', -5)
.attr('y', -17)
.attr('width', 10)
.attr('height', 35);
path {
fill: white;
stroke: black;
}
<meta charset="utf-8">
<head>
<title>Rotate rectangles to arc positions: 0, 90, 180 and 270 </title>
</head>
<body>
<svg width="700" height="220">
<g transform="translate(200, 110)"></g>
</svg>
<script src="https://d3js.org/d3.v5.min.js" charset="utf-8"></script>
</body>
Edit
You can create the rectData
on the fly.
d3.select('g')
.selectAll('.grect')
.data(arcData)
.enter()
.append('g')
.attr('class', 'grect')
.attr('transform', d => {
var centroid = arcGenerator.centroid({startAngle: d.startAngle, endAngle:d.startAngle});
return `translate(${centroid[0]},${centroid[1]})`;
})
.append('rect')
.attr('x', -5)
.attr('y', -17)
.attr('width', 10)
.attr('height', 35);
Upvotes: 1