user159941
user159941

Reputation: 401

Adding more text to d3 pie chart on mouseover event

I am trying to figure out how to show more text on a pie chart using mouseover than just the data that is bound to the pie. Below is my functional code

function Pie(value,names){

svg.selectAll("g.arc").remove()

var outerRadius = 100;
        var innerRadius = 0;
        var arc = d3.svg.arc()
                .innerRadius(innerRadius)
                .outerRadius(outerRadius);

    var pie = d3.layout.pie();
    var color = d3.scale.category10();
    var arcs = svg.selectAll("g.arc")
              .data(pie(value))
              .enter()
              .append("g")
              .attr("class", "arc")
              .attr("transform", "translate(950,80)");

    arcs.append("path")
            .attr("fill", function(d, i) {
                return color(i);
            })
            .attr("d", arc)
            .on("mouseover",function(d,i) {
             arcs.append("text")
                .attr("dy", ".5em")
                .style("text-anchor", "middle")
                .style("fill", function(d,i){return "black";})
                .text(d.data)
            })

            .on("mouseout", function(d) {

                arcs.select("text").remove();
            });}

The names array has the same length as the value array which is passed to the pie. I really hoped that something like this would work by replacing the above mouseover.

.on("mouseover",function(d,i) {
             arcs.append("text")
                .attr("dy", ".5em")
                .style("text-anchor", "middle")
                .style("fill", function(d,i){return "black";})
                .text(function(d,i){return (d.data +" " + names[i]);)
            })

But the only thing it does is to show all the elements of the values array stacked one on top of the other and the last element of the names array. It seems that i is always the last index in this case. How would I go about that? Could I show the text I want in another way? Thank you in advance.

Upvotes: 1

Views: 4421

Answers (1)

Mark
Mark

Reputation: 108512

First, the variable arcs is a data-bound d3 selection which represents all the arcs of the pie. So, by calling arcs.append, you are going to append a text element for each piece of your pie chart. I think you mean to only append one text element based on what you moused-over so re-write that as:

svg.append('text')
  ...

Second, in this expression:

.text(function(d,i){return (d.data +" " + names[i]);)

d and i in the mouseover function already represent the data and index of the pie slice being moused over. There is no reason to wrap this in another function and should be re-written:

.text(d.data +" " + names[i]);

Here's a complete example:

<!DOCTYPE html>
<meta charset="utf-8">
<style>
  body {
    font: 10px sans-serif;
  }
  
  .arc path {
    stroke: #fff;
  }
</style>

<body>
  <script src="//d3js.org/d3.v3.min.js"></script>
  <script>
    var width = 960,
      height = 500,
      radius = Math.min(width, height) / 2;

    var color = d3.scale.category10();

    var arc = d3.svg.arc()
      .outerRadius(radius - 10)
      .innerRadius(0);

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

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

    var data = [{
      value: Math.random(),
    }, {
      value: Math.random(),
    }, {
      value: Math.random(),
    }, {
      value: Math.random(),
    }, {
      value: Math.random(),
    }]
    
    var names = ["A","B","C","D","E"];

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

    arcs.append("path")
      .attr("d", arc)
      .style("fill", function(d,i) {
        return color(i);
      })
      .on("mouseover", function(d, i) {
          console.log(d);
          svg.append("text")
            .attr("dy", ".5em")
            .style("text-anchor", "middle")
            .style("font-size", 45)
            .attr("class","label")
            .style("fill", function(d,i){return "black";})
            .text(names[i]);
          
      })
      .on("mouseout", function(d) {
        svg.select(".label").remove();
      });
    
  </script>

</body>

</html>

Upvotes: 3

Related Questions