solub
solub

Reputation: 1363

How to display interactively percentages in d3?

I'm trying to display the percentages of a polygonal shape within a radar graph by hovering on its name in the legend.

Here is a pic: enter image description here

You can see that the first brand name is being hovered over in the legend and that the corresponding polygonal shape in the graph is selected as a result. I'd like the shape to be surrounded by its values (in %) at each of its angles.

I wrote this code that puts all the percentages at the right places and set their opacity to 0

// percentages
                    var pourcents = g.selectAll(".pourcentage")
                                   .data(data)
                                   .enter()
                                   .append("g")
                                   .attr("class","pourcentage");


                          pourcents.selectAll(".pourcentagetext")
                                   .data(function(d,i) {return d[1]})
                                   .enter().append("text")          
                                   .text(function (d,i) { if (d.value == 0) {"fill", "none"} else {return Format(d.value)}})
                                   .attr("x", function(d,i){ return rScale(d.value + 0.05)* Math.cos(angleSlice*i - Math.PI/2) })
                                   .attr("y", function(d,i){ return rScale(d.value + 0.05) * Math.sin(angleSlice*i - Math.PI/2) })
                                   .attr("class", "pourcentagetext")
                                   .attr("id", function (d,i) {return "per" + i})
                                   .style("font-size", 10)
                                   .style("opacity", 0);

How can I select a group of percentages corresponding to a specific shape and make them appear with it ?

Edit: the code for the polygonal shapes:

blobWrapper.append("path")
                           .attr("class", "radarArea")
                           .attr("d", function(d,i) { return radarLine(d[1])})
                           .style("fill", function(d,i) { return color(i); })
                           .style("fill-opacity", cfg.opacityArea)
                           .attr("id", function (d,i) {return "tag" + i})

I operate the selection and make them appear by setting an id:

legende.on("mouseover", function(d, i, j) {d3.select("#tag" + i)
                                                          .transition()
                                                          .duration(100)
                                                          .style("fill-opacity", 1);

How can I do the same type of selection but with a group of corresponding percentages ?

Upvotes: 0

Views: 497

Answers (1)

KEKUATAN
KEKUATAN

Reputation: 948

Nice chart you have

How can I do the same type of selection but with a group of corresponding percentages ?

i said earlier you can add a class, select that class using

d3.selectAll(/*class_name*/).each(function(){})

then do something on each of that

if you using d3.select('id') you just select one element

that its why it work on path, not on text with using #per1,#per2 etc what its that? why you not name it with same class or group it?

see this. i hope you will understand

var data = [
            [[{name: "Bonpoint"}], [
                {axis: "Coton", value: 1},
                {axis: "Laine", value: 0.8},
                {axis: "Cachemire", value: 0.6},
                {axis: "Soie", value: 0.20},
                {axis: "Angora", value: 0.20},
                {axis: "Autres", value: 0.20},
                {axis: "Nylon", value: 0},
                {axis: "Acrylique", value: 0},
                {axis: "Viscose", value: 0},
                {axis: "Polyuréthane", value: 0},
                {axis: "Polyester", value: 0.20}]],

            [[{name: "Petit Bateau"}], [
                {axis: "Coton", value: 1},
                {axis: "Laine", value: 0.40},
                {axis: "Cachemire", value: 0},
                {axis: "Soie", value: 0},
                {axis: "Angora", value: 0},
                {axis: "Autres", value: 0},
                {axis: "Nylon", value: 0},
                {axis: "Acrylique", value: 0},
                {axis: "Viscose", value: 0},
                {axis: "Polyuréthane", value: 0},
                {axis: "Polyester", value: 0.20}]],

            [[{name: "Bobo Choses"}], [
                {axis: "Coton", value: 1},
                {axis: "Laine", value: 0.20},
                {axis: "Cachemire", value: 0},
                {axis: "Soie", value: 0},
                {axis: "Angora", value: 0},
                {axis: "Autres", value: 0},
                {axis: "Nylon", value: 0.40},
                {axis: "Acrylique", value: 0.40},
                {axis: "Viscose", value: 0},
                {axis: "Polyuréthane", value: 0},
                {axis: "Polyester", value: 0}]],

            [[{name: "BeBe"}], [
                {axis: "Coton", value: 0.40},
                {axis: "Laine", value: 0},
                {axis: "Cachemire", value: 0},
                {axis: "Soie", value: 0},
                {axis: "Angora", value: 0},
                {axis: "Autres", value: 0},
                {axis: "Nylon", value: 0.20},
                {axis: "Acrylique", value: 0.80},
                {axis: "Viscose", value: 0.40},
                {axis: "Polyuréthane", value: 0},
                {axis: "Polyester", value: 0.80}]],

            [[{name: "Familiar"}], [
                {axis: "Coton", value: 1},
                {axis: "Laine", value: 0.20},
                {axis: "Cachemire", value: 0},
                {axis: "Soie", value: 0},
                {axis: "Angora", value: 0},
                {axis: "Autres", value: 0},
                {axis: "Nylon", value: 0},
                {axis: "Acrylique", value: 0},
                {axis: "Viscose", value: 0},
                {axis: "Polyuréthane", value: 0},
                {axis: "Polyester", value: 0.40}]],

            [[{name: "Miki House"}], [
                {axis: "Coton", value: 1},
                {axis: "Laine", value: 0},
                {axis: "Cachemire", value: 0},
                {axis: "Soie", value: 0},
                {axis: "Angora", value: 0},
                {axis: "Autres", value: 0},
                {axis: "Nylon", value: 0},
                {axis: "Acrylique", value: 0},
                {axis: "Viscose", value: 0},
                {axis: "Polyuréthane", value: 0},
                {axis: "Polyester", value: 0.40}]],

            [[{name: "Uniqlo"}], [
                {axis: "Coton", value: 1},
                {axis: "Laine", value: 0.20},
                {axis: "Cachemire", value: 0},
                {axis: "Soie", value: 0},
                {axis: "Angora", value: 0},
                {axis: "Autres", value: 0},
                {axis: "Nylon", value: 0},
                {axis: "Acrylique", value: 0.20},
                {axis: "Viscose", value: 0},
                {axis: "Polyuréthane", value: 0.20},
                {axis: "Polyester", value: 0.40}]],

            [[{name: "Baby GAP"}], [
                {axis: "Coton", value: 1},
                {axis: "Laine", value: 0},
                {axis: "Cachemire", value: 0},
                {axis: "Soie", value: 0},
                {axis: "Angora", value: 0},
                {axis: "Autres", value: 0},
                {axis: "Nylon", value: 0},
                {axis: "Acrylique", value: 0.20},
                {axis: "Viscose", value: 0},
                {axis: "Polyuréthane", value: 0.20},
                {axis: "Polyester", value: 0.40}]],

            [[{name: "Lucien Zazou"}], [
                {axis: "Coton", value: 0.80},
                {axis: "Laine", value: 0},
                {axis: "Cachemire", value: 0},
                {axis: "Soie", value: 0},
                {axis: "Angora", value: 0},
                {axis: "Autres", value: 0},
                {axis: "Nylon", value: 0},
                {axis: "Acrylique", value: 0.20},
                {axis: "Viscose", value: 0.20},
                {axis: "Polyuréthane", value: 0},
                {axis: "Polyester", value: 0.60}]],

            ];


        var color = d3.scaleOrdinal().range(["#00baff", "#0014fe", "#00ff9c", "#f4bf02", "#ffa600", "#ff0000", "#ff00c4", "#ee693e", "#99958f"]);



        radarChart(".radarChart", data);



function radarChart(id, data, options) 
                    {
                      var cfg = {w: 700,
                          h: 700,
                          margin: {top: 20, right: 20, bottom: 20, left: 20},
                          levels: 5,
                          labelFactor: 1.35,
                          wrapWidth: 60,
                          opacityArea: 0.2,
                          dotRadius: 2,
                          opacityCircles: 0.1,
                          strokeWidth: 1,
                          roundStrokes: true,
                          areaName: "areaName",
                          ratio: 1.8,
                           
                          color:function(d){
                            return 'black'
                          }
                                }

                    if('undefined' !== typeof options) 
                          {for(var i in options)
                            {if ('undefined' !== typeof options[i]){cfg[i] = options[i]} } }


                     
                    var maxValue = d3.max(data, function(i){return d3.max(i[1].map(function(o) 
                                                  {return o.value}))} ); 

                    var minValue = d3.min(data, function(i) {return d3.min(i[1].map(function(o) {return o.value}))});

      

                   var areaName = cfg["areaName"];

                    // Variables for when creating the axis
                    var allAxis = (data[0][1].map(function(i, j) {return i.axis})),
                        total = allAxis.length, // autant d'axes que d''axis' indiqués dans data
                        radius = (cfg.h/3), //rayon du cercle le plus éloigné
                        innerRadius = (radius / cfg.levels) * cfg.ratio,
                        Format = d3.format('.0%'), //affiche en pourcentage, arrondi à l'entier
                        angleSlice = Math.PI * 2 / total; // L'écart entre chaque part de camembert




                    // Radius scale
                    var rScale =d3.scaleLinear().range([innerRadius,radius]).domain([0,maxValue]);


                    // Svg
                    var svg = d3.select("body")
                          .append("svg")
                          .attr("width", cfg.w + cfg.margin.left + cfg.margin.right)
                          .attr("height", cfg.h + cfg.margin.top + cfg.margin.bottom)
                          .attr("class", "radar");

   
                    // g
                    var g = svg.append("g")
                               .attr("transform", "translate(" + (cfg.w/2 + cfg.margin.left) + "," + (cfg.h/2 - cfg.margin.top) + ")");




                // GRID
                var axisGrid = g.append("g").attr("class", "axisWrapper");

                // Grid variables
                var inconnu = 2.13 //ratio: 1.8   
                var distance =  cfg.ratio * inconnu ;
                var step = distance / (cfg.levels + 1)


                // drawing the Grid
                axisGrid.selectAll(".levels")
                        .data(d3.range(0, distance, step)) //nombres et écart (1) de cercles à partir du centre 
                        .append("circle")
                        .attr("class", "gridCircle")
                        .attr("r", function(d, i){return innerRadius + (radius /cfg.levels * d)})
                        .style("fill", "white")
                        .style("stroke", "lightgrey")
                        .style("stroke-width", 0.2)
                        .style("fill-opacity", 0);



                // Axis displaying the percentages (not displayed atm)
                    axisGrid.selectAll(".axisLabel")
                            .data(d3.range(1, cfg.levels+1)) // à partir du 2è cercle jusqau'au 5ème
                            .enter()
                            .append("text")
                            .attr("class", "axisLabel")
                            .attr("x", -10)
                            .attr("y", function(d){return innerRadius + (radius /(cfg.levels * 1.575) * d)})
                            .attr("dy", "0.4em")
                            .style("font-size", "10px")
                            .attr("fill", "#737373")
                            .text(function(d,i) { return Format((d/cfg.levels))})
                            .style("display", "none");

                


                // Drawing the axis
                    var axis = axisGrid.selectAll(".axis")
                               .data(allAxis)
                               .enter()
                               .append("g")
                               .attr("class", "axis");

                    axis.append("line")
                        .attr("x1", function(d, i){return rScale(0) * Math.cos(angleSlice*i - Math.PI/2)  }) //x du point de départ des lignes
                        .attr("y1", function(d, i){return rScale(0) * Math.sin(angleSlice*i - Math.PI/2)  }) //y du points de départ des lignes
                        .attr("x2", function(d, i){ return rScale(maxValue) * Math.cos(angleSlice*i - Math.PI/2); })
                        .attr("y2", function(d, i){ return rScale(maxValue) * Math.sin(angleSlice*i - Math.PI/2); })
                        .attr("class", "line")
                        .style("stroke", "lightgrey")
                        .style("stroke-width", 1)
                        .attr("display", "none");


                  // Legend (brand names)
                  var legende =   svg.selectAll("noms")
                                   .data(data)
                                   .enter()
                                   .append("text")
                                   .text(function(d) {return d[0].map(function (o) {return o.name})})
                                   .attr("class", "legende")
                                   .style("font-family", "helvetica")
                                   .style("fill-opacity", 0.8)
                                   .attr("x",  0)
                                   .attr("y", function (d,i) {return 12 + i * 20})
                                   .attr("id", function (d,i) {return "leg" + i})
                                   .style("font-size", 10)
                                   .style("fill", function(d,i) { return color(i)})
                                   .style("opacity", 1);




                    // Put all the percentages at the right place (opacity set to 0 atm)
                    var pourcents = g.selectAll(".pourcentage")
                                   .data(data)
                                   .enter()
                                   .append("g")
                                   .attr('class',function(d) {return d[0].map(function (o,i) {return "pourcentage"+d.name})})

                                  // .attr("class","pourcentage");

                          
                          pourcents.selectAll(".pourcentagetext")
                                   .data(function(d,i) {return d[1]})
                                   .enter().append("text")          
                                   
                                   .attr("x", function(d,i){ return rScale(d.value + 0.05)* Math.cos(angleSlice*i - Math.PI/2) })
                                   .attr("y", function(d,i){ return rScale(d.value + 0.05) * Math.sin(angleSlice*i - Math.PI/2) })
                                   .attr("id", function (d,i) {return "per" + i})
                                   .attr("class", "per" + "pct" )
                                   .style("font-size", 10)
                                    .text(function (d,i) { if (d.value == 0) {"fill", "none"} else {return Format(d.value)}})
                                   .style("opacity", 0);



                  // Drawing the lines of the blobs (polygonal shapes)
                    var radarLine = d3.radialLine()
                                   .curve(d3.curveLinearClosed)
                                   .radius(function(d) { return rScale(d.value); })
                                   .angle(function(d,i) { return i*angleSlice });
                        

    
                        if(cfg.roundStrokes) {radarLine.curve(d3.curveLinearClosed)}
          

      


                var blobWrapper = g.selectAll(".radarWrapper")
                           .data(data)
                           .enter().append("g")
                           .attr("class", "radarWrapper");
            
                //mouseover
                var m_over= function(d,i,j){        
                    d3.selectAll(".radarArea")
                                                         .transition().duration(100)
                                                         .style("fill-opacity", 0);

                                                         d3.selectAll(".radarStroke")
                                                         .transition().duration(100)
                                                         .style("stroke-width", 0);

                                                        d3.select("#tag" + i)
                                                          .transition()
                                                          .duration(100)
                                                          .style("fill-opacity", 1);
                                                        
                                                        d3.selectAll(".cir" + i)
                                                          .transition()
                                                          .duration(100)
                                                          .style("fill-opacity", 1);
                                                        d3.selectAll(".cir_txt" + i)
                                                          .transition()
                                                          .duration(100)
                                                          .style("fill-opacity", 1);

                                                        d3.select(this).style("font-size", 12);
                                                        d3.selectAll(".cir_txt" + i).each(function (d,i) {return d3.select(this).style("opacity",1)})
                                                       d3.selectAll(".cir" + i).each(function (d,i) {return d3.select(this).style("opacity",1)})
                                                        d3.select("#tag" + i).each(function (d,i) {return d3.select("#per").style("opacity", 1)})
                  
                }
                
                var m_out= function(d, i) {d3.selectAll(".radarArea")
                                                         .transition().duration(500)
                                                         .style("fill-opacity", cfg.opacityArea);

                                                         d3.selectAll(".radarStroke")
                                                         .transition().duration(500)
                                                         .style("stroke-width", 0.1);
                                                          
                                                         d3.select("#tag" + i)
                                                          .transition()
                                                          .duration(700)
                                                          .style("fill-opacity", cfg.opacityArea);
                                                          
                                                          d3.selectAll(".cir" + i).each(
                                                          function(d,i){
                                                            return d3.select(this).style("opacity",0)
                                                          }).transition()
                                                          .duration(700)
                                                          .style("fill-opacity", cfg.opacityArea)
                                                          
                                                          d3.selectAll(".cir_txt" + i).each(
                                                          function(d,i){
                                                            return d3.select(this).style("opacity",0)
                                                          }).transition()
                                                          .duration(700)
                                                          .style("fill-opacity", cfg.opacityArea)
                                                          
                                                          
                                                          
                                                        }

         
                // Drawing the blobs 
                blobWrapper.append("g")
                .attr("id", function (d,i) {return "tog" + i})
                .append("path")
                           .attr("class", "radarArea")
                           .attr("d", function(d,i) { return radarLine(d[1])})
                           .style("fill", function(d,i) { return color(i); })
                           .style("fill-opacity", cfg.opacityArea)
                           .attr("id", function (d,i) {return "tag" + i})
                           .on("mouseover",m_over)

                           .on("mouseout",m_out); 


        

                // Drawing the strokes of the blobs
                blobWrapper.append("path")
                           .attr("class", "radarStroke")
                           .attr("d", function(d,i) { return radarLine(d[1]); })
                           .style("stroke-width", 0.1)
                           .style("stroke", function(d,i) { return color(i); })
                           .style("fill", "none")
                           .attr("id", function (d,i) {return "rad" + i});   

                

  
                // Add points (small circles) at every blobs angles (not displayed atm)
 
                      
                data.forEach(function(d,i){
                  var idx = i
                d3.select("#tog" + i).selectAll(".circle")
                         .data(function(d,i,j){return d[1]})
                         .enter()
                         
                         .append('circle')
                         .attr('class', 'cir'+i )
                         
               
                         
                    
                         
                         .attr("r", cfg.dotRadius)
                         .attr("cx", function(d,i){ return rScale(d.value) * Math.cos(angleSlice*i - Math.PI/2) })
                         .attr("cy", function(d,i){ return rScale(d.value) * Math.sin(angleSlice*i - Math.PI/2); })
                         .style("fill", function(d,i,j) { if  (d.value === 0) {return "none"} else {return cfg.color(j)}}) 
                         .style("fill-opacity", 0)
                          .style("fill",  color(idx))
                  
                  d3.select("#tog" + i).selectAll("text")
                  .data(function(d,i,j) {return d[1]})
                         .enter().append("text")
                         .attr('class', 'cir_txt'+i )
                         .attr("x", function(d,i){ return rScale(d.value) * Math.cos(angleSlice*i - Math.PI/2) })
                         .attr("y", function(d,i){ return rScale(d.value) * Math.sin(angleSlice*i - Math.PI/2); })
                         .style("fill", function(d,i,j) { if  (d.value == 0) {return "none"} else {return cfg.color(j)}}) 
                         .style("fill-opacity", 1)
                          .attr("dx", -25) 
                          //.attr("dy", -10) 
                            .attr("text-anchor", "right") 
                        .style("font-weight", "bold")
                
                         .text( function(d,i,j) { if  (d.value == 0) {return "none"} else {return Format(d.value)}})
                      .style("fill-opacity", 0);
                })


                
 				// Set a mouseover function for the legend
                  legende.on("mouseover",m_over)


                                                      
                          .on("mouseout",m_out);


                
                  // Add a white circle at the center, inside the inner circle
                  var centercircle = g.append("circle").attr("r", innerRadius + 1.5).raise().style("fill", "white").style("opacity", 1).style("stroke-width", 1).style("stroke", "lightgrey");


                 

                // Names of the textiles (one at the end of each axis)
                    axis.append("text")
                        .attr("class", "legend")
                        .style("font-size", "11px")
                        .attr("text-anchor", "middle")
                        .attr("dy", "0.35em")
                        .attr("x", function(d, i){ return rScale(maxValue * cfg.labelFactor) * Math.cos(angleSlice*i - Math.PI/2); })
                        .attr("y", function(d, i){ return rScale(maxValue * cfg.labelFactor) * Math.sin(angleSlice*i - Math.PI/2); })
                        .text(function(d){return d})
                        .attr("id", function(d,i) {return "mat" + i});
                
                      
                     
  
}
body {font-family: 'Open Sans', sans-serif;
          font-size: 11px;
          font-weight: 300;
          fill: #242424;
          text-align: center;
          cursor: default;}

      

        .legend {font-family: 'Open Sans', sans-serif;
               fill: #333333;}
      .tooltip {fill: #333333;}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.3/d3.min.js"></script>

  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>

   

<body>
     <div class="radarChart"></div>
</body>
</html>

Upvotes: 1

Related Questions