如何向 Chart.js 圆环图显示第二组标签?

How to show second set of labels to Chart.js doughtnut chart?

我按照 SO 上的其他问题成功添加了第二组标签。

但现在我想显示所有标签的图例,但第二组标签被划掉了。如何避免这种情况?

这是我的尝试: https://jsfiddle.net/L5gs39u2/1/

  var platform_labels = ["Tablet","Ordenador"];
  var platform_dataset = [14,5];
  var os_labels = ["Android","Windows","GNU\/Linux"];
  var os_dataset = [14,4,1];
  var devices_labels = ["Tablet","Ordenador","Android","Windows","GNU\/Linux"];
  
  
  var chartColors = {
      red: 'rgb(255, 99, 132)',
      orange: 'rgb(255, 159, 64)',
      yellow: 'rgb(255, 205, 86)',
      green: 'rgb(75, 192, 192)',
      blue: 'rgb(54, 162, 235)',
      purple: 'rgb(153, 102, 255)',
      grey: 'rgb(201, 203, 207)'
  };


  var config = {
      type: 'doughnut',
      data: {
          datasets: [{
              data: platform_dataset,
              backgroundColor: [
                  chartColors.red,
                  chartColors.orange,
                  chartColors.yellow
              ],
              label: 'Platform',
              labels: platform_labels
          }, {
              data: os_dataset,
              backgroundColor: [
                  chartColors.purple,
                  chartColors.green,
                  chartColors.blue
              ],
              label: 'OS',
              labels: os_labels
          }],
          labels: devices_labels
      },
      options: {
          tooltips: {
              callbacks: {
                  label: function (tooltipItem, data) {
                      var dataset = data.datasets[tooltipItem.datasetIndex];
                      var index = tooltipItem.index;
                      return dataset.labels[index] + ": " + dataset.data[index];
                  }
              }
          }
      }
  };
  var ctx = document.getElementById('deviceChart').getContext('2d');
  var employeesGraph = new Chart(ctx, config);

第二组标签被删除线,因为 chartjs 将它们视为隐藏的,即它们没有值,因此不会呈现,并且标签仅从第一个数据集中绘制。

有几种解决方法,您可以禁用图例,然后创建自定义图例,但我不确定这是否会获取所有标签:

var chart = new Chart(ctx, {
        type: 'line',
        data: data,
        options: {
            legend: {
                display: false
            },
            legendCallback: function(chart) {
                var text = [];
                text.push('<ul>');
                for (var i=0; i<devices_labels.length; i++) {
                    text.push('<li>');
                    text.push('<span style="background-color:' + 
                    chart.data.datasets[i].borderColor + '">' + devices_labels[i] + 
                    '</span>');
                    text.push('</li>');
                }
                text.push('</ul>');
                return text.join("");
            }
        }
    });

或者您可以扩展 chartjs 以更改隐藏数据标签的行为:- change legend item style when dataset is hidden

或者最简单的方法是将一些虚拟数据添加到您的第一个数据集中:-

var platform_labels = ["Tablet","Ordenador"];
  var platform_dataset = [14, 5, 0, 0, 0];
  var os_labels = ["Android","Windows","GNU\/Linux"];
  var os_dataset = [14,4,1];
  var devices_labels = ["Tablet","Ordenador","Android","Windows","GNU\/Linux"];
  
  
      var chartColors = {
          red: 'rgb(255, 99, 132)',
          orange: 'rgb(255, 159, 64)',
          yellow: 'rgb(255, 205, 86)',
          green: 'rgb(75, 192, 192)',
          blue: 'rgb(54, 162, 235)',
          purple: 'rgb(153, 102, 255)',
          grey: 'rgb(201, 203, 207)'
      };


      var config = {
          type: 'doughnut',
          data: {
              datasets: [{
                  data: platform_dataset,
                  backgroundColor: [
                      chartColors.red,
                      chartColors.orange,
                      chartColors.purple,
                      chartColors.green,
                      chartColors.blue
                  ],
                  label: 'Platform',
                  labels: platform_labels
              }, {
                  data: os_dataset,
                  backgroundColor: [
                      chartColors.purple,
                      chartColors.green,
                      chartColors.blue
                  ],
                  label: 'OS',
                  labels: os_labels
              }],
              labels: devices_labels
          }
      };
      var ctx = document.getElementById('deviceChart').getContext('2d');
      var employeesGraph = new Chart(ctx, config);

您必须通过定义一个 legend.labels.generateLabels function together with a legend.onClick 函数来自己生成图例标签,该函数负责隐藏和显示各个饼图切片。这可能如下所示:

legend: {
  labels: {
    generateLabels: () => {
      let labels = [];
      config.data.datasets.forEach((ds, iDs) => labels = labels.concat(ds.labels.map((l, iLabel) => ({
        datasetIndex: iDs,
        labelIndex: iLabel,
        text: l,
        fillStyle: ds.backgroundColor[iLabel],
        hidden: employeesGraph ? employeesGraph.getDatasetMeta(iDs).data[iLabel].hidden : false,
        strokeStyle: '#fff'
      }))));
      return labels;
    }
  },
  onClick: (event, legendItem) => {
    const metaData = employeesGraph.getDatasetMeta(legendItem.datasetIndex).data;
    metaData[legendItem.labelIndex].hidden = !metaData[legendItem.labelIndex].hidden;
    employeesGraph.update();
  }
},

请查看下面修改后的代码:

var platform_labels = ["Tablet", "Ordenador"];
var platform_dataset = [14, 5];
var os_labels = ["Android", "Windows", "GNU\/Linux"];
var os_dataset = [14, 4, 1];
var devices_labels = ["Tablet", "Ordenador", "Android", "Windows", "GNU\/Linux"];

var chartColors = {
  red: 'rgb(255, 99, 132)',
  orange: 'rgb(255, 159, 64)',
  yellow: 'rgb(255, 205, 86)',
  green: 'rgb(75, 192, 192)',
  blue: 'rgb(54, 162, 235)',
  purple: 'rgb(153, 102, 255)',
  grey: 'rgb(201, 203, 207)'
};

var config = {
  type: 'doughnut',
  data: {
    datasets: [{
      data: platform_dataset,
      backgroundColor: [
        chartColors.red,
        chartColors.orange,
      ],
      label: 'Platform',
      labels: platform_labels
    }, {
      data: os_dataset,
      backgroundColor: [
        chartColors.purple,
        chartColors.green,
        chartColors.blue
      ],
      label: 'OS',
      labels: os_labels
    }],
    labels: devices_labels
  },
  options: {
    legend: {
      labels: {
        generateLabels: () => {
          let labels = [];
          config.data.datasets.forEach((ds, iDs) => labels = labels.concat(ds.labels.map((l, iLabel) => ({
            datasetIndex: iDs,
            labelIndex: iLabel,
            text: l,
            fillStyle: ds.backgroundColor[iLabel],
            hidden: employeesGraph ? employeesGraph.getDatasetMeta(iDs).data[iLabel].hidden : false,
            strokeStyle: '#fff'
          }))));
          return labels;
        }
      },
      onClick: (event, legendItem) => {
        const metaData = employeesGraph.getDatasetMeta(legendItem.datasetIndex).data;
        metaData[legendItem.labelIndex].hidden = !metaData[legendItem.labelIndex].hidden;
        employeesGraph.update();
      }
    },
    tooltips: {
      callbacks: {
        label: function(tooltipItem, data) {
          var dataset = data.datasets[tooltipItem.datasetIndex];
          var index = tooltipItem.index;
          return dataset.labels[index] + ": " + dataset.data[index];
        }
      }
    }
  }
};
var ctx = document.getElementById('deviceChart').getContext('2d');
var employeesGraph = new Chart(ctx, config);
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.js"></script>
<canvas id="deviceChart" height="120"></canvas>