Chartjs-Chart.js Radial chart with arrow using Vue.js

1👍

Yes, it is possible.

  1. There might be already a plugin, that can achieve this (but I don’t know any, but I didn’t really look), so you could look for one,
  2. Or you could simply write your own plugin, with a few lines of code

Here a demo, how I would do this, with an inline plugin:
(three charts with 3 different percentages)

var arrowPlugin = {
    id: 'arrowPlugin',
    afterDraw: (chart, args, options) => {
        const { ctx } = chart;
        
        let midX = chart.width / 2;
        let midY = chart.height;
        let arrowLength = chart.height / 2;
        
        let text = `${options.value * 100}%`;
        let textSize = ctx.measureText(text);
        
        ctx.save();
        ctx.save();
        
        ctx.translate(midX, midY);
        ctx.rotate( (Math.PI * options.value)  - Math.PI /2);
        
        ctx.strokeStyle = options.arrowColor;
        ctx.fillStyle = options.arrowColor;
        ctx.lineCap = 'butt';
        
        ctx.lineWidth = 3;
        
        ctx.beginPath();
        ctx.moveTo(0, - arrowLength * 3 / 4 + 3)
        ctx.lineTo(0, - arrowLength * 6 / 4);
        ctx.stroke();
        
        ctx.beginPath();
        ctx.moveTo(0, - arrowLength * 6 / 4 - 4)
        ctx.lineTo(5, - arrowLength * 6 / 4 + 10)
        ctx.lineTo(-5, - arrowLength * 6 / 4  + 10)
        ctx.closePath();
        ctx.fill()
        
        
        ctx.fillStyle = options.triangleColor;
        ctx.beginPath();
        ctx.moveTo(0,   -midY + 25)
        ctx.lineTo(-10, -midY + 10)
        ctx.lineTo(10,  -midY + 10)
        ctx.closePath()
        ctx.fill();
        
        
        ctx.restore();
        

        ctx.fillStyle = options.textColor;
        ctx.font = "50px Arial";
        ctx.fillText(text, midX - textSize.width * 1.5, midY - 25);
        
        ctx.restore();
    },
    defaults: {
        // set here the percentage
        value:.50,
        arrowColor: 'black',
        textColor: 'black',
        triangleColor: 'black'
    }
}

var options1 = {
    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: 33,
      rotation: -90,
      circumference: 180,
      
      maintainAspectRatio: false,
      legend: { display: false },
      
      plugins:{ 
        tooltip: {  enabled: false },
      }
    }, 
    plugins:[arrowPlugin]
}

var options2 = {
    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: 33,
      rotation: -90,
      circumference: 180,
      
      maintainAspectRatio: false,
      legend: { display: false },
      
      plugins:{ 
        tooltip: {  enabled: false },
        // override default percentage
        arrowPlugin: { value: .20 }
      }
    }, 
    plugins:[arrowPlugin]
}

var options3 = {
    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: 33,
      rotation: -90,
      circumference: 180,
      
      maintainAspectRatio: false,
      legend: { display: false },
      
      plugins:{ 
        tooltip: {  enabled: false },
        // override default percentage
        arrowPlugin: { value: .70 }
      }
    }, 
    plugins:[arrowPlugin]
}

const chart1 = document.getElementById('chart1')
new Chart(chart1, options1);

const chart2 = document.getElementById('chart2')
new Chart(chart2, options2);

const chart3 = document.getElementById('chart3')
new Chart(chart3, options3);
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<div style="width:500px;height:184px">
   <canvas id="chart1" width="500" height="184"></canvas>
   <canvas id="chart2" width="500" height="184"></canvas>
   <canvas id="chart3" width="500" height="184"></canvas>
<div>

the percentage is currently set in the inline plugin-options, default value is set to .5 = 50% (valid range 0 – 1 = 0% – 100%).

Leave a comment