Search code examples
d3.jschartsdata-visualizationangular7

Unable to adjust position and text (multi-line) of right side legend in D3js Donut chart


Hi I am trying to implement d3js donut chart in my angular 7 application. Here is the stackblitz link for the same :

https://stackblitz.com/edit/angular-with-d3js-charts-cne1eb?file=src%2Fapp%2Fapp.component.html

Current output which I am getting:

enter image description here

I am trying to adjust right side's legend position like this :

enter image description here

  1. right side legend needs to be vertically aligned properly
  2. Each square color box needs to circle
  3. Legend text should be multi-line.

I am unable to achieve this. Can anyone help me out with this ?

Thanks a ton in advance.


Solution

  • See the fixed code in the snippet below:

    var w = 583,
          h = 500,
          r = 150,
          inner = 180 / 2,
          color = d3
            .scaleOrdinal()
            .range([
              "rgb(3,17,142)",
              "rgb(19,37,180)",
              "rgb(37,58,217)",
              "rgb(55,78,255)",
              "rgb(94,113,255)",
              "rgb(133,147,254)",
              "rgb(210,215,252)",
            ]),
          margin = { top: 20, right: 20, bottom: 50, left: 100 };
    
        var data = [
          { label: "Received", value: 194 },
          { label: "Allocated", value: 567 },
          { label: "In Progress", value: 1314 },
          { label: "Cancelled", value: 793 },
          { label: "Returned", value: 1929 },
          { label: "Hold", value: 1383 },
          { label: "Rejected", value: 2 },
        ];
    
        var total = d3.sum(data, function (d) {
          return d3.sum(d3.values(d));
        });
    
        var svg = d3
          .select("#chart-1")
          .append("div")
          .classed("svg-container", true) //container class to make it responsive
          .append("svg") // Place the chart in 'pie-chart-div'
          .attr("preserveAspectRatio", "xMinYMin meet")
          .attr("viewBox", "0 0 600 500")
          .classed("svg-content-responsive", true)
          .attr("width", "100%")
          .attr("height", "100%");
        var vis = svg
          .data([data])
          .attr("width", "100%")
          .attr("height", "100%")
          .attr("viewBox", -w / 2 + " " + -h / 2 + " " + w + " " + h)
          .attr("preserveAspectRatio", "xMinYMin");
    
        var textTop = vis
            .append("text")
            .attr("dy", ".35em")
            .style("text-anchor", "middle")
            .attr("class", "textTop")
            .text("Total Orders")
            .attr("fill", "rgb(112,112,112)")
            .attr("y", -10),
          textBottom = vis
            .append("text")
            .attr("dy", ".35em")
            .attr("fill", "rgb(112,112,112)")
            .style("text-anchor", "middle")
            .attr("class", "textBottom")
            .text(total.toFixed(2) + "m")
            .attr("y", 10);
    
        var arc = d3.arc().innerRadius(inner).outerRadius(r);
    
        var arcOver = d3
          .arc()
          .innerRadius(inner + 5)
          .outerRadius(r + 5);
    
        var pie = d3.pie().value(function (d) {
          return d.value;
        });
    
        var arcs = vis
          .selectAll("g.slice")
          .data(pie)
          .enter()
          .append("svg:g")
          .attr("class", "slice")
          .on("mouseover", function (d) {
            d3.select(this)
              .select("path")
              .transition()
              .duration(200)
              .attr("d", arcOver);
    
            textTop.text(d3.select(this).datum().data.label).attr("y", -10);
            textBottom
              .text(d3.select(this).datum().data.value.toFixed(2))
              .attr("y", 10);
          })
          .on("mouseout", function (d) {
            d3.select(this)
              .select("path")
              .transition()
              .duration(100)
              .attr("d", arc);
    
            textTop.text("Total Orders").attr("y", -10);
            textBottom.text(total.toFixed(2) + "m");
          });
    
        arcs
          .append("svg:path")
          .style("fill", function (d, i) {
            return color(i);
          })
          .attr("d", arc);
    
        var legend = svg
          .append("g")
          .classed('legend', true)
          .selectAll("g")
          .data(data)
          .enter()
          .append("g")
    
          .attr("transform", function (d, i) {
            return "translate(" + (r + 20) + "," + ((i - data.length / 2) * 45 + 10) + ")";
          });
    
        legend
          .append("circle")
          .attr("r", 6)
          .attr('cy', 10)
          .attr('cx', 8)
          .style("fill", function (d, i) {
            return color(i);
          });
    
        legend
          .append("text")
          .attr("x", 24)
          .attr("y", 9)
          .attr("dy", ".35em")
          .attr("fill", "rgb(112,112,112)")
          .style('font-weight', 'bold')
          .text(function (d) {
            return d.label;
          });
        legend
          .append("text")
          .attr("x", 24)
          .attr("y", 30)
          .attr("fill", "rgb(112,112,112)")
          .text(d => `${d.value} orders`);
    .legend text {
      font-family: 'Ubuntu';
      font-size: 12px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <div id="chart-1" />

    Here is a forked Stackblitz: https://stackblitz.com/edit/angular-with-d3js-charts-fw9rkv