chart.js:在饼图外显示标签

Sve*_*erg 13 javascript charts chart.js

chart.js 2.6.0

我需要渲染一个如下所示的图表:

在此输入图像描述

始终显示所有工具提示是不可接受的方式,因为它们不会以适当的方式呈现:

在此输入图像描述

不幸的是我找不到解决方案了.我已经尝试了片标签插件,但这有同样的问题,因为它的标签重叠,我无法隐藏某些标签.

这是代码,它使用piece-label创建我的图表以将标签定位在切片上方:

private createStatusChart(): void {
    const chartData = this.getStatusChartData();

    if (!chartData) {
        return;
    }

    const $container = $(Templates.Dashboard.ChartContainer({
        ContainerID: 'chart-status',
        HeaderText: 'Status'
    }));

    this._$content.append($container);

    const legendOptions =
        new Model.Charts.LegendOptions()
            .SetDisplay(false);

    const pieceLabelOptions =
        new Model.Charts.PieceLabelOptions()
            .SetRender('label')
            .SetPosition('outside')
            .SetArc(true)
            .SetOverlap(true);

    const options =
         new Model.Charts.Options()
             .SetLegend(legendOptions)
             .SetPieceLabel(pieceLabelOptions);

    const chartDefinition = new Model.Charts.Pie(chartData, options);
    const ctx = this._$content.find('#chart-status canvas').get(0);

    const chart = new Chart(ctx, chartDefinition);
}

private getStatusChartData(): Model.Charts.PieChartData {
    if (!this._data) {
        return;
    }

    const instance = this;
    const data: Array<number> = [];
    const labels: Array<string> = [];
    const colors: Array<string> = [];

    this._data.StatusGroupings.forEach(sg => {
        if (!sg.StatusOID) {
            data.push(sg.Count);
            labels.push(i18next.t('Dashboard.NoStateSet'));
            colors.push('#4572A7');

            return;
        }

        const status = DAL.Properties.GetByOID(sg.StatusOID);

        data.push(sg.Count);
        labels.push(status ? status.Title : i18next.t('Misc.Unknown'));
        colors.push(status ? status.Color : '#fff');
    });

    const dataset = new Model.Charts.Dataset(data).setBackgroundColor(colors);

    return new Model.Charts.PieChartData(labels, [dataset]);
}
Run Code Online (Sandbox Code Playgroud)

结果:

在此输入图像描述

小智 9

有一个新插件(从一年开始),叫做chartjs-plugin-piechart-outlabels

只需导入源
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-piechart-outlabels"></script>
并将其与 outlabeledPie 类型一起使用

var randomScalingFactor = function() {
return Math.round(Math.random() * 100);
};
var ctx = document.getElementById("chart-area").getContext("2d");
var myDoughnut = new Chart(ctx, {
type: 'outlabeledPie',
data: {
labels: ["January", "February", "March", "April", "May"],
...
plugins: {
        legend: false,
        outlabels: {
           text: '%l %p',
           color: 'white',
           stretch: 45,
           font: {
               resizable: true,
               minSize: 12,
               maxSize: 18
           }
        }
     }
})
Run Code Online (Sandbox Code Playgroud)


bil*_*dou 6

我找不到确切的插件,但我制作了一个。

      const data = {
        labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
        datasets: [
          {
            data: [1, 2, 3, 4, 5, 6],
            backgroundColor: [
              "#316065",
              "#1A7F89",
              "#2D9CA7",
              "#2D86A7",
              "#1167A7",
              "#142440",
            ],
            borderColor: [
              "#316065",
              "#1A7F89",
              "#2D9CA7",
              "#2D86A7",
              "#1167A7",
              "#142440",
            ],
          },
        ],
      };

      // pieLabelsLine plugin
      const pieLabelsLine = {
        id: "pieLabelsLine",
        afterDraw(chart) {
          const {
            ctx,
            chartArea: { width, height },
          } = chart;

          const cx = chart._metasets[0].data[0].x;
          const cy = chart._metasets[0].data[0].y;

          const sum = chart.data.datasets[0].data.reduce((a, b) => a + b, 0);

          chart.data.datasets.forEach((dataset, i) => {
            chart.getDatasetMeta(i).data.forEach((datapoint, index) => {
              const { x: a, y: b } = datapoint.tooltipPosition();

              const x = 2 * a - cx;
              const y = 2 * b - cy;

              // draw line
              const halfwidth = width / 2;
              const halfheight = height / 2;
              const xLine = x >= halfwidth ? x + 20 : x - 20;
              const yLine = y >= halfheight ? y + 20 : y - 20;

              const extraLine = x >= halfwidth ? 10 : -10;

              ctx.beginPath();
              ctx.moveTo(x, y);
              ctx.arc(x, y, 2, 0, 2 * Math.PI, true);
              ctx.fill();
              ctx.moveTo(x, y);
              ctx.lineTo(xLine, yLine);
              ctx.lineTo(xLine + extraLine, yLine);
              // ctx.strokeStyle = dataset.backgroundColor[index];
              ctx.strokeStyle = "black";
              ctx.stroke();

              // text
              const textWidth = ctx.measureText(chart.data.labels[index]).width;
              ctx.font = "12px Arial";
              // control the position
              const textXPosition = x >= halfwidth ? "left" : "right";
              const plusFivePx = x >= halfwidth ? 5 : -5;
              ctx.textAlign = textXPosition;
              ctx.textBaseline = "middle";
              // ctx.fillStyle = dataset.backgroundColor[index];
              ctx.fillStyle = "black";

              ctx.fillText(
                ((chart.data.datasets[0].data[index] * 100) / sum).toFixed(2) +
                  "%",
                xLine + extraLine + plusFivePx,
                yLine
              );
            });
          });
        },
      };
      // config
      const config = {
        type: "pie",
        data,
        options: {
          maintainAspectRatio: false,
          layout: {
            padding: 30,
          },
          scales: {
            y: {
              display: false,
              beginAtZero: true,
              ticks: {
                display: false,
              },
              grid: {
                display: false,
              },
            },
            x: {
              display: false,
              ticks: {
                display: false,
              },
              grid: {
                display: false,
              },
            },
          },
          plugins: {
            legend: {
              display: false,
            },
          },
        },
        plugins: [pieLabelsLine],
      };

      // render init block
      const myChart = new Chart(document.getElementById("myChart"), config);
Run Code Online (Sandbox Code Playgroud)

https://codepen.io/BillDou/pen/oNoGBXb


Dee*_*015 2

真正的问题在于切片很小时标签的重叠。您可以使用PieceLabel.js,它通过隐藏标签来解决重叠标签的问题。您提到您无法隐藏标签,因此请使用图例,它将显示所有切片的名称

或者,如果您想要精确的行为,您可以使用 highcharts 但它需要商业使用许可。

var randomScalingFactor = function() {
  return Math.round(Math.random() * 100);
};
var ctx = document.getElementById("chart-area").getContext("2d");
var myDoughnut = new Chart(ctx, {
  type: 'pie',
  data: {
    labels: ["January", "February", "March", "April", "May"],
    datasets: [{
      data: [
        250,
        30,
        5,
        4,
        2,

      ],
      backgroundColor: ['#ff3d67', '#ff9f40', '#ffcd56', '#4bc0c0', '#999999'],
      borderColor: 'white',
      borderWidth: 5,
    }]
  },
  showDatapoints: true,
  options: {
    tooltips: {
      enabled: false
    },
    pieceLabel: {
      render: 'label',
      arc: true,
      fontColor: '#000',
      position: 'outside'
    },
    responsive: true,
    legend: {
      position: 'top',
    },
    title: {
      display: true,
      text: 'Testing',
      fontSize: 20
    },
    animation: {
      animateScale: true,
      animateRotate: true
    }
  }
});
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<script src="https://cdn.rawgit.com/emn178/Chart.PieceLabel.js/master/build/Chart.PieceLabel.min.js"></script>
<canvas id="chart-area"></canvas>
Run Code Online (Sandbox Code Playgroud)

小提琴演示