Search code examples
javascriptgraphingflotr2

Flotr2 bug with bar graph dates


I have a flotr2 graph that is supposed to display some data in it:

Edit: Chrome users: Please note, this jsfiddle does not seem to work me in chrome, not sure why

http://jsfiddle.net/1jgb2k6r/7/

My problem is that my bars aren't center-aligned over the date they represent.

$(function () {
    (function color_gradients(container) {
        var myData = [];

        myData.push([new Date('1/1/2014').getTime(), Math.ceil(Math.random() * 10)]);
        myData.push([new Date('1/8/2014').getTime(), Math.ceil(Math.random() * 10)]);
        myData.push([new Date('1/15/2014').getTime(), Math.ceil(Math.random() * 10)]);
        myData.push([new Date('1/22/2014').getTime(), Math.ceil(Math.random() * 10)]);
        var
        bars = {
            data: myData,
            bars: {
                show: true,
                barWidth: 0.8,
                lineWidth: 20,
            }
        };

        graph = Flotr.draw(
        container, [bars], {
            yaxis: {
                min: 0,
                max: 11
            },
            xaxis: {
                mode: 'time',
                timeMode: 'local',
                min: (new Date('1/1/2014').getTime() - (7 * 24 * 60 * 60 * 1000)),
                max: (new Date('1/22/2014').getTime() + (7 * 24 * 60 * 60 * 1000))
            }
        });
    })(document.getElementById("editor-render-0"));
});

Is there a way in flot to realign these bars?


Solution

  • Always in the eleventh hour I post my question, and always in the eleventh hour I find the solution.

    http://jsfiddle.net/1jgb2k6r/10/

    Basically, the flot line of graphing libraries have an integral bug in their datetime calculations. They all suffer severe floating point rounding errors in relation to time axis on the graph which causes the bars to shimmy over to the left of their intended plot locations.

    Here is an example of a getTimeScale function that returns a date as a week number from epoch time (starting at ~2200 from 1/1/2014):

    function getTimeScale(date){
        return (new Date(date).getTime() / 1000 / 60 / 60 / 24 / 7);
    }
    

    This function, applied to date arguments in the data series, returns a normalized number not on the order of the hundreds of thousands:

    $(function () {
        (function color_gradients(container) {
            var myData = [];
    
    
            myData.push([getTimeScale('1/1/2014'),Math.ceil(Math.random() * 10)]);
            myData.push([getTimeScale('1/8/2014'),Math.ceil(Math.random() * 10)]);
            myData.push([getTimeScale('1/15/2014'), Math.ceil(Math.random() * 10)]);
            myData.push([getTimeScale('1/22/2014'), Math.ceil(Math.random() * 10)]);
    
            var bars = {
                data: myData,
                bars: {
                    show: true,
                    barWidth: 0.8,
                    lineWidth: 1,
                }
            };
    
            graph = Flotr.draw(
            container, [bars], {
                yaxis: {
                    min: 0,
                    max: 11
                },
                xaxis: {
                    ticks: ticks,
                    min: (getTimeScale('1/1/2014') - 1),
                    max: (getTimeScale('1/22/2014') + 1)
                }
            });
        })(document.getElementById("editor-render-0"));
    });
    

    In order to display the ticks as a datetime again, you have to specify the ticks explicitly:

    var ticks = [];
    
    ticks.push([getTimeScale('1/1/2014'), '1/1/2014']);
    ticks.push([getTimeScale('1/8/2014'),  '1/8/2014']);
    ticks.push([getTimeScale('1/15/2014'), '1/15/2014']);
    ticks.push([getTimeScale('1/22/2014'), '1/22/2014']);
    
    graph = Flotr.draw(
        container, [bars], {
            yaxis: {
                min: 0,
                max: 11
            },
            xaxis: {
                ticks: ticks,
                min: (getTimeScale('1/1/2014') - 1), //gives a little padding room on the graph
                max: (getTimeScale('1/22/2014') + 1) //gives a little padding room on the graph
            }
    });