Chart.js - 定位甜甜圈标签

时间:2016-11-30 13:41:50

标签: javascript css charts

我有一个使用Chart.js的网页。在这个页面中,我正在渲染三个圆环图。在每个图表的中间,我想显示填充的甜甜圈的百分比。目前,我有以下代码,可在此Fiddle中看到。

function setupChart(chartId, progress) {
  var canvas = document.getElementById(chartId);
  var context = canvas.getContext('2d');

  var remaining = 100 - progress;
  var data = {
    labels: [ 'Progress', '', ],
    datasets: [{
      data: [progress, remaining],
      backgroundColor: [
        '#8FF400',
        '#FFFFFF'
      ],
      borderColor: [
        '#8FF400',
        '#408A00'
      ],
      hoverBackgroundColor: [
        '#8FF400',
        '#FFFFFF'
      ]
    }]
  };

  var options = {
    responsive: true,
    maintainAspectRatio: false,
    scaleShowVerticalLines: false,

    cutoutPercentage: 80,
    legend: {
      display: false
    },
    animation: {
      onComplete: function () {
        var xCenter = (canvas.width / 2) - 20;
        var yCenter = canvas.height / 2 - 40;

        context.textAlign = 'center';
        context.textBaseline = 'middle';

        var progressLabel = data.datasets[0].data[0] + '%';
        context.font = '20px Helvetica';
        context.fillStyle = 'black';
        context.fillText(progressLabel, xCenter, yCenter);
      }
    }
  };

  Chart.defaults.global.tooltips.enabled = false;
  var chart = new Chart(context, {
    type: 'doughnut',
    data: data,
    options: options
  });
}

图表"运行"。但问题在于标签的渲染。标签不是在甜甜圈中间垂直和水平居中。标签的位置也会根据屏幕分辨率而变化。您可以通过调整图表在Fiddle内呈现的框架来查看标签更改位置。

我的问题是,我如何始终将百分比定位在甜甜圈中间?我的页面是一个响应式页面,所以具有一致的定位很重要然而,我不知道还能做什么。我觉得textAligntextBaseline属性不起作用,或者我误解了它们的用法。

谢谢!

6 个答案:

答案 0 :(得分:4)

根据this answer,您可以使用其他版本的插件执行此操作。我不知道你是否注意到了,但是如果你增加宽度并在你的小提琴上一遍又一遍地减少它,你的画布的高度会变得越来越大(图表越走越远)。

在您使用的版本上,您可以像这样扩展doughnut控制器:

http://jsfiddle.net/ivanchaer/cutkqkuz/1/

Chart.defaults.DoughnutTextInside = Chart.helpers.clone(Chart.defaults.doughnut);
Chart.controllers.DoughnutTextInside = Chart.controllers.doughnut.extend({
    draw: function(ease) {

        var ctx = this.chart.chart.ctx;
        var data = this.getDataset();

        var easingDecimal = ease || 1;
        Chart.helpers.each(this.getDataset().metaData, function(arc, index) {
            arc.transition(easingDecimal).draw();

            var vm = arc._view;
            var radius = (vm.outerRadius + vm.innerRadius) / 2;
            var thickness = (vm.outerRadius - vm.innerRadius) / 2;
            var angle = Math.PI - vm.endAngle - Math.PI / 2;

            ctx.save();
            ctx.fillStyle = vm.backgroundColor;

            ctx.font = "20px Verdana";
            ctx.textAlign = 'center';
            ctx.textBaseline = "middle";

            var text = data.data[0] + '%';
            ctx.fillStyle = '#000';
            ctx.fillText(text, $(ctx.canvas).width()/2, $(ctx.canvas).height()/2);
        });
        ctx.fillStyle = '#fff';
        ctx.fill();
        ctx.restore();

    }

});


function setupChart(chartId, progress) {
    var canvas = document.getElementById(chartId);
    var context = canvas.getContext('2d');
    var remaining = 100 - progress;

    var deliveredData = {
        labels: [
            "Value"
        ],
        datasets: [{
            data: [progress, remaining],
            backgroundColor: [
                '#8FF400',
                '#FFFFFF'
            ],
            borderColor: [
                '#8FF400',
                '#408A00'
            ],
            hoverBackgroundColor: [
                '#8FF400',
                '#FFFFFF'
            ]
        }]
    };

    var deliveredOpt = {
        cutoutPercentage: 88,

        animation: false,
        legend: {
            display: false
        },
        tooltips: {
            enabled: false
        }
    };

    var chart = new Chart(canvas, {
        type: 'DoughnutTextInside',
        data: deliveredData,
        options: deliveredOpt
    });

}

setupChart('standChart', 33);
setupChart('moveChart', 66);
setupChart('exerciseChart', 99);

答案 1 :(得分:2)

请参阅此http://jsfiddle.net/uha5tseb/2/

可以通过此参考

获取每个图表的宽度/高度来处理
  onComplete: function (event) {
    console.log(this.chart.height);
    var xCenter = this.chart.width/2;
    var yCenter = this.chart.height/2;

    context.textAlign = 'center';
    context.textBaseline = 'middle';

    var progressLabel = data.datasets[0].data[0] + '%';
    context.font = '20px Helvetica';
    context.fillStyle = 'black';
    context.fillText(progressLabel, xCenter, yCenter);
  }

希望这能解决你的问题!

答案 2 :(得分:2)

获取xCenter和yCenter时,无法正确设置变量。目前他们没有得到画布的中间部分。

你有:

var xCenter = (canvas.width / 2) - 20;
var yCenter = canvas.height / 2 - 40;

应该是:

var xCenter = (canvas.width / 2);
var yCenter = (canvas.height / 2);

答案 3 :(得分:0)

我不熟悉chart.js,但据我从文档中了解,他们为您的目的提供了 generateLegend 方法。它返回来自 legendCallback 的数据,您可以在画布外的页面上显示该数据。

图例文本的容器可以相对于画布的包装器对齐。

HTML:

<div class="chart" data-legend="">
  <canvas id="standChart"></canvas>
</div>

JS:

var container = canvas.parentElement;
...
container.setAttribute('data-legend', chart.generateLegend());

Fiddle

答案 4 :(得分:0)

解决此问题的一种方法是在画布顶部添加绝对定位的元素。

您可以在每个canvas元素后添加div元素,然后将其样式设置为:

.precentage {
  font-family: tahoma;
  font-size: 28px;
  left: 50%;
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
}

这是一个完整的JSFiddle

答案 5 :(得分:-1)

We Give Size of the Chart Can be with in the Chart And Align to center on the Give the hight width based on the Chart Hight and Width..
i will make simple change in Your Jsfiddle
..
xcenter and y center with the half distence for chart..

[http://jsfiddle.net/uha5tseb/10/][1]