TheChosenOne94
TheChosenOne94

Reputation: 103

move a slice of the pie chart using d3.js

In the code below, a simple pie chart is created, but I am not able to move one slice towards the outer side of the chart when selected.

I want the individual (element) slice to be positioned outer the pie and the rest of the pie chart elements(slices) in its usual position, something like this:

enter image description here

Here is my code:

<!DOCTYPE html>


<body>
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <script>
    var data = [35, 20, 45];

    var width = 300,
      height = 300,
      radius = 150;

    var arc = d3.arc()
      .outerRadius(130);

    var arcLabel = d3.arc()
      .outerRadius(radius - 30)
      .innerRadius(radius - 20);


    var pie = d3.pie()
      .value(function(d) {
        return d;
      });


    var svg = d3.select("body").append("svg")
      .attr("width", width)
      .attr("height", height)
      .append("g")
      .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");


    var emptyPies = svg.selectAll(".arc")
      .data(pie(data))
      .enter()
      .append("g")
      .attr("class", "arc")



    emptyPies.append("path")
      .attr("d", arc)
      .style("fill", function(d, i) {
        return color[i];
      })


    emptyPies.append("text")
      .attr("transform", function(d) {
        return "translate(" + arcLabel.centroid(d) + ")";
      })
      .text(function(d) {
        return d.data;
      });

  </script>

Upvotes: 2

Views: 2475

Answers (2)

Keval Bhatt
Keval Bhatt

Reputation: 1

A simple solution is to use multiple arc() but to do slice we can use arc.centroid() of 2nd arc. The following code will work in v5.

  function onDrawPieChart() {
    var data = [35, 20, 45];
    var color = d3.schemeCategory10;
    var width = 600;
    var height = 600;
    var radius = 100;

    var pie = d3.pie().value((d) => d);
    var arc = d3.arc().innerRadius(0).outerRadius(130);
    var arc2 = d3.arc().innerRadius(0).outerRadius(20);
    var slicedIndex = 1;
    var pieData = pie(data);
    var centroid = arc2.centroid(pieData[slicedIndex]);
    var svg = d3
      .select("body")
      .append("svg")
      .attr("viewBox", [-width / 2, -height / 2, width, height].join(" "))
      .attr("width", width)
      .attr("height", height)
      .append("g");

    svg
      .selectAll("path")
      .data(pieData)
      .join("path")
      .attr("fill", (d, i) => color[i])
      .attr("d", (d) => arc(d))
      .attr("transform", (d, i) => {
        if (i === slicedIndex) {
          var [x, y] = centroid;
          return "translate(" + x + ", " + y + ")";
        }
      });
  }

Upvotes: 0

Gerardo Furtado
Gerardo Furtado

Reputation: 102194

A simple solution is creating a different arc generator:

var arc2 = d3.arc()
    .outerRadius(radius)
    .innerRadius(60);

And, when setting the "d" attribute, choosing which arc generator to use. For instance, moving the red slice:

emptyPies.append("path")
    .attr("d", function(d,i){
        return i != 1 ? arc(d) : arc2(d);
})

Here is your code with that change:

<!DOCTYPE html>
<style>
  .arc text {
    text-anchor: middle;
  }
  
  .arc path {
    stroke: white;
  }

</style>

<body>
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <script>
    var data = [35, 20, 45];

    var width = 300,
      height = 300,
      radius = Math.min(width, height) / 2;


    var color = ["brown", "red", "blue"];

    var arc = d3.arc()
      .outerRadius(radius - 10)
      .innerRadius(50);
      
    var arc2 = d3.arc()
      .outerRadius(radius)
      .innerRadius(60);

    var arcLabel = d3.arc()
      .outerRadius(radius - 30)
      .innerRadius(radius - 20);


    var pie = d3.pie()
      .value(function(d) {
        return d;
      });


    var svg = d3.select("body").append("svg")
      .attr("width", width)
      .attr("height", height)
      .append("g")
      .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");


    var emptyPies = svg.selectAll(".arc")
      .data(pie(data))
      .enter()
      .append("g")
      .attr("class", "arc")



    emptyPies.append("path")
      .attr("d", function(d,i){
      return i != 1 ? arc(d) : arc2(d);})
      .style("fill", function(d, i) {
        return color[i];
      })


    emptyPies.append("text")
      .attr("transform", function(d) {
        return "translate(" + arcLabel.centroid(d) + ")";
      })
      .text(function(d) {
        return d.data;
      });

  </script>

Upvotes: 1

Related Questions