Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add labels into Chart.js canvas plugin?

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.

like image 832
mllamazares Avatar asked May 16 '13 14:05

mllamazares


4 Answers

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.

like image 119
Jack Avatar answered Sep 16 '22 20:09

Jack


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);         }      } } }); 
like image 42
animesh manglik Avatar answered Sep 19 '22 20:09

animesh manglik


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);
    }
});
like image 37
dunckr Avatar answered Sep 18 '22 20:09

dunckr


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.

like image 36
Sareesh Avatar answered Sep 17 '22 20:09

Sareesh