ewilan
ewilan

Reputation: 716

Rotating rectangles on an arc in D3js

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>

Here is the result:image showing rectangles at the centroid position of each arc

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

Answers (1)

rioV8
rioV8

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

Related Questions