如何在 Chart.js 上显示数据值

Posted

技术标签:

【中文标题】如何在 Chart.js 上显示数据值【英文标题】:How to display data values on Chart.js 【发布时间】:2015-10-16 08:31:53 【问题描述】:

我想问是否可以使用 Chart.js 来显示数据值? 我想打印图表。

感谢您的建议。

【问题讨论】:

我的图表运行良好..我只想在我的 LineBar 图表中显示数据值..然后我可以打印我的图表..因为现在我可以通过鼠标事件显示数据值 【参考方案1】:

后期编辑: Chart.js 有一个官方插件2.7.0+ 可以做到这一点:https://github.com/chartjs/chartjs-plugin-datalabels

原答案:

您可以遍历动画完成上的点/条并显示值


预览


HTML

<canvas id="myChart1"  ></canvas>
<canvas id="myChart2"  ></canvas>

脚本

var chartData = 
    labels: ["January", "February", "March", "April", "May", "June"],
    datasets: [
        
            fillColor: "#79D1CF",
            strokeColor: "#79D1CF",
            data: [60, 80, 81, 56, 55, 40]
        
    ]
;

var ctx = document.getElementById("myChart1").getContext("2d");
var myLine = new Chart(ctx).Line(chartData, 
    showTooltips: false,
    onAnimationComplete: function () 

        var ctx = this.chart.ctx;
        ctx.font = this.scale.font;
        ctx.fillStyle = this.scale.textColor
        ctx.textAlign = "center";
        ctx.textBaseline = "bottom";

        this.datasets.forEach(function (dataset) 
            dataset.points.forEach(function (points) 
                ctx.fillText(points.value, points.x, points.y - 10);
            );
        )
    
);

var ctx = document.getElementById("myChart2").getContext("2d");
var myBar = new Chart(ctx).Bar(chartData, 
    showTooltips: false,
    onAnimationComplete: function () 

        var ctx = this.chart.ctx;
        ctx.font = this.scale.font;
        ctx.fillStyle = this.scale.textColor
        ctx.textAlign = "center";
        ctx.textBaseline = "bottom";

        this.datasets.forEach(function (dataset) 
            dataset.bars.forEach(function (bar) 
                ctx.fillText(bar.value, bar.x, bar.y - 5);
            );
        )
    
);

小提琴 - http://jsfiddle.net/uh9vw0ao/

【讨论】:

如果我在同一个图表中有两个折线图怎么办? 使用上面它仍然会显示值,但如果点彼此太接近,您可能会看到重叠。但是您始终可以输入逻辑来更改值位置。例如 - jsfiddle.net/hh719qex 如果您有彩色打印机。如果您只有 2 个系列,您还可以设置 textBaseline 不同,如果 2 个点彼此接近 2。 这是v1.0.2的,v2.1.3怎么做?后面的对象结构不一样了。 @potatopeelings 我在这里使用了onComplete 回调,但是当鼠标悬停在图表的条形上时它也会触发,导致数字由于重绘而闪烁。如果onAnimationComplete 会相同?我无法将此回调与我现有的图表代码一起使用(请参阅底部的var chartBar pastebin.com/tT7yTkGh) 我需要工具提示和图表顶部的数据。显示工具提示时,栏顶部的数据变为白色,这在我的透明工具提示中可见。我该如何解决这个问题?【参考方案2】:

这是 Chart.js 2.3 的更新版本

2016 年 9 月 23 日:编辑了我的代码以使用 v2.3 来处理线/条类型。

重要提示:即使不需要动画,也不要将duration选项改成0,否则会出现chartInstance.controller is undefined错误。

var chartData = 
    labels: ["January", "February", "March", "April", "May", "June"],
        datasets: [
            
                fillColor: "#79D1CF",
                strokeColor: "#79D1CF",
                data: [60, 80, 81, 56, 55, 40]
            
        ]
    ;

var opt = 
    events: false,
    tooltips: 
        enabled: false
    ,
    hover: 
        animationDuration: 0
    ,
    animation: 
        duration: 1,
        onComplete: function () 
            var chartInstance = this.chart,
                ctx = chartInstance.ctx;
            ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
            ctx.textAlign = 'center';
            ctx.textBaseline = 'bottom';

            this.data.datasets.forEach(function (dataset, i) 
                var meta = chartInstance.controller.getDatasetMeta(i);
                meta.data.forEach(function (bar, index) 
                    var data = dataset.data[index];                            
                    ctx.fillText(data, bar._model.x, bar._model.y - 5);
                );
            );
        
    
;
 var ctx = document.getElementById("Chart1"),
     myLineChart = new Chart(ctx, 
        type: 'bar',
        data: chartData,
        options: opt
     );
&lt;canvas id="myChart1" height="300" width="500"&gt;&lt;/canvas&gt;

【讨论】:

在条形图上尝试此操作时出现“未捕获的类型错误:无法读取未定义的属性 '0'”。酒吧是否使用“dataset.metaData[i]._model”以外的其他内容? 其实就是 var model = dataset._meta[i].data[0]._model; 这也不是全部真相。我仍然有例外。会想办法解决的。 var model = dataset._meta[0].data[i]._model;实际上。 看起来不像_meta[0]那么简单。实际上 _meta 对象不是一个数组,它有一个以数字为键的元素。我无法弄清楚数字背后的基本原理,所以我只是通过查看键列表来获取第一个元素,如下所示: var model = dataset._meta[Object.keys(dataset._meta)[0]] .data[i]._model;【参考方案3】:

此动画选项适用于条形图上的 2.1.3。

稍微修改了@Ross 的回答

animation: 
duration: 0,
onComplete: function () 
    // render the value of the chart above the bar
    var ctx = this.chart.ctx;
    ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, 'normal', Chart.defaults.global.defaultFontFamily);
    ctx.fillStyle = this.chart.config.options.defaultFontColor;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'bottom';
    this.data.datasets.forEach(function (dataset) 
        for (var i = 0; i < dataset.data.length; i++) 
            var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
            ctx.fillText(dataset.data[i], model.x, model.y - 5);
        
    );

【讨论】:

我还必须设置 hover: animationDuration: 0 以阻止标签在悬停时动画消失 另外,请注意,如果要在从图例中隐藏某些内容时隐藏标签,则需要在 forEach 循环之前添加以下内容:.filter(dataset =&gt; !dataset._meta[0].hidden) 如果条形上方没有足够的空间,此方法会导致值被剪切。 不敢相信这么丑^^干得好 看起来不错,但在重新绘制工具提示时会闪烁。也不处理组合图表和堆积条的累积数据标签上的冲突——这当然需要更多的编码。【参考方案4】:

如果您使用插件chartjs-plugin-datalabels,那么以下代码选项对象将有所帮助

确保您在 typescript 文件中导入 import 'chartjs-plugin-datalabels'; 或在您的 javascript 文件中添加对 &lt;script src="chartjs-plugin-datalabels.js"&gt;&lt;/script&gt; 的引用。

options: 
    maintainAspectRatio: false,
    responsive: true,
    scales: 
      yAxes: [
        ticks: 
          beginAtZero: true,
        
      ]
    ,
    plugins: 
      datalabels: 
        anchor: 'end',
        align: 'top',
        formatter: Math.round,
        font: 
          weight: 'bold'
        
      
    
  

【讨论】:

你的回答很简单,对我有用。谢谢你。编码愉快。 非常好的解决方案!谢谢你好心的陌生人:-* 这是最好的!【参考方案5】:

根据 @Ross 对 Chart.js 2.0 及更高版本的回答,我必须进行一些调整以防止条形高度太选择比例边界的情况。

条形图选项的animation属性:

animation: 
            duration: 500,
            easing: "easeOutQuart",
            onComplete: function () 
                var ctx = this.chart.ctx;
                ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal', Chart.defaults.global.defaultFontFamily);
                ctx.textAlign = 'center';
                ctx.textBaseline = 'bottom';

                this.data.datasets.forEach(function (dataset) 
                    for (var i = 0; i < dataset.data.length; i++) 
                        var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model,
                            scale_max = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._yScale.maxHeight;
                        ctx.fillStyle = '#444';
                        var y_pos = model.y - 5;
                        // Make sure data value does not get overflown and hidden
                        // when the bar's value is too close to max value of scale
                        // Note: The y value is reverse, it counts from top down
                        if ((scale_max - model.y) / scale_max >= 0.93)
                            y_pos = model.y + 20; 
                        ctx.fillText(dataset.data[i], model.x, y_pos);
                    
                );               
            
        

【讨论】:

鼠标悬停在图表上时文本会闪烁。我尝试在最后调用ctx.save(),但没有帮助 onComplete 回调是在我将鼠标悬停在栏上时执行的,这会导致重绘和文本似乎闪烁。这是否与 onAnimationComplete 相同?我无法使用onAnimationComplete 用我现有的代码回调(见pastebin.com/tT7yTkGh底部的var chartBar 饼图中也可以做同样的事情 @RaviKhambhati 是的,您可以在此答案中查看:***.com/a/38797604/6402571【参考方案6】:

我认为在 chartJS v2.x 中执行此操作的最佳选择是使用插件,因此选项中没有大量代码。此外,它还可以防止数据在悬停在条形上时消失。

即只需使用这段代码,它注册了一个插件,在绘制图表后添加文本。

Chart.pluginService.register(
    afterDraw: function(chartInstance) 
        var ctx = chartInstance.chart.ctx;

        // render the value of the chart above the bar
        ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, 'normal', Chart.defaults.global.defaultFontFamily);
        ctx.textAlign = 'center';
        ctx.textBaseline = 'bottom';

        chartInstance.data.datasets.forEach(function (dataset) 
            for (var i = 0; i < dataset.data.length; i++) 
                var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
                ctx.fillText(dataset.data[i], model.x, model.y - 2);
            
        );
  
);

【讨论】:

Chart.plugins.register( 我必须使用Chart.defaults.global.tooltips.enabled = false;。该解决方案的问题是 afterDraw 函数被调用了数百次,可能会产生 CPU 开销。尽管如此,这是目前唯一没有眨眼的答案。如果您需要更好地呈现horizontalBar 图表,请使用ctx.textAlign = 'left'; ctx.textBaseline = 'middle';ctx.fillText(dataset.data[i], model.x+5, model.y); 更清洁和模块化的解决方案。【参考方案7】:

按照这个good answer,我会使用这些选项来制作条形图:

var chartOptions = 
    animation: false,
    responsive : true,
    tooltipTemplate: "<%= value %>",
    tooltipFillColor: "rgba(0,0,0,0)",
    tooltipFontColor: "#444",
    tooltipEvents: [],
    tooltipCaretSize: 0,
    onAnimationComplete: function()
    
        this.showTooltip(this.datasets[0].bars, true);
    
;

window.myBar = new Chart(ctx1).Bar(chartData, chartOptions);

这仍然使用了工具提示系统和他的优点(自动定位、模板,...),但隐藏了装饰(背景颜色,插入符号,...)

【讨论】:

实施可能会因图表类型而异。例如,对于折线图,它是 this.datasets[0].points 而不是 .bars。我确实更喜欢这个解决方案,因为它使用了工具提示系统。 此解决方案适用于早期版本。如何为最新版本实现此功能,即 2.1.3。我在动画onComplete 回调中使用了 potatopeelings 和 Huang Trang 的答案,但即使将鼠标悬停在图表的条形上也会触发它,这会导致文本重绘并产生不需要的闪烁效果。我也试过 afterDraw 和它都是一样的。奇怪的是它不会发生在potatopeelings提供的小提琴中。请问有什么想法吗?【参考方案8】:

来自 chart.js 示例(文件 Chart.js-2.4.0/samples/data_labelling.html):

``` // 定义一个插件来提供数据标签

    Chart.plugins.register(
        afterDatasetsDraw: function(chartInstance, easing) 
            // To only draw at the end of animation, check for easing === 1
            var ctx = chartInstance.chart.ctx;

            chartInstance.data.datasets.forEach(function (dataset, i) 
                var meta = chartInstance.getDatasetMeta(i);
                if (!meta.hidden) 
                    meta.data.forEach(function(element, index) 
                        // Draw the text in black, with the specified font
                        ctx.fillStyle = 'rgb(0, 0, 0)';

                        var fontSize = 16;
                        var fontStyle = 'normal';
                        var fontFamily = 'Helvetica Neue';
                        ctx.font = Chart.helpers.fontString(fontSize, fontStyle, fontFamily);

                        // Just naively convert to string for now
                        var dataString = dataset.data[index].toString();

                        // Make sure alignment settings are correct
                        ctx.textAlign = 'center';
                        ctx.textBaseline = 'middle';

                        var padding = 5;
                        var position = element.tooltipPosition();
                        ctx.fillText(dataString, position.x, position.y - (fontSize / 2) - padding);
                    );
                
            );
        
    );

```

【讨论】:

我通过执行 if(chart.config.type == "horizo​​ntalBar") 然后定义自定义垂直填充 10 以使其居中对齐,为此添加了一条线以在水平条形图上对齐。 【参考方案9】:

我推荐使用这个插件:https://github.com/chartjs/chartjs-plugin-datalabels

只需将插件导入 js 文件,即可将标签添加到图表中,例如:

import 'chartjs-plugin-datalabels'

并且可以使用这些文档进行微调:https://chartjs-plugin-datalabels.netlify.com/options.html

【讨论】:

最简单的一种,不需要“代码”,只需使用标准的“选项”对象进行自定义。注意:最低要求的 charts.js 版本是 2.7.0,我从 CDN 引用 2.5.0,并且图表上没有任何变化... @GBU 选项属性是什么?。 另请注意,这是官方的 chartjs 插件,不是 3rd 方助手【参考方案10】:

根据我的经验,一旦包含chartjs-plugin-datalabels 插件(确保将&lt;script&gt; 标记放在页面上的chart.js 标记之后),您的图表就会开始显示值。

如果您随后选择,您可以自定义它以满足您的需求。 The customization is clearly documented here 但基本上,格式就像这个假设的例子:

var myBarChart = new Chart(ctx, 
    type: 'bar',
    data: yourDataObject,
    options: 
        // other options
        plugins: 
            datalabels: 
                anchor :'end',
                align :'top',
                // and if you need to format how the value is displayed...
                formatter: function(value, context) 
                    return GetValueFormatted(value);
                
            
        
    
);

【讨论】:

【参考方案11】:

稍微编辑了@ajhuddy 的回答。 仅适用于条形图。我的版本添加:

淡入动画的值。 如果条形太高,通过将值定位在条形内来防止剪切。 不闪烁。

缺点:将鼠标悬停在其中包含值的条上时,该值可能看起来有点锯齿状。我还没有找到禁用悬停效果的解决方案。它可能还需要根据您自己的设置进行调整。

配置:

bar: 
  tooltips: 
    enabled: false
  ,
  hover: 
    animationDuration: 0
  ,
  animation: 
    onComplete: function() 
      this.chart.controller.draw();
      drawValue(this, 1);
    ,
    onProgress: function(state) 
      var animation = state.animationObject;
      drawValue(this, animation.currentStep / animation.numSteps);
    
  

助手:

// Font color for values inside the bar
var insideFontColor = '255,255,255';
// Font color for values above the bar
var outsideFontColor = '0,0,0';
// How close to the top edge bar can be before the value is put inside it
var topThreshold = 20;

var modifyCtx = function(ctx) 
  ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, 'normal', Chart.defaults.global.defaultFontFamily);
  ctx.textAlign = 'center';
  ctx.textBaseline = 'bottom';
  return ctx;
;

var fadeIn = function(ctx, obj, x, y, black, step) 
  var ctx = modifyCtx(ctx);
  var alpha = 0;
  ctx.fillStyle = black ? 'rgba(' + outsideFontColor + ',' + step + ')' : 'rgba(' + insideFontColor + ',' + step + ')';
  ctx.fillText(obj, x, y);
;

var drawValue = function(context, step) 
  var ctx = context.chart.ctx;

  context.data.datasets.forEach(function (dataset) 
    for (var i = 0; i < dataset.data.length; i++) 
      var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
      var textY = (model.y > topThreshold) ? model.y - 3 : model.y + 20;
      fadeIn(ctx, dataset.data[i], model.x, textY, model.y > topThreshold, step);
    
  );
;

【讨论】:

Janne,感谢您提供的解决方案,它看起来很棒。但是我有一种情况,我的值实际上有点大(5 个十进制数字),当屏幕尺寸很小或者我有很多图表时,这些数字是相互重叠的。有没有办法让这项工作具有响应性?比如,让数字在没有空格的时候旋转,就像条形下面的标签一样? @PhiterFernandes 我认为应该可以通过在 modifyCtx 函数中检查当前屏幕尺寸并使用 ctx.rotate 来旋转。但是我不确定如何将值大小与可用空间进行比较以确定何时旋转。 modifyCtx 函数只能工作一次,并且不能调整大小,对吧?我将看一下chart.js 源代码,看看它们在x 轴上旋转标签的位置。如果我看到一些东西,我会尝试做一些事情并在这里告诉你,好吗? =) 我在 2.3.0 版的第 7075 行找到了一些东西。calculateTickRotation,它在 Scale 函数中。我来分析一下。【参考方案12】:

为了防止您的数字在太靠近画布顶部时被截断:

yAxes: [
    ticks: 
      stepSize: Math.round((1.05*(Math.max.apply(Math, myListOfyValues)) / 10)/5)*5,
      suggestedMax: 1.05*(Math.max.apply(Math, myListOfyValues)),
        beginAtZero: true,
        precision: 0
    
]

10 = 滴答数

5 = 将刻度值四舍五入到最接近的 5 - 所有 y 值将均匀递增

1.05 = 增加最大 y 轴刻度值,这样数字就不会被截断

类似的方法也适用于 xAxes。

【讨论】:

以上是关于如何在 Chart.js 上显示数据值的主要内容,如果未能解决你的问题,请参考以下文章

为chart.js中的水平条添加值

如何在 React 中更新 chart.js 的状态

web页面 chart.js 怎样在折线图的点上显示对应数值?

如何在chart.js中的饼图上方显示标签

如何使用 web 视图(chart.js)在 android 电视中显示图表

如何在 Chart Js 中自定义工具提示?