d3.jsreusability

Make two pie charts with the same d3js code


I have a pie chart that was made with d3js.

The data is read from an url.

I want to use the same code to generate the chart, changing the colors of the chart and the data, but I am not managing to do it. In which regard changing the data, the only variable that change its name is earth_footprint, that will be IHD.

Here there is the fiddle of how the code is today. In this fiddle there are the div on where I want to have my second chart:

<div id="donut2"></div>

And the data that I want to use to the second chart is on this link.


Solution

  • make a function that encloses everything in your code and make two function calls

    function drawChart(url, id, key) {
      d3.json(url)
        .then(function(data) {
    
        data = data.filter(dataPoint => dataPoint.year == 2015);
    
          const heightValue = 300;
          const widthValue = 600;
          const strokeWidth = 1.5;
          const margin = {
            top: 0,
            bottom: 20,
            left: 30,
            right: 20
          };
          var width = 600 - margin.left - margin.right - (strokeWidth * 2);
              var height = 250 - margin.top - margin.bottom;
              var radius = Math.min(width, height) / 2;
    
             var color = d3.scaleOrdinal()
                  .range(["#e688a1", "#ed9a73", "#e3c878", "#64b2cd", "#e1b12c", "red", "green", "violet", "steelblue"]);
    
              var pie = d3.pie()
                  .value(function(d) {
                      return d[key];
                  })(data); 
    
    
               var arc = d3.arc()
                  .outerRadius(radius - 10)
                  .innerRadius(0);
    
              var svg =
                  d3
                  .select(id)
                  .append("svg")
                  .attr("viewBox", `0 0 ${widthValue} ${heightValue}`)
                  .append("g")
                  .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
    
      var g = svg.selectAll("arc")
                  .data(pie)
                  .enter().append("g")
                  .attr("class", "arc")
    
      g.on('mouseover', function(d, i) {
                      d3.select(this).transition()
                          .duration('50')
                          .attr('opacity', '.95')
                          .attr("stroke", "#23374d")
                      g.append("text")
                          .attr("class", "text remove")
                          .style("text-anchor", "middle")
                          .attr("stroke", "#23374d")
                          .attr("fill", "#23374d")
                          .text(d.data.country_name)
                  })
                  .on('mouseout', function(d, i) {
                      d3.select(this).transition()
                          .duration('50')
                          .attr('opacity', '1')
                          .attr("stroke", "none")
                      g.select(".text.remove").remove();
                  })
                  .attr('transform', 'translate(0, 0)');
    
       g.append("path")
                  .attr("d", arc)
                  .style("fill", function(d) {
                      return color(d.data.country_name);
                  });
       g
                  .append("text")
                  .attr("text-anchor", "middle")
                  .attr("x", function(d) {
                      var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
                      d.cx = Math.cos(a) * (radius - 45);
                      return d.x = Math.cos(a) * (radius + 30);
                  })
                  .attr("y", function(d) {
                      var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
                      d.cy = Math.sin(a) * (radius - 12);
                      return d.y = Math.sin(a) * (radius - 5);
                  })
                  .text(function(d) {
                      return d.value.toFixed(2);
                  })
                  .each(function(d) {
                      var bbox = this.getBBox();
                      d.sx = d.x - bbox.width / 2 - 2;
                      d.ox = d.x + bbox.width / 2 + 2;
                      d.sy = d.oy = d.y + 5;
                  });
    
          g.append("path")
                  .attr("class", "pointer")
                  .style("fill", "none")
                  .style("stroke", "#2c3e50")
                  .attr("d", function(d) {
                      if (d.cx > d.ox) {
                          return "M" + d.sx + "," + d.sy + "L" + d.ox + "," + d.oy + " " + d.cx + "," + d.cy;
                      } else {
                          return "M" + d.ox + "," + d.oy + "L" + d.sx + "," + d.sy + " " + d.cx + "," + d.cy;
                      }
                  });
    
    
    
      });
    }
    
    
    drawChart("https://raw.githubusercontent.com/cvrnogueira/CODWorkData/master/database/topfive/biggestEarthFootprint.json", 
    "#donut", 
    "earth_footprint"
    )
    drawChart("https://raw.githubusercontent.com/cvrnogueira/CODWorkData/master/database/topfive/biggestIHD.json",
    "#donut2", 
    "IHD"
    )
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width">
        <script src="https://d3js.org/d3.v5.min.js"></script>
        <title>JS Bin</title>
      </head>
    
      <body>
        <div id="donut"></div>
        <br>
        <br>
        <div id="donut2"></div>
      </body>
    
    </html>

    So your function now takes the url, the id upon which to load and the key you want to read from in the data.