如何在chart.js中显示每个切片的饼图数据值

IT技术 javascript php jquery charts
2021-03-20 21:14:10

我正在使用 Chart.js 在我的 php 页面中绘制饼图。我发现工具提示显示每个切片值。
在此处输入图片说明

但我希望显示如下图所示的值。 在此处输入图片说明

我不知道如何用 chart.js 做到这一点。

请帮我。

我的Javascript代码:

function drawPie(canvasId,data,legend){
    var ctx = $("#pie-canvas-" + canvasId).get(0).getContext("2d");

    var piedata = [];
    $.each(data,function(i,val){
        piedata.push({value:val.count,color:val.color,label:val.status});
    });
    var options =
    {
        tooltipTemplate: "<%= Math.round(circumference / 6.283 * 100) %>%",
    }
    var pie = new Chart(ctx).Pie(piedata,options);
    if(legend)document.getElementById("legend").innerHTML = pie.generateLegend();
}

php代码:

printf('<table><tr>');
echo '<td style="text-align: right;"><canvas id="pie-canvas-'
    . $canvasId
    . '" width="256" height="256" ></canvas></td><td style="text-align: left;width:360px;height:auto" id="legend" class="chart-legend"></td></tr></table>';

     echo '<script type="text/javascript">drawPie('
    . $canvasId
    . ', '
    . $data3
    .', '
    . $legend
    . ');</script>';

在此处输入图片说明

6个回答

对于Chart.js 2.0及更高版本,Chart 对象数据已更改。对于那些使用 Chart.js 2.0+ 的人,下面是使用 HTML5 CanvasfillText()方法在饼图中显示数据值的示例该代码也适用于圆环图,唯一的区别是type: 'pie'type: 'doughnut'创建图表时的不同

脚本:

Javascript

var data = {
    datasets: [{
        data: [
            11,
            16,
            7,
            3,
            14
        ],
        backgroundColor: [
            "#FF6384",
            "#4BC0C0",
            "#FFCE56",
            "#E7E9ED",
            "#36A2EB"
        ],
        label: 'My dataset' // for legend
    }],
    labels: [
        "Red",
        "Green",
        "Yellow",
        "Grey",
        "Blue"
    ]
};

var pieOptions = {
  events: false,
  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,
              total = dataset._meta[Object.keys(dataset._meta)[0]].total,
              mid_radius = model.innerRadius + (model.outerRadius - model.innerRadius)/2,
              start_angle = model.startAngle,
              end_angle = model.endAngle,
              mid_angle = start_angle + (end_angle - start_angle)/2;

          var x = mid_radius * Math.cos(mid_angle);
          var y = mid_radius * Math.sin(mid_angle);

          ctx.fillStyle = '#fff';
          if (i == 3){ // Darker text color for lighter background
            ctx.fillStyle = '#444';
          }
          var percent = String(Math.round(dataset.data[i]/total*100)) + "%";      
          //Don't Display If Legend is hide or value is 0
          if(dataset.data[i] != 0 && dataset._meta[0].data[i].hidden != true) {
            ctx.fillText(dataset.data[i], model.x + x, model.y + y);
            // Display percent in another line, line break doesn't work for fillText
            ctx.fillText(percent, model.x + x, model.y + y + 15);
          }
        }
      });               
    }
  }
};

var pieChartCanvas = $("#pieChart");
var pieChart = new Chart(pieChartCanvas, {
  type: 'pie', // or doughnut
  data: data,
  options: pieOptions
});

HTML

<canvas id="pieChart" width=200 height=200></canvas>

js小提琴

我在同一个 Javascript 中有其他图表。那么 ctx 会是什么?
2021-04-27 21:14:10
我意识到这是一个旧答案,但是您能解释一下我如何换出标签的百分比吗?那么数据是在每个切片的标签下面吗?谢谢
2021-04-28 21:14:10
谢谢你的例子,这真的帮助我理解了chartjs中的细分
2021-05-01 21:14:10
没关系,var label = data.labels[i];如果将来有人想知道,可以得到标签
2021-05-14 21:14:10

我找到了一个很好的Chart.js插件,它完全符合你的要求:https : //github.com/emn178/Chart.PieceLabel.js

据我所知,我不相信 Chart.JS 有任何功能可以帮助在饼图上绘制文本。但这并不意味着您不能在原生 JavaScript 中自行完成。我会给你一个关于如何做到这一点的例子,下面是为饼图中每个段绘制文本的代码:

function drawSegmentValues()
{
    for(var i=0; i<myPieChart.segments.length; i++) 
    {
        // Default properties for text (size is scaled)
        ctx.fillStyle="white";
        var textSize = canvas.width/10;
        ctx.font= textSize+"px Verdana";

        // Get needed variables
        var value = myPieChart.segments[i].value;
        var startAngle = myPieChart.segments[i].startAngle;
        var endAngle = myPieChart.segments[i].endAngle;
        var middleAngle = startAngle + ((endAngle - startAngle)/2);

        // Compute text location
        var posX = (radius/2) * Math.cos(middleAngle) + midX;
        var posY = (radius/2) * Math.sin(middleAngle) + midY;

        // Text offside to middle of text
        var w_offset = ctx.measureText(value).width/2;
        var h_offset = textSize/4;

        ctx.fillText(value, posX - w_offset, posY + h_offset);
    }
}

饼图有一个存储在其中的段数组PieChart.segments,我们可以查看这些段startAngleendAngle以确定文本所在位置之间的角度middleAngle然后我们将朝那个方向移动,Radius/2以弧度为单位位于图表的中间点。

在上面的例子中,做了一些其他的清理操作,由于绘制的文本位置在fillText()右上角,我们需要得到一些偏移值来纠正它。最后textSize是根据图表本身的大小来确定的,图表越大文字越大。

小提琴示例


通过稍加修改,您可以将数据集的离散数值更改为图表中的百分位数。为此,获取value数据集中项目的总数,请调用此totalValue然后在每个段上,您可以通过执行以下操作找到百分比:

Math.round(myPieChart.segments[i].value/totalValue*100)+'%';

此处的部分用于myPieChart.segments[i].value/totalValue计算该段在图表中所占的百分比。例如,如果当前段的值为50并且 totalValue 为200那么该段所占的百分比将是:50/200 => 0.25剩下的就是让这个看起来不错。0.25*100 => 25,然后我们%在最后添加一个对于整数百分比的瓷砖,我四舍五入到最接近的整数,尽管可能会导致准确性问题。如果我们需要更高的准确性,您可以使用.toFixed(n)来保存小数位。例如,我们可以这样做以在需要时保存一个小数位:

var value = myPieChart.segments[i].value/totalValue*100;
if(Math.round(value) !== value)
    value = (myPieChart.segments[i].value/totalValue*100).toFixed(1);
value = value + '%';

带小数的百分位数示例

带有整数的百分位数示例

@Nithya.K 该值在 JS 对象中明确定义为数字,饼图查看这些值以确定它们占据图表的多少。因此,您可以通过currentValue/totalValue获取百分位数(例如:)来获得它=>0.50乘以 100 =>50,然后"%"在末尾添加一个示例在这里
2021-04-20 21:14:10
哇 - 非常令人印象深刻的答案;如果它对我有用,我将自己对它进行 Bountify,因为我已经为这个答案搜索了高低。
2021-04-28 21:14:10
@Nithya.K 一种可能有帮助的方法是更改​​文本在画布上绘制的距离((radius/2)代码中确定)以获取小值。对于较小的值(比如小于 5%),您可能希望将它们绘制在绘制图形的边缘或越过边缘,并与该显示一起强制显示为整数。明天我举个例子。
2021-04-30 21:14:10
@spencer...完美!!..谢谢..但在这里var value = myPieChart.segments[i].value;我希望这个值是饼图的百分比..你能告诉我在这里怎么做..
2021-05-15 21:14:10
如果值低 .0.8% 和 1%..如果这些值在附近,两个值都被覆盖。它无法读取。我尝试修改角度,但完全令人困惑。你会怎么做?..我添加了截图多于。
2021-05-15 21:14:10

您可以使用Chart.js 的 PieceLabel插件。

{ pieceLabel: { mode: 'percentage', precision: 2 } }

演示| 文档

该插件似乎有一个新位置(和名称): Demo Docs

我想使用模式百分比与图例标签连接。
2021-05-04 21:14:10

@Hung Tran 的回答很完美。作为改进,我建议不要显示 0 的值。假设您有 5 个元素,其中 2 个是 0,其余的都有值,上面的解决方案将显示 0 和 0%。最好用不等于 0 的检查过滤掉它!

          var val = dataset.data[i];
          var percent = String(Math.round(val/total*100)) + "%";

          if(val != 0) {
            ctx.fillText(dataset.data[i], model.x + x, model.y + y);
            // Display percent in another line, line break doesn't work for fillText
            ctx.fillText(percent, model.x + x, model.y + y + 15);
          }

更新代码如下:

var data = {
    datasets: [{
        data: [
            11,
            16,
            7,
            3,
            14
        ],
        backgroundColor: [
            "#FF6384",
            "#4BC0C0",
            "#FFCE56",
            "#E7E9ED",
            "#36A2EB"
        ],
        label: 'My dataset' // for legend
    }],
    labels: [
        "Red",
        "Green",
        "Yellow",
        "Grey",
        "Blue"
    ]
};

var pieOptions = {
  events: false,
  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,
              total = dataset._meta[Object.keys(dataset._meta)[0]].total,
              mid_radius = model.innerRadius + (model.outerRadius - model.innerRadius)/2,
              start_angle = model.startAngle,
              end_angle = model.endAngle,
              mid_angle = start_angle + (end_angle - start_angle)/2;

          var x = mid_radius * Math.cos(mid_angle);
          var y = mid_radius * Math.sin(mid_angle);

          ctx.fillStyle = '#fff';
          if (i == 3){ // Darker text color for lighter background
            ctx.fillStyle = '#444';
          }

          var val = dataset.data[i];
          var percent = String(Math.round(val/total*100)) + "%";

          if(val != 0) {
            ctx.fillText(dataset.data[i], model.x + x, model.y + y);
            // Display percent in another line, line break doesn't work for fillText
            ctx.fillText(percent, model.x + x, model.y + y + 15);
          }
        }
      });               
    }
  }
};

var pieChartCanvas = $("#pieChart");
var pieChart = new Chart(pieChartCanvas, {
  type: 'pie', // or doughnut
  data: data,
  options: pieOptions
});