Search code examples
javascriptcanvaschartschart.jsgauge

Chartjs-gauge create circumference until certain value from data


I am creating 5 sections of gauge using chartjs-gauge. I am using the following data.

[150,200,250,300,400]

From this data, I want to display the circumference until 300. But the angle should calculated by including the last section value too. I had custom the text showing in section by setting it to empty string if more than 300. For section colour, I set 4 colours["green", "yellow", "orange", "red"]. Now, last section showing as silver colour which is default background of gauge. I have add rgba(0,0,0,0) to colour array ["green", "yellow", "orange", "red","rgba(0,0,0,0)"] which will show transparent colour for last section. But, when hover on section, it is responsive showing border. I would like to know if have other way to show the circumference until certain value from our data ,but calculating section area in chart using all value from data.

var data = [150, 200, 250, 300, 400];

var config = {
  type: "gauge",
  data: {
    labels: ['Success', 'Warning', 'Warning', 'Error'],
    datasets: [{
      data: data,
      value: 300,
      backgroundColor: ["green", "yellow", "orange", "red"],
      borderWidth: 2
    }]
  },
  options: {
    responsive: true,
    title: {
      display: true,
      text: "Gauge chart with datalabels plugin"
    },
    layout: {
      padding: {
        bottom: 30
      }
    },
    needle: {
      // Needle circle radius as the percentage of the chart area width
      radiusPercentage: 2,
      // Needle width as the percentage of the chart area width
      widthPercentage: 3.2,
      // Needle length as the percentage of the interval between inner radius (0%) and outer radius (100%) of the arc
      lengthPercentage: 80,
      // The color of the needle
      color: "rgba(0, 0, 0, 1)"
    },

    valueLabel: {
      formatter: Math.round
    },
    plugins: {
      datalabels: {
        display: true,
        formatter: function(value, context) {
          //return '>'+value;
          if (value <= 300) {
            return value;
          } else {
            return '';
          }

        },
        color: function(context) {
          //return context.dataset.backgroundColor;
          return 'black';
        },
        //color: 'rgba(255, 255, 255, 1.0)',
        /*backgroundColor: "rgba(0, 0, 0, 1.0)",*/
        borderWidth: 0,
        borderRadius: 5,
        font: {
          weight: "bold"
        }
      }

    }
  }
};

window.onload = function() {
  var ctx = document.getElementById("chart").getContext("2d");
  window.myGauge = new Chart(ctx, config);
};
canvas {
  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en-US">
<head>
  <script src="jQuery/jquery-3.4.1.min.js"></script>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Gauge Chart with datalabels plugin</title>
  <script src="https://unpkg.com/[email protected]/dist/Chart.bundle.js"></script>
  <script src="https://unpkg.com/[email protected]/dist/chartjs-gauge.js"></script>
  <script src="https://unpkg.com/[email protected]/dist/chartjs-plugin-datalabels.js"></script>
</head>
<body>
  <div id="canvas-holder" style="width:100%">
    <canvas id="chart"></canvas>
  </div>
</body>
</html>


Solution

  • var data = [150, 200, 250, 300, 400];
    colour_array = ["#11d8ee", "#3cc457", "#f12b0e", "#dda522", "#808080"];
    let sum = data.reduce(function(a, b) {
      return a + b;
    }, 0);
    
    var perc = 0;
    perc_array = [];
    for (i = 0; i < data.length; i++) {
      perc = (data[i] / sum * 100).toFixed(2);
      perc_array.push(perc);
    }
    
    Chart.plugins.register({ //increase distance between legend and chart
      id: 'paddingBelowLegends',
      beforeInit: function(chart, options) {
        chart.legend.afterFit = function() {
          this.height = this.height + 50; //custom 50 to value you wish
        };
      }
    });
    //when want to disable this plugin in other chart, paddingBelowLegends: false in plugin{}   
    var config = {
      type: "doughnut",
      data: {
        labels: ['A', 'B', 'C', 'D', 'Others'],
        datasets: [{
          data: data,
          value: data[(colour_array.length - 1)], //300
          backgroundColor: colour_array,
          borderWidth: 2
        }]
      },
      options: {
        responsive: true,
        cutoutPercentage: 60,//thickness of chart
        title: {
          display: true,
          text: "Gauge chart with datalabels plugin"
        },
        layout: {
          padding: {
            bottom: 30
          }
        },
        valueLabel: {
          formatter: Math.round,
          display: false // hide the label in center of gauge
        },
        plugins: {
          beforeInit: function(chart, options) {
            chart.legend.afterFit = function() {
              this.height = this.height + 50;
            };
          },
          outlabels: {
            display: true,
            //text: '%l %v %p',//(label value percentage)the percentage automatically roundoff   
            //hide chart text label for last section-https://github.com/Neckster/chartjs-plugin-piechart-outlabels/issues/10#issuecomment-716606369    
            text: function(label) {
              console.log(label);
              highest_index = label['labels'].length - 1; //get highest index from the labels array
              current_index = label['dataIndex']; //current index
              value = label['dataset']['data'][label['dataIndex']]; //value of current index
              const v = parseFloat(label['percent']) * 100;
              if (current_index != highest_index) //to hide last section text label on chart.
              {
                //return value + ' , ' + `${v.toFixed(2)}%`;
                return value+',\n'+`${v.toFixed(2)}%`;
              } else {
                return false;
              }
            },
    
            color: 'white',
            stretch: 12, //length of stretching
            font: {
              resizable: true,
             minSize: 10,
             maxSize: 14
            },
            padding: {
              /*left:25,
              right: 0
              top:0,
              bottom:0*/
            }
          },
          //inner label:
          datalabels: { //label on arc section
            display: false,
            formatter: function(value, context) {
              if (value <= data[(colour_array.length - 2)]) //hide datalabel for last section
              {
                id = data.indexOf(value);
                perc = perc_array[id];
                return value + ' , ' + perc + '%';
              } else {
                return '';
              }
            },
            color: function(context) {
              return 'black';
            },
            borderWidth: 0,
            borderRadius: 10,
            font: {
              weight: "bold",
            },
            anchor: "end" //'center' (default): element center, 'start': lowest element boundary, 'end': highest element boundary
          }
        },
        legend: { //filter last section from legend chart labels
          display: true,
          //position: 'right',
          labels: {
            filter: function(legendItem, data) {
              //ori-return legendItem !=1;
              return !legendItem.text.includes('Others');
            },
            boxWidth: 20
          }
        },
        rotation: 1 * Math.PI,
        circumference: 1 * Math.PI,
        tooltips: {
          enabled: true,
          mode: 'single',
          filter: function(tooltipItem, data) { //disable display tooltip in last section
            var label = data.labels[tooltipItem.index];
            if (label == "Others") {
              return false;
            } else {
              return true;
            }
          },
          callbacks: { //custom tooltip text to show percentage amount (by default,showing real amount)
            label: function(tooltipItem, data) {
              var dataset = data.datasets[tooltipItem.datasetIndex];
              hovered_index = tooltipItem.index;
              data_length = data.datasets[0].data.length;
              var total = dataset.data.reduce(function(previousValue, currentValue, currentIndex, array) {
                return previousValue + currentValue;
              });
              var currentValue = dataset.data[tooltipItem.index];
              var percentage = (currentValue / total * 100).toFixed(2);
              return currentValue + ' , ' + percentage + "%";
            }
          }
        }
      }
    };
    
    window.onload = function() {
      var ctx = document.getElementById("chartJSContainer").getContext("2d");
      window.myGauge = new Chart(ctx, config);
    };
    <html>
    
    <head>
      <script src="https://unpkg.com/[email protected]/dist/Chart.bundle.js"></script>
      <script src="https://unpkg.com/[email protected]/dist/chartjs-gauge.js"></script>
      <script src="https://unpkg.com/[email protected]/dist/chartjs-plugin-datalabels.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-piechart-outlabels"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    </head>
    
    <body>
      <div id="canvas-holder" style="width:50% align:center">
        <canvas id="chartJSContainer"></canvas>
      </div>
    </body>
    
    </html>