2

I've got the doughnut part of the chart complete and the gauge needle. I want to add this circular pointer on the doughnut instead of the needle. I was able to draw the circular pointer but couldn't find the right X,Y coordinates to place the pointer.

Here is the DEMO

Here in the below image, the circle should be placed at the gauge needle pointer enter image description here

The code I've used is the following for the circular pointer.

const pointer = {
  id: "pointer",
  afterDatasetsDraw: (chart) => {
    const { ctx } = chart;

    var data = chart._metasets[0].data[0];

    var radius = data.innerRadius + (data.outerRadius - data.innerRadius) / 2;

    var centerX = data.x;
    var centerY = data.y;

    const angle = (180 / 1000) * speed;
    // this thing needs to be fixed
    var x = centerX + radius * Math.cos(angle * Math.PI);
    var y = centerY + radius * Math.sin(angle * Math.PI);

    ctx.save();

    ctx.beginPath();
    ctx.lineWidth = 6;
    ctx.arc(x, y, 12, 0, 2 * Math.PI);
    ctx.stroke();

    ctx.restore();
  }
};

Target to achive:

enter image description here

SKR Sama
  • 156
  • 1
  • 7

1 Answers1

1

Basically you want 75% of 180 Degrees (because the speed = 75):

const angle = Math.PI * ( speed / 100)  +  Math.PI;

And than Math.cos and Math.sin expect a radiant value(link to mdn documentation), which you already have, so no multiplication with Math.PI is needed anymore.

  var x = centerX + radius * Math.cos( angle );
  var y = centerY + radius * Math.sin( angle );

Full working demo (Updated Example, now with animation):

const speed = 75;
let animationAngle = 0;

var pointer = {
    id: 'pointer',
    defaults:{
     percentage: 0,
     maxAngle: 0
    },
    afterDraw: function(chart, args, opt) {
      const { ctx } = chart;

      var data = chart._metasets[0].data[0];
      var radius = data.innerRadius + (data.outerRadius - data.innerRadius) / 2;

      var centerX = data.x;
      var centerY = data.y;

      const angle = (Math.PI * ( speed / 100) * chart.options.plugins.pointer.percentage)  +  Math.PI;
      
      var x = centerX + radius * Math.cos( angle );
      var y = centerY + radius * Math.sin( angle );

      ctx.save();

      ctx.beginPath();
      ctx.lineWidth = 6;
      ctx.arc(x, y, 12, 0, 2 * Math.PI);
      ctx.stroke();

      ctx.restore();
    },
}

var options = {
    type: 'doughnut',
    data: {
    datasets: [{
        data: [20, 50, 30],
        backgroundColor: [
            'rgba(231, 76, 60, 1)',
            'rgba(255, 164, 46, 1)',
            'rgba(46, 204, 113, 1)'
        ],
        borderColor: [
            'rgba(255, 255, 255 ,1)',
            'rgba(255, 255, 255 ,1)',
            'rgba(255, 255, 255 ,1)'
        ],
        borderWidth: 0
    }]},
    options: {
      cutout: 80,
      rotation: -90,
      circumference: 180,
      animation:{
        onProgress: function(context){
            if(context.initial){
                this.options.plugins.pointer.percentage = context.currentStep / context.numSteps;
            }
        }
      },
      
      maintainAspectRatio: false,
      legend: { display: false },
      
      plugins:{ 
        tooltip: {  enabled: false },
        pointer: {currentAngle: 1}
      }
    }, 
    plugins:[pointer]
}

const chart = document.getElementById('chart1')
new Chart(chart, options);
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<div style="width:500px;height:184px">
   <canvas id="chart1" width="500" height="184"></canvas>
<div>
winner_joiner
  • 12,173
  • 4
  • 36
  • 61