Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to draw a needle on a custom donut chart and add datapoints to the needle?

I'm created a custom gauge chart using Chart.js, Laravel and Bootstrap 3, now I'm trying to draw a needle and display the datasets with the needle. Here is what I've done so far and I get the gauge to display, however I can't get the needle to display and I'm not sure how to attach data to the needle. Thank you all in advance.

var oilCanvas = document.getElementById("oilChart");

Chart.defaults.global.defaultFontFamily = "Lato";
Chart.defaults.global.defaultFontSize = 18;

var oilData = {
  labels: [],
  datasets: [{
    data: [35, 35, 35],
    backgroundColor: [
      'rgba(255, 99, 132, 0.2)',
      'rgba(255, 206, 86, 0.2)',
      'rgba(63, 191, 63, 0.2)'
    ],

    borderWidth: ""
  }]
};

var chartOptions = {
  rotation: -Math.PI,
  cutoutPercentage: 30,
  circumference: Math.PI,
  legend: {
    position: 'left'
  },
  animation: {
    animateRotate: false,
    animateScale: true
  }
};

function drawNeedle(radius, radianAngle) {
  var canvas = document.getElementById("oilChart");
  var ctx = canvas.getContext('2d');
  var cw = canvas.offsetWidth;
  var ch = canvas.offsetHeight;
  var cx = cw / 2;
  var cy = ch - (ch / 4);

  ctx.translate(cx, cy);
  ctx.rotate(radianAngle);
  ctx.beginPath();
  ctx.moveTo(0, -5);
  ctx.lineTo(radius, 0);
  ctx.lineTo(0, 5);
  ctx.fillStyle = 'rgba(0, 76, 0, 0.8)';
  ctx.fill();
  ctx.rotate(-radianAngle);
  ctx.translate(-cx, -cy);
  ctx.beginPath();
  ctx.arc(cx, cy, 7, 0, Math.PI * 2);
  ctx.fill();
}

var pieChart = new Chart(oilCanvas, {
  type: 'doughnut',
  data: oilData,
  options: chartOptions
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<div>
  <canvas id="oilChart"></canvas>
</div>
like image 443
Simona Buga Avatar asked Oct 27 '25 04:10

Simona Buga


1 Answers

You can use the Plugin Core API that offers a range of hooks that may be used for performing custom code. The afterDraw hook may be used to draw the needle directly on the canvas through CanvasRenderingContext2D.

First we need to define the property needleValue inside the dataset.

datasets: [{
  data: [35, 35, 35],
  needleValue: 580,
  ...
}],

The solution is based on the code sample provided by Konstantin S.. Please have a look at your amended code below.

new Chart('oilChart', {
  type: 'doughnut',
  plugins: [{
    afterDraw: chart => {
      var needleValue = chart.chart.config.data.datasets[0].needleValue;
      var dataTotal = chart.chart.config.data.datasets[0].data.reduce((a, b) => a + b, 0);
      var angle = Math.PI + (1 / dataTotal * needleValue * Math.PI);
      var ctx = chart.chart.ctx;
      var cw = chart.chart.canvas.offsetWidth;
      var ch = chart.chart.canvas.offsetHeight;
      var cx = cw / 2;
      var cy = ch - 6;

      ctx.translate(cx, cy);
      ctx.rotate(angle);
      ctx.beginPath();
      ctx.moveTo(0, -3);
      ctx.lineTo(ch - 20, 0);
      ctx.lineTo(0, 3);
      ctx.fillStyle = 'rgb(0, 0, 0)';
      ctx.fill();
      ctx.rotate(-angle);
      ctx.translate(-cx, -cy);
      ctx.beginPath();
      ctx.arc(cx, cy, 5, 0, Math.PI * 2);
      ctx.fill();
    }
  }],
  data: {
    labels: [],
    datasets: [{
      data: [35, 35, 35],
      needleValue: 27,
      backgroundColor: [
        'rgba(255, 99, 132, 0.2)',
        'rgba(255, 206, 86, 0.2)',
        'rgba(63, 191, 63, 0.2)'
      ]
    }]
  },
  options: {
    layout: {
      padding: {
        bottom: 3
      }
    },
    rotation: -Math.PI,
    cutoutPercentage: 30,
    circumference: Math.PI,
    legend: {
      position: 'left'
    },
    animation: {
      animateRotate: false,
      animateScale: true
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="oilChart" height="80"></canvas>
like image 85
uminder Avatar answered Oct 29 '25 18:10

uminder



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!