41

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.

Dennis Rongo
  • 4,611
  • 1
  • 25
  • 25
mllamazares
  • 7,876
  • 17
  • 61
  • 89
  • 3
    From that pull you posted https://github.com/Regaddi/Chart.js - It appears it is not in the master branch but that guys fork. – Jack May 16 '13 at 14:45
  • 3
    @Jack is correct, you have to use this file: https://github.com/Regaddi/Chart.js/blob/9fe98b61c5c059bcf347508ac724d38f6eb83764/Chart.min.js – A. Wolff May 16 '13 at 14:47
  • 6
    See working jsfiddle: http://jsfiddle.net/7ktug/2/ – A. Wolff May 16 '13 at 14:49

4 Answers4

32

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.

Jack
  • 5,264
  • 7
  • 34
  • 43
  • 2
    This helped me. It took a while to figure out what you were talking about but I managed through. To clear things up for other users, this code is located in the original Chart.js on line 758. You will need to modify it as the Fiddle example he provided. Mess with the numbers so that you can get it centered the way you want it. Thanks – CodeGodie Dec 13 '13 at 05:55
  • I guess the Chart.js code is changed a little at now.. I solved anyway by changing this line and adding the percentage char to the text: ctx.fillText(this.text+"%", tooltipX + tooltipWidth/2, tooltipY + tooltipRectHeight/2); – Joe Aspara Nov 24 '14 at 10:21
  • 1
    In **Chart.Doughnut.js** file, I have not found **drawPieSegments** function – Kiquenet Jun 22 '15 at 05:58
  • @Kiquenet: this answer is outdated regarding current, totally rewritten version of Chart.js. For current versions, please see answer by dunckr – Risto Välimäki Aug 26 '15 at 09:20
7

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);
        }
     }
}
});
animesh manglik
  • 755
  • 7
  • 14
  • Great work! I've [made a modification](https://gist.github.com/frankfuu/392aaeb75d9d0bf53907) to this to handle passing of custom options when intializing the chart. I also removed showing of the total inside the donut center. – Frank Fu Oct 14 '15 at 02:37
  • It appears that Chart.types. is empty so I cannot extend this using Chart.types.Doughnut.extend. I am using angular-chartjs btw. Any idea why the types parameter is empty and/or how to get it filled? – EeKay Sep 28 '16 at 06:44
3

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.

rene
  • 41,474
  • 78
  • 114
  • 152
Sareesh
  • 85
  • 1
  • 9
3

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);
    }
});
gnclmorais
  • 4,897
  • 5
  • 30
  • 41
dunckr
  • 31
  • 1
  • 2