How to add labels into Chart.js canvas plugin?

2019-01-16 11:15发布

I'm using the awesome plugin Chart.js, and I'm trying to find the way of display labels within each percentage. So I googled it, and I found this pull: https://github.com/nnnick/Chart.js/pull/35

I did a simple fiddle to test it, but doesn't works: http://jsfiddle.net/marianico2/7ktug/1/

This is the content:

HTML

<canvas id="canvas" height="450" width="450"></canvas>

JS

$(document).ready(function () {
    var pieData = [{
        value: 30,
        color: "#F38630",
        label: 'HELLO',
        labelColor: 'black',
        labelFontSize: '16'
    }, {
        value: 50,
        color: "#E0E4CC"
    }, {
        value: 100,
        color: "#69D2E7"
    }];

    var myPie = new Chart(document.getElementById("canvas").getContext("2d")).Pie(pieData, {
        labelAlign: 'center'
    });
});

I'm afraid there is no information about this in the documentation.

Also I'd like to know how to display a label for each portion, but outside the chart. Linked by a line. As do the charts of highcharts.js.

By the way, I'd be glad if you recommend me an html5 chart alternative which includes the options I said above. I've heard about the flot plugin, but I'm afraid does not support animations...

If you need more info, let me know and I'll edit the post.

4条回答
Animai°情兽
2楼-- · 2019-01-16 11:34

You'll have to add code in 2 places. As an example, take the doughnut. First add label info to the defaults (look at the original Chart.js code and compare with this):

    chart.Doughnut.defaults = {
        segmentShowStroke : true,
        segmentStrokeColor : "#fff",
        segmentStrokeWidth : 2,
        percentageInnerCutout : 50,
        animation : true,
        animationSteps : 100,
        animationEasing : "easeOutBounce",
        animateRotate : true,
        animateScale : false,
        onAnimationComplete : null,
        labelFontFamily : "Arial",
        labelFontStyle : "normal",
        labelFontSize : 24,
        labelFontColor : "#666"
    };

Then go down to where the Doughnut is drawn and add the four ctx lines.

    animationLoop(config,null,drawPieSegments,ctx);

    function drawPieSegments (animationDecimal){
        ctx.font = config.labelFontStyle + " " + config.labelFontSize+"px " + config.labelFontFamily;
        ctx.fillStyle = 'black';
        ctx.textBaseline = 'middle';
        ctx.fillText(data[0].value + "%", width/2 - 20, width/2, 200);

The ctx.fillText call will put the text onto the canvas, so you can use that to write text with x,y coordinates. You ought to be able to use this way to do basic labels. Here is the jsfiddle to tinker with:

http://jsfiddle.net/nCFGL/ (look at lines 281 and 772 in the JavaScript section of the jsfiddle for aforementioned code)

If you need something fancier, someone forked a version of Charts.js and added tooltips. Here is the discussion https://github.com/nnnick/Chart.js/pull/35, and you'll be able to find the link to the forked version inside that discussion.

查看更多
趁早两清
3楼-- · 2019-01-16 11:37

This one literally took hours and hours and I found a working solution.

https://github.com/nnnick/Chart.js/pull/116

This was my final code. I was trying to display percentages as labels on doughnut

Chart.types.Doughnut.extend({
name: "DoughnutAlt",
draw: function() {
    Chart.types.Doughnut.prototype.draw.apply(this, arguments);
    this.chart.ctx.fillStyle = 'black';
    this.chart.ctx.textBaseline = 'middle';
    this.chart.ctx.textAlign = 'start';
    this.chart.ctx.font="18px Verdana";

    var total = 0;
    for (var i = 0; i < this.segments.length; i++) { 
        total += this.segments[i].value;      
    }

    this.chart.ctx.fillText(total , this.chart.width / 2 - 20, this.chart.height / 2, 100);
    for(var i = 0; i < this.segments.length; i++){
        var percentage = ((this.segments[i].value / total) * 100).toFixed(1);
        if( percentage > 3 ){
            var centreAngle = this.segments[i].startAngle + ((this.segments[i].endAngle - this.segments[i].startAngle) / 2),
                rangeFromCentre = (this.segments[i].outerRadius - this.segments[i].innerRadius) / 2 + this.segments[i].innerRadius;
            var x = this.segments[i].x + (Math.cos(centreAngle) * rangeFromCentre);
            var y = this.segments[i].y + (Math.sin(centreAngle) * rangeFromCentre);
            this.chart.ctx.textAlign = 'center';
            this.chart.ctx.textBaseline = 'middle';
            this.chart.ctx.fillStyle = '#fff';
            this.chart.ctx.font = 'normal 10px Helvetica';
            this.chart.ctx.fillText(percentage , x, y);
        }
     }
}
});
查看更多
聊天终结者
4楼-- · 2019-01-16 11:40

There is an forked version, ChartNew, that provides this functionality out of the box.

If you need to use ChartJS then you can use this revised version of @Jack's solution:

Chart.types.Doughnut.extend({
    name: "DoughnutAlt",
    draw: function() {
        Chart.types.Doughnut.prototype.draw.apply(this, arguments);
        this.chart.ctx.fillStyle = 'black';
        this.chart.ctx.textBaseline = 'middle';
        this.chart.ctx.fillText(this.segments[0].value + "%", this.chart.width / 2 - 20, this.chart.width / 2, 200);
    }
});
查看更多
我只想做你的唯一
5楼-- · 2019-01-16 11:55

I have figured out a way so that we can display the values for each region out side the graph.

Also I removed the rotation of the values and I referred to here

Add the following lines of code inside the Doughnut function. ( I have pasted the modified lines from the Chart.js file).

    var Doughnut = function(data,config,ctx){

    var segmentTotal = 0;

    //In case we have a canvas that is not a square. Minus 10 pixels as padding round the edge.
    var doughnutRadius = Min([height/2,width/2]) - 15;
    var cutoutRadius = doughnutRadius * (config.percentageInnerCutout/100);
    //Modified for setting the label values out side the arc
    var outRadius= doughnutRadius + cutoutRadius/3;
    var outRadiustop= doughnutRadius + cutoutRadius/5;
    ......
    ......
    ......

    function drawPieSegments (animationDecimal){
    :
    :



       if (config.scaleShowValues) {
                ctx.save();                
                ctx.translate(width / 2, height / 2);
                ctx.font = config.scaleFontStyle + ' ' + config.scaleFontSize + 'px ' + config.scaleFontFamily;
                ctx.textBaselne = 'middle';
                var a = (cumulativeAngle + cumulativeAngle + segmentAngle) / 2,
                    w = ctx.measureText(data[i].value).width,
                    b = Math.PI / 2 < a && a < Math.PI * 3 / 2;
                var c  = 0 < a && a < Math.PI;
                if(b){
                    ctx.textAlign = 'right';
                }
                else{
                    ctx.textAlign = 'left';
                }
                if(c){
                    ctx.translate(Math.cos(a) * outRadius +1 , Math.sin(a) * outRadius+1);

                }
                else{
                    ctx.translate(Math.cos(a) * outRadiustop, Math.sin(a) * outRadiustop);      
                }

                ctx.fillStyle = config.scaleFontColor;
                //If the segment angle less than 0.2, then the lables will overlap, so hiding it.
                if(segmentAngle > 0.2){
                    ctx.fillText(data[i].value,0,0);

                }
                ctx.restore();
     }

     ......
     ...... 

Now the values will be displayed out side each sections and it will not be rotated.

查看更多
登录 后发表回答