【问题标题】:Chart.js - Positioning Donut LabelChart.js - 定位甜甜圈标签
【发布时间】:2016-12-08 17:57:40
【问题描述】:

我有一个使用 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 属性不起作用,或者我误解了它们的用法。

谢谢!

【问题讨论】:

  • 您更喜欢使用您的小提琴上的 Chart.JS 版本,还是考虑使用 V2.1?

标签: javascript css charts


【解决方案1】:

根据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);

【讨论】:

    【解决方案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);
      }
    

    希望这能解决您的问题!

    【讨论】:

    • 我很好奇,当您将鼠标悬停在图表的一部分上时,我注意到百分比闪烁。有什么办法可以消除闪烁吗?换句话说,当您将鼠标悬停在甜甜圈的一部分上时,让标签保持不变?
    • @user687554 是的,可以通过悬停模式“false”看到这个jsfiddle.net/uha5tseb/7希望这能解决你的所有问题:)
    【解决方案3】:

    当您获得 xCenter 和 yCenter 时,您错误地设置了变量。目前他们没有到达画布的中间。

    你有:

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

    应该是:

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

    【讨论】:

      【解决方案4】:

      我不熟悉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

      【讨论】:

        【解决方案5】:

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

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

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

        这是一个完整的JSFiddle

        【讨论】:

          猜你喜欢
          • 2016-08-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-03-07
          • 1970-01-01
          • 2016-09-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多