【问题标题】:ChartJS: Position labels at end of doughnut segmentChartJS:在甜甜圈段末尾放置标签
【发布时间】:2020-08-31 04:51:02
【问题描述】:

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

饼图和圆环图中的标签通常用于显示该段的值,但由于这已被自定义为显示为仪表,我想将我的数据标签放置在每个段的末尾,以便它显示值那一点是这样的:

虽然可以使用锚点、对齐和偏移来移动标签,但它们允许围绕一个点进行有限的移动,我无法找到实现我需要的方法。我可以锚定到“结束”以将标签放在仪表之外,然后我想也许我可以结合 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
            }
        }
    }
}

这是生成的图表: 我可以通过更改数据集对象中的 datalabels 参数来移动标签(在本例中,我将它们留在中心),但由于它们都相对于图表区域而不是相对线段的方向移动,所以我可以' t 让它们都对齐到它们段的末尾。这是一个将 6k 标签移动到大约正确位置的示例,但 3k 和 10k 标签最终会退出:

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

This 是我用于数据标签定位的文档。 Align 部分下的一行显示:

'end':标签定位在锚点之后,方向一致

我认为这就是我想要的,“遵循相同的方向”对我来说意味着它应该遵循段的弧线,但它没有:

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

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

谢谢!

更新

我已经设法使用 Scriptable Options 找到了部分解决方案。以下对代码的更新为我在每个扇区的末尾提供了很好的定位标签。我已将数据标签代码从数据集移到选项中

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;
    },
    ...
}

这会导致:

我对我目前的项目很满意,因为我总是有三个均匀分割的扇区,但是这不是一个完整的解决方案。我计算的角度很大程度上取决于偏移量。更改偏移量意味着对齐计算不再给出很好的结果。这里最大的问题是,由于偏移量如此重要,因此更改扇区数意味着此解决方案不再有效。

【问题讨论】:

  • 请发布您生成上图的代码。这样可以更轻松地为您的问题提出解决方案。
  • 会做的,虽然插件确实可以,我只是设置了一些参数

标签: javascript charts chart.js


【解决方案1】:

您在 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;
  },
}

【讨论】:

    【解决方案2】:

    我的想法是在原始图表之上绘制一个额外的透明图表,该图表将负责绘制标签。 标签图表数据将包含包含原始图表中每个段的末尾的段,这样显示在标签图表段中间的标签实际上将显示在原始图表段的末尾。

    这是绘制透明标签图表的代码:

    
    const getLabelsChartData = (min, data) => {
      if (!data) return [];
      const max = data[data.length - 1];
      const step = (max - min) / 1000;
      const values = data
        .slice(0, -1) // remove "max" value
        .map((value, index) => {
          // remove too close values (because labels collapse)
          const prevValue = data[index - 1];
          if (!prevValue || value - prevValue > step * 50) {
            return value;
          }
        })
        .reduce((arr, value) => {
          // create small ranges between each value
          if (value) {
            return [...arr, value - step, value + step];
          }
          return arr;
        }, []);
      return [...values, max];
    };
    
    const getLabel = (originalData, labelIndex) => {
      if (labelIndex % 2) {
        const originalDataIndex = Math.floor(labelIndex / 2);
        return originalData[originalDataIndex];
      }
      return '';
    };
    
    const labelsChartConfig = {
        type: 'gauge',
        plugins: [ChartDataLabels],
        data: {
          data: getLabelsChartData(minValue, originalData),
          minValue: minValue,
          fill: false,
          backgroundColor: ['transparent'],
          borderColor: 'transparent',
        }
        options: {
          plugins: {
            datalabels: {
              display: true,
              formatter: function (value, context) {
                return getLabel(originalData, context.dataIndex);
              }
              anchor: 'end',
              align: 'end',
            },
          },
        }
    }
    
    new Chart(labelsCanvas, labelsChartConfig);
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-02
      • 2015-03-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多