How to display pie chart data values of each slice in chart.js

前端 未结 6 1318
执念已碎
执念已碎 2020-11-30 00:03

I am using Chart.js for drawing pie chart in my php page.I found tooltip as showing each slice values.

But I wish to display those values like below image.

相关标签:
6条回答
  • 2020-11-30 00:25

    @Hung Tran's answer works perfect. As an improvement, I would suggest not showing values that are 0. Say you have 5 elements and 2 of them are 0 and rest of them have values, the solution above will show 0 and 0%. It is better to filter that out with a not equal to 0 check!

              var val = dataset.data[i];
              var percent = String(Math.round(val/total*100)) + "%";
    
              if(val != 0) {
                ctx.fillText(dataset.data[i], model.x + x, model.y + y);
                // Display percent in another line, line break doesn't work for fillText
                ctx.fillText(percent, model.x + x, model.y + y + 15);
              }
    

    Updated code below:

    var data = {
        datasets: [{
            data: [
                11,
                16,
                7,
                3,
                14
            ],
            backgroundColor: [
                "#FF6384",
                "#4BC0C0",
                "#FFCE56",
                "#E7E9ED",
                "#36A2EB"
            ],
            label: 'My dataset' // for legend
        }],
        labels: [
            "Red",
            "Green",
            "Yellow",
            "Grey",
            "Blue"
        ]
    };
    
    var pieOptions = {
      events: false,
      animation: {
        duration: 500,
        easing: "easeOutQuart",
        onComplete: function () {
          var ctx = this.chart.ctx;
          ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal', Chart.defaults.global.defaultFontFamily);
          ctx.textAlign = 'center';
          ctx.textBaseline = 'bottom';
    
          this.data.datasets.forEach(function (dataset) {
    
            for (var i = 0; i < dataset.data.length; i++) {
              var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model,
                  total = dataset._meta[Object.keys(dataset._meta)[0]].total,
                  mid_radius = model.innerRadius + (model.outerRadius - model.innerRadius)/2,
                  start_angle = model.startAngle,
                  end_angle = model.endAngle,
                  mid_angle = start_angle + (end_angle - start_angle)/2;
    
              var x = mid_radius * Math.cos(mid_angle);
              var y = mid_radius * Math.sin(mid_angle);
    
              ctx.fillStyle = '#fff';
              if (i == 3){ // Darker text color for lighter background
                ctx.fillStyle = '#444';
              }
    
              var val = dataset.data[i];
              var percent = String(Math.round(val/total*100)) + "%";
    
              if(val != 0) {
                ctx.fillText(dataset.data[i], model.x + x, model.y + y);
                // Display percent in another line, line break doesn't work for fillText
                ctx.fillText(percent, model.x + x, model.y + y + 15);
              }
            }
          });               
        }
      }
    };
    
    var pieChartCanvas = $("#pieChart");
    var pieChart = new Chart(pieChartCanvas, {
      type: 'pie', // or doughnut
      data: data,
      options: pieOptions
    });
    
    0 讨论(0)
  • 2020-11-30 00:32

    For Chart.js 2.0 and up, the Chart object data has changed. For those who are using Chart.js 2.0+, below is an example of using HTML5 Canvas fillText() method to display data value inside of the pie slice. The code works for doughnut chart, too, with the only difference being type: 'pie' versus type: 'doughnut' when creating the chart.

    Script:

    Javascript

    var data = {
        datasets: [{
            data: [
                11,
                16,
                7,
                3,
                14
            ],
            backgroundColor: [
                "#FF6384",
                "#4BC0C0",
                "#FFCE56",
                "#E7E9ED",
                "#36A2EB"
            ],
            label: 'My dataset' // for legend
        }],
        labels: [
            "Red",
            "Green",
            "Yellow",
            "Grey",
            "Blue"
        ]
    };
    
    var pieOptions = {
      events: false,
      animation: {
        duration: 500,
        easing: "easeOutQuart",
        onComplete: function () {
          var ctx = this.chart.ctx;
          ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal', Chart.defaults.global.defaultFontFamily);
          ctx.textAlign = 'center';
          ctx.textBaseline = 'bottom';
    
          this.data.datasets.forEach(function (dataset) {
    
            for (var i = 0; i < dataset.data.length; i++) {
              var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model,
                  total = dataset._meta[Object.keys(dataset._meta)[0]].total,
                  mid_radius = model.innerRadius + (model.outerRadius - model.innerRadius)/2,
                  start_angle = model.startAngle,
                  end_angle = model.endAngle,
                  mid_angle = start_angle + (end_angle - start_angle)/2;
    
              var x = mid_radius * Math.cos(mid_angle);
              var y = mid_radius * Math.sin(mid_angle);
    
              ctx.fillStyle = '#fff';
              if (i == 3){ // Darker text color for lighter background
                ctx.fillStyle = '#444';
              }
              var percent = String(Math.round(dataset.data[i]/total*100)) + "%";      
              //Don't Display If Legend is hide or value is 0
              if(dataset.data[i] != 0 && dataset._meta[0].data[i].hidden != true) {
                ctx.fillText(dataset.data[i], model.x + x, model.y + y);
                // Display percent in another line, line break doesn't work for fillText
                ctx.fillText(percent, model.x + x, model.y + y + 15);
              }
            }
          });               
        }
      }
    };
    
    var pieChartCanvas = $("#pieChart");
    var pieChart = new Chart(pieChartCanvas, {
      type: 'pie', // or doughnut
      data: data,
      options: pieOptions
    });
    

    HTML

    <canvas id="pieChart" width=200 height=200></canvas>
    

    jsFiddle

    0 讨论(0)
  • 2020-11-30 00:32

    Easiest way to do this with Chartjs. Just add below line in options:

    pieceLabel: {
            fontColor: '#000'
        }
    

    Best of luck

    0 讨论(0)
  • 2020-11-30 00:43

    I found an excellent Chart.js plugin that does exactly what you want: https://github.com/emn178/Chart.PieceLabel.js

    0 讨论(0)
  • 2020-11-30 00:49

    From what I know I don't believe that Chart.JS has any functionality to help for drawing text on a pie chart. But that doesn't mean you can't do it yourself in native JavaScript. I will give you an example on how to do that, below is the code for drawing text for each segment in the pie chart:

    function drawSegmentValues()
    {
        for(var i=0; i<myPieChart.segments.length; i++) 
        {
            // Default properties for text (size is scaled)
            ctx.fillStyle="white";
            var textSize = canvas.width/10;
            ctx.font= textSize+"px Verdana";
    
            // Get needed variables
            var value = myPieChart.segments[i].value;
            var startAngle = myPieChart.segments[i].startAngle;
            var endAngle = myPieChart.segments[i].endAngle;
            var middleAngle = startAngle + ((endAngle - startAngle)/2);
    
            // Compute text location
            var posX = (radius/2) * Math.cos(middleAngle) + midX;
            var posY = (radius/2) * Math.sin(middleAngle) + midY;
    
            // Text offside to middle of text
            var w_offset = ctx.measureText(value).width/2;
            var h_offset = textSize/4;
    
            ctx.fillText(value, posX - w_offset, posY + h_offset);
        }
    }
    

    A Pie Chart has an array of segments stored in PieChart.segments, we can look at the startAngle and endAngle of these segments to determine the angle in between where the text would be middleAngle. Then we would move in that direction by Radius/2 to be in the middle point of the chart in radians.

    In the example above some other clean-up operations are done, due to the position of text drawn in fillText() being the top right corner, we need to get some offset values to correct for that. And finally textSize is determined based on the size of the chart itself, the larger the chart the larger the text.

    Fiddle Example


    With some slight modification you can change the discrete number values for a dataset into the percentile numbers in a graph. To do this get the total value of the items in your dataset, call this totalValue. Then on each segment you can find the percent by doing:

    Math.round(myPieChart.segments[i].value/totalValue*100)+'%';
    

    The section here myPieChart.segments[i].value/totalValue is what calculates the percent that the segment takes up in the chart. For example if the current segment had a value of 50 and the totalValue was 200. Then the percent that the segment took up would be: 50/200 => 0.25. The rest is to make this look nice. 0.25*100 => 25, then we add a % at the end. For whole number percent tiles I rounded to the nearest integer, although can can lead to problems with accuracy. If we need more accuracy you can use .toFixed(n) to save decimal places. For example we could do this to save a single decimal place when needed:

    var value = myPieChart.segments[i].value/totalValue*100;
    if(Math.round(value) !== value)
        value = (myPieChart.segments[i].value/totalValue*100).toFixed(1);
    value = value + '%';
    

    Fiddle Example of percentile with decimals

    Fiddle Example of percentile with integers

    0 讨论(0)
  • 2020-11-30 00:50

    You can make use of PieceLabel plugin for Chart.js.

    { pieceLabel: { mode: 'percentage', precision: 2 } }
    

    Demo | Documentation

    The plugin appears to have a new location (and name): Demo Docs.

    0 讨论(0)
提交回复
热议问题