Properly rendering sparklines in a datatable
Asked Answered
E

5

7

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>
Esurient answered 2/1, 2014 at 1:25 Comment(0)
T
8

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.

Tideway answered 30/9, 2014 at 21:20 Comment(3)
Thanks for posting this! Definitely better to do it locally rather than need to update the library. Hopefully this all gets cleaned up by the maintainer of the sparkline lib so we don't have to do workarounds in the future. Again, thanks for posting this.Esurient
the charts are there, but whenever you paginate back they are goneAberdare
solved it. Modified sparkline's code as shown in the bottom of this post: 4byte.cn/question/266312/… works great. you might want to include it in your answer somewhereAberdare
E
5

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;
        }
Esurient answered 3/1, 2014 at 18:1 Comment(3)
Any news on this, I'm having the same issue. Would you mind showing the mod yo made to the sparklines library... ThanksBarnyard
I am posting an update to my original response with the code change right now.Esurient
Thanks for popping back and updating your answer, really appreciated.Barnyard
S
4

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>'
        }
    });
}
Snobbish answered 28/3, 2016 at 17:51 Comment(1)
great answer. I have started working on the composite feature in sparkline github.com/htmlwidgets/sparkline/issues/…. I would love examples, use cases, and feedback.Theatheaceous
A
2

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.

Aircraft answered 15/1, 2015 at 20:40 Comment(2)
Hi, can you show how the data should be rendered initially in the columns array?Blastocoel
Also I had a specify a field in data because data itself is an object, for example: $('td:eq(0)', row).html('<span class="spark">' + data[0] + '</span>');Blastocoel
B
2

Same Problem with paging and rerendering sparkline losing the first rendered sparklines in my jqgrid table. Solved it in my case by removing the sparkline selector class once rendered so I can call sparkline for all additional loaded tables via the jqgrid event loadComplete

$('.inlinesparkline').sparkline('html', {type: 'line' ,disableHiddenCheck: true, height: '20px', width: '90px'}).removeClass('inlinesparkline');

Breadwinner answered 23/6, 2017 at 10:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.