user3288556
user3288556

Reputation: 305

Flot Chart Crosshair Plugin with multiple charts and dynamic legend

I have two flot charts and three data sets with crosshair in sync on both charts and dynamic legends that indicates value of each point on graph. Legend in the second chart does not show value where other two work fine. How would one make third or more legends show dynamic values as well. Moreover, can one make improvements to existing code where any number of charts with crosshair in sync can be displayed? Thanks,

Here is the fiddle: http://jsfiddle.net/mashinista/Q24qN/

and this is the code

plot = null;
plot2 = null;

var data1 = [
        [gd(2012, 0, 1), 8],
        [gd(2012, 1, 1), 13],
        [gd(2012, 2, 1), 4],
        [gd(2012, 3, 4), 8],
        [gd(2012, 4, 1), 16],
        [gd(2012, 5, 1), 20],
        [gd(2012, 6, 1), 29],
        [gd(2012, 7, 1), 23],
        [gd(2012, 8, 1), 28],
        [gd(2012, 9, 1), 16],
        [gd(2012, 10, 1), 8],
        [gd(2012, 11, 2), 4]
];


var data2 = [
        [gd(2012, 0, 1), 16],
        [gd(2012, 1, 1), 14],
        [gd(2012, 2, 1), 22],
        [gd(2012, 3, 1), 30],
        [gd(2012, 4, 1), 28],
        [gd(2012, 5, 1), 39],
        [gd(2012, 6, 1), 38],
        [gd(2012, 7, 1), 28],
        [gd(2012, 8, 1), 31],
        [gd(2012, 9, 1), 28],
        [gd(2012, 10, 1), 22],
        [gd(2012, 11, 1), 16]
];

var data3 = [
        [gd(2012, 0, 1), 16],
        [gd(2012, 1, 1), 14],
        [gd(2012, 2, 1), 22],
        [gd(2012, 3, 1), 30],
        [gd(2012, 4, 1), 28],
        [gd(2012, 5, 1), 39],
        [gd(2012, 6, 1), 29],
        [gd(2012, 7, 1), 23],
        [gd(2012, 8, 1), 28],
        [gd(2012, 9, 1), 16],
        [gd(2012, 10, 1), 8],
        [gd(2012, 11, 2), 4]
];

function gd(year, month, day) {
        return new Date(year, month, day).getTime();
}

$(function () {
    var sin = [], cos = []; 
    for (var i = 0; i < 14; i += 0.1) {
        sin.push([i, Math.sin(i)]);
        cos.push([i, Math.cos(i)]);
    }

    plot = $.plot($("#placeholder"),
                      [ { data: data1, label: "Query1 = 0.00"}, {
                data: data2, label: "Query2 = 0.00"}],
                  {
                            series: {
                                lines: { show: true }
                            },
                            crosshair: { mode: "x" },
                            grid: { hoverable: true, autoHighlight: false},
                            yaxis: { min: 0, max: 40 },
                          xaxis: {mode: "time"}
                        });

    plot2 = $.plot($("#placeholder2"),
                      [ { data: data3, label: "Query3 = 0.00"} ], {
                            series: {
                                lines: { show: true },
                                color: "#2eef34"
                            },
                            crosshair: { mode: "x" },
                            grid: { hoverable: true, autoHighlight: false},
                            yaxis: { min: 0, max: 40 },
                          xaxis: {mode: "time"}
                        });
    var legends = $("#placeholder .legendLabel, #placeholder .legendLabel");
    var updateLegendTimeout = null;
        var latestPosition = null;

        function updateLegend() {
                updateLegendTimeout = null;

                var pos = latestPosition;

                var axes = plot.getAxes();
                if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max || pos.y < axes.yaxis.min || pos.y > axes.yaxis.max) return;

                var i, j, dataset = plot.getData();
                for (i = 0; i < dataset.length; ++i) {
                        var series = dataset[i];

                        // find the nearest points, x-wise
                        for (j = 0; j < series.data.length; ++j)
                        if (series.data[j][0] > pos.x) break;

                        // now interpolate
                        var y, p1 = series.data[j - 1],
                                p2 = series.data[j];
                        if (p1 == null) y = p2[1];
                        else if (p2 == null) y = p1[1];
                        else y = p1[1] + (p2[1] - p1[1]) * (pos.x - p1[0]) / (p2[0] - p1[0]);

                        legends.eq(i).text(series.label.replace(/=.*/, "= " + y.toFixed(2) + " "));
                }
        }

        $("#placeholder").bind("plothover", function (event, pos, item) {
            plot2.setCrosshair({x: pos.x}),
                latestPosition = pos;
                if (!updateLegendTimeout) updateLegendTimeout = setTimeout(updateLegend, 50);
        });

     $("#placeholder2").bind("plothover", function (event, pos, item) {
                plot.setCrosshair({x: pos.x}),
                latestPosition = pos;
                if (!updateLegendTimeout) updateLegendTimeout = setTimeout(updateLegend, 50);
        });  
    });

Upvotes: 1

Views: 1391

Answers (1)

Raidri
Raidri

Reputation: 17560

There were two errors which needed fixing:

1) Your legends array contains only the legends from the first plot:

var legends = $("#placeholder .legendLabel, #placeholder .legendLabel");

needs to be

var legends = $("#placeholder .legendLabel, #placeholder2 .legendLabel");

2) In your updateLegend method you only use the data from the first plot:

var i, j, dataset = plot.getData();

I added a for loop over both plots / datasets:

for (var p = 0; p <= 1; p++) {
    var i, j, dataset;
    if (p == 0) dataset = plot.getData();
    else dataset = plot2.getData();

    ...

    legends.eq(i + p * 2).text(series.label.replace(/=.*/, "= " + y.toFixed(2) + " "));

See this updated fiddle for the working code.

3) More charts:

If you want to add a larger number of charts then you need to change the same lines of code as above. For the dataset you can use a switch statement or build an array of flot objects and then use something like

var dataset = plot[p].getData();

And for the legend number you have to count the number of legends / dataseries per chart:

legends.eq(i + countOfLegendsFromOtherCharts(p)).text( ... );

with something like this (but maybe better store this values somewhere):

function countOfLegendsFromOtherCharts(p) {
    var count = 0;
    for (var i = 0; i < p; i++) {
        var dataset = plot[p].getData();
        count += dataset.length;
    }
    return count;
}

Upvotes: 3

Related Questions