0

I know there are a few answer for this, but it seems this one is a bit different. I need to change doughnut chart, rounded the first one and the last but one too. So in my example the black (first dataset) only would be rounded on the beginning (one side) and the gray (last but one) would be rounded at the end, like on the picture. enter image description here

Of course, this is the latest version (v3) of Chart.js.

I used some code from here: Chart.js Doughnut with rounded edges and text centered

Maybe it's better with a custom chart, but I couldn't even get this far with that.

This is my code so far. Only makes rounded the first dataset and unfortunately both sided of it.

Chart.defaults.elements.arc.borderWidth = 0;
Chart.defaults.elements.arc.roundedCornersFor = 0;
Chart.defaults.elements.arc.hoverBorderColor = 'white';

Chart.defaults.datasets.doughnut.cutout = '85%';

var doughnutChart = document.getElementById('doughnutChart');

if(doughnutChart) {
    new Chart(doughnutChart, {
        type: 'doughnut',
    
        // The data for our dataset
        data: {
            labels: [
                'Label 1',
                'Label 2',
                'Label 3',
                'Label 4'
              ],
              datasets: [{
                label: 'My First Dataset',
                data: [22, 31, 26, 19],
                backgroundColor: [
                  '#000000',
                  '#ffff00',
                  '#aaaaaa',
                  '#ff0000'
                ]
            }]
        },
        plugins: [
            {
                afterUpdate: function(chart) {
                    if (chart.options.elements.arc.roundedCornersFor !== undefined) {
                        var arc = chart.getDatasetMeta(0).data[chart.options.elements.arc.roundedCornersFor];
                        
                        arc.round = {
                            x: (chart.chartArea.left + chart.chartArea.right) / 2,
                            y: (chart.chartArea.top + chart.chartArea.bottom) / 2,
                            radius: (arc.outerRadius + arc.innerRadius) / 2,
                            thickness: (arc.outerRadius - arc.innerRadius) / 2,
                            backgroundColor: arc.options.backgroundColor
                        }
                    }
                },
                afterDraw: (chart) => {
                    if (chart.options.elements.arc.roundedCornersFor !== undefined) {
                        var {ctx, canvas} = chart;
                        var arc = chart.getDatasetMeta(0).data[chart.options.elements.arc.roundedCornersFor];

                        var startAngle = Math.PI / 2 - arc.startAngle;
                        var endAngle = Math.PI / 2 - arc.endAngle;
        
                        ctx.save();
                        ctx.translate(arc.round.x, arc.round.y);
                        ctx.fillStyle = arc.round.backgroundColor;
                        ctx.beginPath();
                        ctx.arc(arc.round.radius * Math.sin(startAngle), arc.round.radius * Math.cos(startAngle), arc.round.thickness, 0, 2 * Math.PI);
                        ctx.arc(arc.round.radius * Math.sin(endAngle), arc.round.radius * Math.cos(endAngle), arc.round.thickness, 0, 2 * Math.PI);
                        ctx.closePath();
                        ctx.fill();
                        ctx.restore();
                    }
                }
            }
        ]
    });
}
.container {
  width: 400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.3.2/chart.min.js"></script>
<div class="container">
  <canvas id="doughnutChart"></canvas>
</div>
levipadre
  • 569
  • 7
  • 31
  • Does this answer your question? [Chart.js Doughnut with rounded edges](https://stackoverflow.com/questions/36934967/chart-js-doughnut-with-rounded-edges) – User863 Jun 14 '21 at 10:13

1 Answers1

2

I have modified your code and made changes for roundedCornersFor. It will now take an object structure which will define take start and end as keys and the values will be the arc positions which are according to labels.

Chart.defaults.elements.arc.roundedCornersFor = {
  "start": 0, //0th position of Label 1
  "end": 2 //2nd position of Label 2
};

Below is the entire code snippet:

Chart.defaults.elements.arc.borderWidth = 0;
Chart.defaults.elements.arc.roundedCornersFor = {
  "start": 0, //0th position of Label 1
  "end": 2 //2nd position of Label 2
};

//Can be provided as array:
//Chart.defaults.elements.arc.roundedCornersFor = {
//  "start": [0,1,2],
//  "end": 3
//};

Chart.defaults.elements.arc.hoverBorderColor = 'white';

Chart.defaults.datasets.doughnut.cutout = '85%';

var chartInstance = new Chart(document.getElementById("chartJSContainer"), {
  type: 'doughnut',

  // The data for our dataset
  data: {
    labels: [
      'Label 1',
      'Label 2',
      'Label 3',
      'Label 4'
    ],
    datasets: [{
      label: 'My First Dataset',
      data: [22, 31, 26, 19],
      backgroundColor: [
        '#000000',
        '#ffff00',
        '#aaaaaa',
        '#ff0000'
      ]
    }]
  },
  //Inline Options...
  /*  options: {
    elements: {
      arc: {
        roundedCornersFor: {
          "start": 1, //0th position of Label 1
          "end": 1 //2nd position of Label 2
        }
      }
    }
  }, */
  plugins: [{
    afterUpdate: function(chart) {
      if (chart.options.elements.arc.roundedCornersFor !== undefined) {
        var arcValues = Object.values(chart.options.elements.arc.roundedCornersFor);

        arcValues.forEach(function(arcs) {
          arcs = Array.isArray(arcs) ? arcs : [arcs];
          arcs.forEach(function(i) {
            var arc = chart.getDatasetMeta(0).data[i];
            arc.round = {
              x: (chart.chartArea.left + chart.chartArea.right) / 2,
              y: (chart.chartArea.top + chart.chartArea.bottom) / 2,
              radius: (arc.outerRadius + arc.innerRadius) / 2,
              thickness: (arc.outerRadius - arc.innerRadius) / 2,
              backgroundColor: arc.options.backgroundColor
            }
          });
        });
      }
    },
    afterDraw: (chart) => {

      if (chart.options.elements.arc.roundedCornersFor !== undefined) {
        var {
          ctx,
          canvas
        } = chart;
        var arc,
          roundedCornersFor = chart.options.elements.arc.roundedCornersFor;
        for (var position in roundedCornersFor) {
          var values = Array.isArray(roundedCornersFor[position]) ? roundedCornersFor[position] : [roundedCornersFor[position]];
          values.forEach(p => {
            arc = chart.getDatasetMeta(0).data[p];
            var startAngle = Math.PI / 2 - arc.startAngle;
            var endAngle = Math.PI / 2 - arc.endAngle;
            ctx.save();
            ctx.translate(arc.round.x, arc.round.y);
            ctx.fillStyle = arc.options.backgroundColor;
            ctx.beginPath();
            if (position == "start") {
              ctx.arc(arc.round.radius * Math.sin(startAngle), arc.round.radius * Math.cos(startAngle), arc.round.thickness, 0, 2 * Math.PI);
            } else {
              ctx.arc(arc.round.radius * Math.sin(endAngle), arc.round.radius * Math.cos(endAngle), arc.round.thickness, 0, 2 * Math.PI);
            }
            ctx.closePath();
            ctx.fill();
            ctx.restore();
          });

        };
      }
    }
  }]
});
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.3.1/dist/chart.js"></script>

<body>
  <canvas id="chartJSContainer" width="200" height="200"></canvas>
</body>
wahab memon
  • 2,193
  • 2
  • 10
  • 23
  • Just one remaining question. What if I want to define the rounded corner values within config? Like `elements: {arc: {roundedCornersFor: {'start': 0,'end': 1}}},` It doesn't override. – levipadre Jun 14 '21 at 15:53
  • it doesn't for me unfortunately, but I keep trying. And it's also weird, that on hover (e.g. gray section), the background color doesn't change along with the other part. – levipadre Jun 14 '21 at 16:04
  • 1
    I have updated my answer and added inline options so in config the `roundedCorners` part will work and didn't understood your point about 'background doesn't change'. – wahab memon Jun 14 '21 at 16:17
  • Thanks again! I meant that when you roll over the gray area, it will become darker expect a circle at the end where it connects to the red area. – levipadre Jun 14 '21 at 16:21
  • 1
    I have updated that part in my code, so if you run the snippet the round and hover arc color will match. You will need to understand the logic and make changes accordingly from here on. – wahab memon Jun 14 '21 at 16:46