Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to display Line Chart dataset point labels with Chart.js?

I have a design requirement to display a line chart with 5 datasets of trends data. Each data value along the stroke lines need to be showing a data value label at its respective data point.

Unfortunately, I cannot find an option within Charts.js that will satisfy this requirement.

Is there a workaround that can help me out?

I've posted this on fiddle too: http://jsfiddle.net/s9eannLh/

Thanks so much!

    var data = {
                labels: ["","Jun 2013","Jul 2013","Aug 2013","Sep 2013","Oct 2013","Nov 2013","Dec 2013","Jan 2014","Feb 2014","Mar 2014","Apr 2014","May 2014"],
                datasets: [
                    {
                        label: "hemoglobin_1",
                        title: "test",
                        fillColor: "transparent",
                        strokeColor: "#65204c",
                        pointColor: "#65204c",
                        pointHighlightStroke: "#FFF",
                        data: [null,5.7,5.7,5.8,5.7,5.8,5.7,5.9,6.7,6.7,6.5,6.4,6.4]
                    },
                    {
                        label: "hemoglobin_2",
                        fillColor: "transparent",
                        strokeColor: "#ed7141",
                        pointColor: "#ed7141",
                        pointHighlightStroke: "#FFF",
                        data: [null,15.5,15.5,15.6,15.2,15.6,15.1,15.8,17,17.4,16.8,16.4,16.4]
                    },                    
                    {
                        label: "hemoglobin_3",
                        fillColor: "transparent",
                        strokeColor: "#de4760",
                        pointColor: "#de4760",
                        pointHighlightStroke: "#FFF",
                        data: [null,37.1,37,37.2,37.6,36.9,37.6,36.8,37.6,38,37.5,39.1,37.5]
                    },
                    {
                        label: "hemoglobin_4",
                        fillColor: "transparent",
                        strokeColor: "#fdcf7e",
                        pointColor: "#fdcf7e",                          
                        pointHighlightStroke: "#FFF",
                        data: [null,29.9,30.4,29.5,29.6,30.2,29.4,29.8,26.9,27,28.5,26.8,28.5]
                     },                                        
                    {
                        label: "hemoglobin_5",
                        fillColor: "transparent",
                        strokeColor: "#a33a59",
                        pointColor: "#a33a59",
                        pointHighlightStroke: "#FFF",
                        data: [null,11.8,11.4,11.9,11.9,11.5,12.2,11.7,11.8,10.9,10.7,11.3,11.3]
                    }
                ]
            };

            var options = {
                responsive: true,
                scaleOverride: true,
                scaleSteps: 10,
                scaleStepWidth: 5,
                scaleStartValue: 0,
                showTooltips: false,
                pointDot: true,
                pointDotRadius : 6,
                datasetStrokeWidth : 3,
                bezierCurve : false,
                scaleShowHorizontalLines: false,
                scaleGridLineWidth : 2,
                scaleGridLineColor : "#EEEEEE",
                scaleLineWidth: 3,
                scaleLineColor: "#000000",
                scaleFontFamily: '"Gotham Book",sans-serif',
                scaleFontSize: 18
            }

            var ctx = $("#myChart").get(0).getContext("2d");
            var Trends = new Chart(ctx).Line(data, options);
like image 451
JBMcClure Avatar asked Jan 09 '15 23:01

JBMcClure


2 Answers

I was able to finally find the solution to this question.

I realized I had access to the chart object within the DOM:

Trends.datasets

Within each of the five datasets there was a points object containing x & y positions:

Trends.datasets[0..4].points

So I parsed through the points with a callback utilizing the global configuration functions in Chart.js:

    // Function - Will fire on animation progression.
     onAnimationProgress: function(){},

   // Function - Will fire on animation completion.
    onAnimationComplete: function(){}

I found that I had to use onAnimationComplete with responsive: true because the point labels would get wiped out on a resize event.

Once I found the points within the callback, I simply wrote the labels I wanted onto the canvas.

My additions to the code were:

var options = {
    onAnimationProgress: function() { drawDatasetPointsLabels() },
    onAnimationComplete: function() { drawDatasetPointsLabels() }
}

With the added function:

    function drawDatasetPointsLabels() {
            ctx.font = '.9rem "Gotham Book",sans-serif';
            ctx.fillStyle = '#AAA';
            ctx.textAlign="center";
            $(Trends.datasets).each(function(idx,dataset){
                $(dataset.points).each(function(pdx,pointinfo){
                    // First dataset is shifted off the scale line. 
                    // Don't write to the canvas for the null placeholder.
                    if ( pointinfo.value !== null ) { 
                        ctx.fillText(pointinfo.value,pointinfo.x,pointinfo.y - 15);
                    }
                });
            });         
         }

So here is the entire code source along with the new code providing the solution:

    var data = {
                labels: ["","Jun 2013","Jul 2013","Aug 2013","Sep 2013","Oct 2013","Nov 2013","Dec 2013","Jan 2014","Feb 2014","Mar 2014","Apr 2014","May 2014"],
                datasets: [
                    {
                        label: "hemoglobin_1",
                        fillColor: "transparent",
                        strokeColor: "#65204c",
                        pointColor: "#65204c",
                        pointHighlightStroke: "#FFF",
                        data: [null,5.7,5.7,5.8,5.7,5.8,5.7,5.9,6.7,6.7,6.5,6.4,6.4]
                    },
                    {
                        label: "hemoglobin_2",
                        fillColor: "transparent",
                        strokeColor: "#ed7141",
                        pointColor: "#ed7141",
                        pointHighlightStroke: "#FFF",
                        data: [null,15.5,15.5,15.6,15.2,15.6,15.1,15.8,17,17.4,16.8,16.4,16.4]
                    },                    
                    {
                        label: "hemoglobin_3",
                        fillColor: "transparent",
                        strokeColor: "#de4760",
                        pointColor: "#de4760",
                        pointHighlightStroke: "#FFF",
                        data: [null,37.1,37,37.2,37.6,36.9,37.6,36.8,37.6,38,37.5,39.1,37.5]
                    },
                    {
                        label: "hemoglobin_4",
                        fillColor: "transparent",
                        strokeColor: "#fdcf7e",
                        pointColor: "#fdcf7e",                          
                        pointHighlightStroke: "#FFF",
                        data: [null,29.9,30.4,29.5,29.6,30.2,29.4,29.8,26.9,27,28.5,26.8,28.5]
                     },                                        
                    {
                        label: "hemoglobin_5",
                        fillColor: "transparent",
                        strokeColor: "#a33a59",
                        pointColor: "#a33a59",
                        pointHighlightStroke: "#FFF",
                        data: [null,11.8,11.4,11.9,11.9,11.5,12.2,11.7,11.8,10.9,10.7,11.3,11.3]
                    }
                ]
            };

    var options = {
                responsive: true,
                scaleOverride: true,
                scaleSteps: 10,
                scaleStepWidth: 5,
                scaleStartValue: 0,
                showTooltips: false,
                pointDot: true,
                pointDotRadius : 6,
                datasetStrokeWidth : 3,
                bezierCurve : false,
                scaleShowHorizontalLines: false,
                scaleGridLineWidth : 2,
                scaleGridLineColor : "#EEEEEE",
                scaleLineWidth: 3,
                scaleLineColor: "#000000",
                scaleFontFamily: '"Gotham Book",sans-serif',
                scaleFontSize: 18,
                onAnimationProgress: function() { drawDatasetPointsLabels() },
                onAnimationComplete: function() { drawDatasetPointsLabels() }                    
            }
            var ctx = $("#myChart").get(0).getContext("2d");
            var Trends = new Chart(ctx).Line(data, options);            

        function drawDatasetPointsLabels() {
            ctx.font = '.9rem "Gotham Book",sans-serif';
            ctx.fillStyle = '#AAA';
            ctx.textAlign="center";
            $(Trends.datasets).each(function(idx,dataset){
                // First dataset is shifted off the scale line. 
                // Don't write to the canvas for the null placeholder.
                $(dataset.points).each(function(pdx,pointinfo){
                    if ( pointinfo.value !== null ) {
                        ctx.fillText(pointinfo.value,pointinfo.x,pointinfo.y - 15);
                    }
                });
            });         
        }

Here is the original problematic version on jsfiddle: http://jsfiddle.net/s9eannLh

[Updated link] And here is the updated solution on jsfiddle: https://jsfiddle.net/s9eannLh/82/

Thanks all!

like image 183
JBMcClure Avatar answered Oct 05 '22 18:10

JBMcClure


In case anyone comes here looking for this as I did recently, there's a new plug in available.

https://github.com/chartjs/chartjs-plugin-datalabels

like image 22
Jeremy L. Avatar answered Oct 05 '22 17:10

Jeremy L.