有没有办法为 chart.js 中的饼图提供与各段之间的边框颜色不同的外边框颜色?

Is there a way to give a pie chart in chart.js a different color outer border than the border color between segments?

我正在使用 chart.js 在我正在构建的网页上绘制一些饼图。我希望馅饼看起来像这样,a visible border around the pie and between segments。

但偶尔,底层数据会将零值的数据点混入其中,这意味着图表看起来像这样 circle with a single line。

虽然我可以在存在零值数据点时关闭 borderWidth 属性,但会关闭整个饼图的 属性,meaning they look like this。

那么,有没有什么方法可以使只有一个数据点具有实际数据时,饼图本身仍然有边框?

或者当只有一个数据点具有实际数据时,将边框宽度 属性 设置为 0,然后在 canvas 中的饼图上画一个圆圈?

您可以将自定义内联插件与 borderWidth 本身的脚本化选项结合使用。

插件:

{
    id: 'circleAroundPieDoughnut',
    beforeDatasetsDraw: (chart, args, options) => {
      if (chart.data.datasets[0].data.length > 1) return;

      const {
        ctx,
        canvas
      } = chart;
      const {
        top,
        left,
        width,
        height
      } = chart.chartArea;
      const x = left + width / 2;
      const y = top + height / 2;
      const outerRadius = chart._metasets[0].data[0].outerRadius;

      ctx.beginPath()
      ctx.arc(x, y, outerRadius + ((options.width || 0) / 2), 0, 2 * Math.PI);
      ctx.lineWidth = options.width || 1
      ctx.strokeStyle = options.color || '#000';
      ctx.stroke();
    }
  }

实例:

var options = {
  type: 'doughnut',
  data: {
    labels: ["Red"],
    datasets: [{
      label: '# of Votes',
      data: [12],
      borderWidth: (ctx) => (ctx.chart.data.datasets[0].data.length === 1 ? 0 : 3),
      backgroundColor: ["Red"]
    }]
  },
  options: {
    radius: '98%',
    plugins: {
      legend: {
        display: false
      },
      circleAroundPieDoughnut: {
        width: 6, // Width of the border, defaults to 1
        color: 'blue' // Color of the border, defaults to black
      }
    }
  },
  plugins: [{
    id: 'circleAroundPieDoughnut',
    beforeDatasetsDraw: (chart, args, options) => {
      if (chart.data.datasets[0].data.length > 1) return;

      const {
        ctx,
        canvas
      } = chart;
      const {
        top,
        left,
        width,
        height
      } = chart.chartArea;
      const x = left + width / 2;
      const y = top + height / 2;
      const outerRadius = chart._metasets[0].data[0].outerRadius;

      ctx.beginPath()
      ctx.arc(x, y, outerRadius + ((options.width || 0) / 2), 0, 2 * Math.PI);
      ctx.lineWidth = options.width || 1
      ctx.strokeStyle = options.color || '#000';
      ctx.stroke();
    }
  }]
}

var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
  <canvas id="chartJSContainer" width="600" height="400"></canvas>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.3.0/chart.js"></script>
</body>

Fiddle: https://jsfiddle.net/Leelenaleee/us52em7f/18/

太棒了 - 我已经实现了这一点,但在函数绘制只有一个数据点的边界的情况下,似乎得到了一个稍微四四方方的圆圈,它超出了 canvas 的边界。关于如何解决的任何想法?

    function makepie(a,b,c,d){
 if (b <= 0) {n = 'n'} else {n = 'y'}
  if (c <= 0) {o = 'n'} else {o = 'y'}
  if (d <= 0) {p = 'n'} else {p = 'y'}
  q = n + o + p
  if (q == 'nnn') {s = [a];r = ['Indianred'];u = ['Emails']}
  if (q == 'yyy') {s = [a, b, c, d];r = ['Indianred', 'salmon', 'pink', 'mistyrose'];u = ['Emails','Calls','Meetings','Working']}
  if (q == 'ynn') {s = [a, b];r = ['Indianred', 'salmon'];u = ['Emails','Calls']}
  if (q == 'nyn') {s = [a, c];r = ['Indianred', 'pink', ];u = ['Emails','Working']}
  if (q == 'nny') {s = [a, d];r = ['Indianred', 'mistyrose'];u = ['Emails','Working']}
  if (q == 'yyn') {s = [a, b, c];r = ['Indianred', 'salmon', 'pink'];u = ['Emails','Calls','Meetings']}
  if (q == 'yny') {s = [a, b, d];r = ['Indianred', 'salmon', 'mistyrose'];u = ['Emails','Calls','Working']}
  if (q == 'nyy') {s = [a, c, d];r = ['Indianred', 'pink', 'mistyrose'];u = ['Emails','Meetings','Working']}
  var options = {
    type: 'pie',
    data: {
      labels: u,
      datasets: [{
        data: s,
        borderColor: '#6f6f6f',
        borderWidth: (ctx) => (ctx.chart.data.datasets[0].data.length === 1 ? 0 : 3),
        backgroundColor: r
      }]
    },
    options: {
        hover: {mode: null},
        animation: {duration: (Math.floor(Math.random() * 30) + 20) * 100},
        legend: {display: false,labels: {display: false}},
        rotation: (Math.floor(Math.random() * 5)+1),
        tooltips: {enabled: false},
        plugins: {
        legend: {display: false},
        circleAroundPieDoughnut: {
          width: 3,
          color: '#6f6f6f'
        }
      }
    },
    plugins: [{
      id: 'circleAroundPieDoughnut',
      beforeDatasetsDraw: (chart, args, options) => {
        if (chart.data.datasets[0].data.length > 1) return;

        var {
          ctx,
          canvas
        } = chart;
        var {
          top,
          left,
          width,
          height
        } = chart.chartArea;
        var x = left + width / 2;
        var y = top + height / 2;
        var outerRadius = chart._metasets[0].data[0].outerRadius;

        ctx.beginPath()
        ctx.arc(x, y, outerRadius + ((options.width || 0) / 2), 0, 2 * Math.PI);
        ctx.lineWidth = options.width || 1
        ctx.strokeStyle = options.color || '#000';
        ctx.stroke();
      }
    }],

  }

  var ctx = document.getElementById('chartJSContainer').getContext('2d');
  new Chart(ctx, options);
}

Fiddle: https://jsfiddle.net/theboyler/mp016df2/17/