Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Properly rendering sparklines in a datatable

In my example posted below I am attempting to render a sparkline from the jquery.sparkline library as a column of data in a jquery.dataTables table. Loading the example below works just fine but only for the first page. If I click on 'next' instead of having the data render as a sparkline it simply renders the numbers. If I click 'previous' the sparklines show up for the initial set. If I sort I get a combination of the two.

I'm new to both of these libraries and I have tried to look on this forum as well as others for solutions and so far none of my findings have solved my problem. Anyone know what I'm doing wrong?

Thanks for any suggestions!

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <style type="text/css" title="currentStyle">
    @import "http://datatables.net/release-datatables/media/css/demo_page.css";
    @import "http://datatables.net/release-datatables/media/css/jquery.dataTables.css";

        td.right {
            text-align: right;
        }
    </style>

<script type="text/javascript" src="http://code.jquery.com/jquery-2.0.3.js"></script>
<script type="text/javascript" src="http://datatables.net/release-datatables/media/js/jquery.dataTables.js"></script>
<script type="text/javascript" src="http://omnipotent.net/jquery.sparkline/2.1.2/jquery.sparkline.js"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            $('#dynamic').html('<table cellpadding="0" cellspacing="0" border="0" class="display" id="example"></table>');
            $('#example').dataTable({
                "aaSorting": [],
                "aaData": [
                    ["0,1,2,3,4"],
                    ["4,3,2,1,0"],
                    ["0,1,2,3,4"],
                    ["4,3,2,1,0"],
                    ["0,1,2,3,4"],
                    ["4,3,2,1,0"],
                    ["0,1,2,3,4"],
                    ["4,3,2,1,0"],
                    ["0,1,2,3,4"],
                    ["4,3,2,1,0"],
                    ["0,1,2,3,4"],
                    ["4,3,2,1,0"]
                ],
                "aoColumns": [
                    { "sTitle": "Sparkline", "sClass": "center" }
                ],
                "aoColumnDefs": [
                    {
                        "aTargets": [0],
                        "mRender": function (data, type, full) {
                            return '<span class="spark">' + data + '</span>'
                        }
                    }
                ],
                "fnInitComplete": function (oSettings, json) {
                    $('.spark').sparkline('html', {
                        type: 'line',
                        minSpotColor: 'red',
                        maxSpotColor: 'green',
                        spotColor: false
                    });
                }
            });
        });
    </script>
</head>

<body id="dt_example">

<div id="container">
    <div id="dynamic"></div>
    <div class="spacer"></div>
</div>

</body>
</html>
like image 500
Joshua Avatar asked Jan 02 '14 01:01

Joshua


4 Answers

Your answer did not work for me, but the following did, and I believe it is a lot cleaner.

Instead of changing the sparkline jquery plugin, just don't call .sparkline() in the fnDrawCallback every time. This can be managed by simply changing your selector to this:

"fnDrawCallback": function (oSettings) {
    $('.spark:not(:has(canvas))').sparkline('html', {
        type: 'line',
        minSpotColor: 'red',
        maxSpotColor: 'green',
        spotColor: false
    });
}

The selectors selects all elements with the spark class, excluding the ones with a canvas element inside.

like image 188
Jeffrey Klardie Avatar answered Sep 22 '22 09:09

Jeffrey Klardie


After spending some time debugging the libraries I've found that part of the issue is I shouldn't be initializing the sparklines in 'fnInitComplete'. This is only triggered on the fist page and the document only contains the visible rows. I should be doing it in 'fnDrawCallback'. So the code would be:

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <style type="text/css" title="currentStyle">
        @import "/static/css/demo_page.css";
        @import "/static/css/jquery.dataTables.css";

        td.right {
            text-align: right;
        }
    </style>

    <script type="text/javascript" src="/static/js/jquery-2.0.3.js"></script>
    <script type="text/javascript" src="/static/js/jquery.dataTables.js"></script>
    <script type="text/javascript" src="/static/js/jquery.sparkline.js"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            $('#dynamic').html('<table cellpadding="0" cellspacing="0" border="0" class="display" id="example"></table>');
            var table = $('#example').dataTable({
                "aaSorting": [],
                "aaData": [
                    ["0,1,2,3,4"],
                    ["4,3,2,1,0"],
                    ["0,1,2,3,4"],
                    ["4,3,2,1,0"],
                    ["0,1,2,3,4"],
                    ["4,3,2,1,0"],
                    ["0,1,2,3,4"],
                    ["4,3,2,1,0"],
                    ["0,1,2,3,4"],
                    ["4,3,2,1,0"],
                    ["0,1,2,3,4"],
                    ["4,3,2,1,0"],
                    ["0,1,2,3,4"],
                    ["4,3,2,1,0"],
                    ["0,1,2,3,4"],
                    ["4,3,2,1,0"]
                ],
                "aoColumns": [
                    { "sTitle": "Sparkline", "sClass": "center" }
                ],
                "aoColumnDefs": [
                    {
                        "aTargets": [0],
                        "mRender": function (data, type, full) {
                            return '<span class="spark">' + data + '</span>';
                        }
                    },
                ],
                "fnDrawCallback": function (oSettings) {
                    $('.spark').sparkline('html', {
                        type: 'line',
                        minSpotColor: 'red',
                        maxSpotColor: 'green',
                        spotColor: false
                    });
                }
            });
        });
    </script>
</head>

<body id="dt_example">

<div id="container">
    <div id="dynamic"></div>
</div>

</body>
</html>

This still causes an issue because the sparkline library will re-initialize the sparkline with the wrong data on the second viewing of a page since we call 'sparkline' in the fnDrawCallback which gets called every time you click on 'next' or 'previous' to repaint the table with the proper data. If you click on 'next' and then 'previous' the sparkline will get re-initialized but with the canvas data that's in the DOM from our first call. To get around this final issue I simply modified the sparkline render method to skip rendering if we've already done so. My way of doing this is probably not the best, simply looking to see if the val of the tag contains 'canvas' but it does solve my issue. I'll post a question to the sparkline library maintainer and see if they have a better way of handling this.

Here's the code modification I made in jquery.sparkline.js. I modified the render function on approx line 947 to include the check for 'canvas' and return if it's already there.

    render = function () {
        var values, width, height, tmp, mhandler, sp, vals;
        if (userValues === 'html' || userValues === undefined) {
            vals = this.getAttribute(options.get('tagValuesAttribute'));
            if (vals === undefined || vals === null) {
                vals = $this.html();
            }

            # Don't re-render if we already have.
            if (vals.indexOf('canvas') === 1) {
                return;
            }

            values = vals.replace(/(^\s*<!--)|(-->\s*$)|\s+/g, '').split(',');
        } else {
            values = userValues;
        }
like image 40
Joshua Avatar answered Sep 22 '22 09:09

Joshua


Found this to do the trick. Including 3 stacked bar charts together as sparkline in data tables.

BackEnd Data:

<span class="mysparkline" linevalues="1,2,3,4,5,6" barvalues="1,6,2,3,4,5" ></span>

DataTables Code

"fnDrawCallback": function(oSettings) {
    $('.mysparkline').sparkline('html', {
        type: 'bar',
        tagValuesAttribute: 'linevalues',
        barWidth: 6,
        barSpacing: 3,
        barColor: '#fb8072',
        width: '350px',
        tooltipFormatter: function(sp, options, fields) {
            return '<div class="jqsfield"><span style="color: ' + fields[0].color + '">&#9679;</span> Perp, New Term: ' + fields[0].value + '</div>'
        }
    });
    $('.mysparkline').sparkline('html', {
        type: 'bar',
        tagValuesAttribute: 'barvalues',
        barWidth: 6,
        barSpacing: 3,
        barColor: '#36C',
        composite: true,
        tooltipFormatter: function(sp, options, fields) {
            return '<div class="jqsfield"><span style="color: ' + fields[0].color + '">&#9679;</span> Maint, Term Renew: ' + fields[0].value + '</div>'
        }
    });
}
like image 45
Gayu Avatar answered Sep 23 '22 09:09

Gayu


I came with the same problem and I found the solution is outdated for the newest version of DataTables. For DataTables 1.10. We need to do something like this:

$('#example').dataTable( {
    "rowCallback": function( row, data ) {
        $('td:eq(0)', row).html('<span class="spark">' + data + '</span>');
    },
    "drawCallback": function (Settings) {
        $('.spark').sparkline('html', {
            type: 'line',
            minSpotColor: 'red',
            maxSpotColor: 'green',
            spotColor: false
        });
    }
});

I don't see the problem of re-rendering the spark-line though. It has taken me some time to make it work, so I am just posting what I figured out here to help anyone who might have the same problem. Thanks.

like image 32
esdotzed Avatar answered Sep 24 '22 09:09

esdotzed