Chart.js (v3) 带圆边的甜甜圈,但不是到处都是

Chart.js (v3) Doughnut with rounded edges, but not everywhere

我知道对此有几个答案,但这个似乎有点不同。我需要更改甜甜圈图,将第一个和最后一个也四舍五入。因此,在我的示例中,黑色(第一个数据集)只会在开头(一侧)四舍五入,而灰色(最后一个数据集)会在最后四舍五入,如图所示。

当然,这是Chart.js的最新版本(v3)。

我使用了这里的一些代码:

也许使用自定义图表会更好,但我什至无法做到这一点。

到目前为止,这是我的代码。只使第一个数据集四舍五入,不幸的是它的两边。

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>

我已经修改了您的代码并针对 roundedCornersFor 进行了更改。它现在将采用一个对象结构,该结构将定义以 startend 作为键,值将是根据标签的弧位置。

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

下面是完整的代码片段:

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>