ChartJS:在甜甜圈段的末端放置标签

时间:2020-05-14 15:17:06

标签: javascript charts chart.js

我正在使用带有扩展名chartjs-gauge的chartJS,它基本上是用于创建仪表盘样式表的自定义甜甜圈。我添加了chartjs-plugin-datalabels plugin,以便可以自定义标签。

饼图和甜甜圈图中的标签通常用于显示该段的值,但是由于已对其进行了自定义以显示为量表,因此我想将数据标签放置在每个段的末尾,因此它将值显示在像这样:

Label position I'm aiming for

虽然可以使用锚,对齐和偏移来移动标签,但是这些标签允许围绕一个点的有限移动,而我想不出一种方法来实现所需的功能。我可以锚定到“ end”以使标签超出量规,然后我想也许可以结合使用align和offset将标签推到分段的末端,但是不幸的是,这些命令似乎基于整个轴而起作用而非弧形线段。

这是我用来设置选项和数据的代码。这在Salesforce Aura组件中,因此chartJsGaugeInstance从控制器获取值:

let chartJsGaugeInstance = component.get("v.dataInstance");
let type = chartJsGaugeInstance.type;
let target = chartJsGaugeInstance.targetValue;
let firstDivide = target * 0.33;
let secondDivide = target * 0.66;
let data = {
    datasets : [{
        backgroundColor: ["#0fdc63", "#fd9704", "#ff7143"],
        data: [firstDivide, secondDivide, target],
        value: chartJsGaugeInstance.dataValues,
        datalabels: {
            anchor: 'center',
            align: 'center',
            offset: 0
        }
    }]
};

let options = {
    responsive: true,
    title: {
        display: true,
        text: chartJsGaugeInstance.title
    },
    layout: {
        padding: {
            bottom: 30
        }
    },
    needle: {
        // Needle circle radius as the percentage of the chart area width
        radiusPercentage: 1.5,
        // Needle width as the percentage of the chart area width
        widthPercentage: 1,
        // Needle length as the percentage of the interval between inner radius (0%) and outer radius (100%) of the arc
        lengthPercentage: 80,
        // The color of the needle
        color: 'rgba(0, 0, 0, 1)'
    },
    valueLabel: {
        formatter: Math.round
    },
    cutoutPercentage : 80,
    plugins: {
        datalabels: {
            display: true,
            formatter:  function (value, context) {
                return context.chart.data.labels[context.dataIndex];
            },
            color: 'rgba(0, 0, 0, 1.0)',
            backgroundColor: null,
            font: {
                size: 16
            }
        }
    }
}

这是结果图表: Labels with center positioning 我可以通过更改数据集对象内的datalabels参数来移动标签(在本示例中,将它们放在中间),但是当它们全部相对于图表区域而不是相对段的方向移动时,我可以不要让它们全部对齐其段的末尾。这是一个将6k标签移动到正确位置的示例,但是3k和10k标签最终移到了外面:

datalabels: {
    anchor: 'end',
    align: 'right',
    offset: 50
}

Labels right aligned This是我用于数据标签定位的文档。对齐部分下的一行显示:

'end':标签位于锚点之后,并沿相同方向

我认为这就是我想要的,对我来说“遵循相同的方向”建议它应遵循细分的弧线,但事实并非如此:

datalabels: {
    anchor: 'end',
    align: 'end',
    offset: 20
}

Labels with end positioning

还有其他人设法做到这一点吗? There is a similar issue raised in github自2018年以来被标记为“增强”,但想知道是否有办法以编程方式或通过编辑源文件来实现此目的,因为它看起来不会很快交付。

谢谢!

更新

我设法使用脚本选项找到了部分解决方案。以下代码更新使我可以在每个扇区的末尾找到标签。我已经将datalabels代码从数据集中移到了选项中

let numSectors = data.datasets[0].data.length;
let sectorDegree = 180 / numSectors;

datalabels: {
    anchor: 'end',
    align: function(context){
        return (sectorDegree * context.dataIndex) - sectorDegree;
    },
    offset: function(context){
        return 70;
    },
    ...
}

这导致: latest looking gauge

我对当前的项目很满意,因为我将始终拥有三个平均分配的部门,但是这并不是一个完整的解决方案。我计算出的角度很大程度上取决于偏移量。更改偏移量意味着对齐计算将不再提供良好的结果。这里最大的问题是,由于偏移非常重要,因此更改扇区数意味着该解决方案不再有效。

1 个答案:

答案 0 :(得分:0)

你在 align 函数中的代码确实帮助我开始了,但我希望定位有点不同,我编写了这段代码来根据段数量、所需的字体大小(适当的偏移量)计算位置,以及画布父级的宽度。

let numSectors = insert length of data array here;
let sectorDegree = 180 / numSectors;
let width = (canvas.parent().width() - parseInt(canvas.css('padding').replace("px", "") * 2));
let fontSize = 16;
let b = (width / 2) - 3;
let c = b - (fontSize * 1.8);
let a = Math.sqrt((Math.pow(b, 2) + Math.pow(c, 2)) - (2 * b * c * Math.cos((sectorDegree / 2) * Math.PI / 180)));
let offset = a - (fontSize * 1.2);
let alignAngle = (Math.asin(Math.sin((sectorDegree / 2) * Math.PI / 180) * c / a) * 180 / Math.PI) - (sectorDegree / 2);

datalabels: {
  display: true,
  anchor: 'end',
  font: {
    size: fontSize,
  },
  offset: offset,
  align: function(context) {
    return (sectorDegree * context.dataIndex) - alignAngle;
  },
}