Properly rendering sparklines in a datatable

人走茶凉 提交于 2019-12-05 04:26:01

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.

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;
        }
Gayu

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>'
        }
    });
}

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.

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');

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!