josejaner / flot

Automatically exported from code.google.com/p/flot
MIT License
0 stars 1 forks source link

Interactive Legends: allow labelFormatter to be a fn:txt->txt or fn:txt->jquery #232

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago
In order to make the legend interactive, I suggest allowing the labelFormatter 
function to return either txt or a jquery object. 

Example use case: Clicks on a label in the legend to toggle that plot on or off 
on 
the current chart. You can certainly work around this by making your return 
value of 
labelFormatter be something like this:

function labelFormatter (labelName) {
      return '<span onclick="hideLabel(labelName);">' + ;
}

But you then have to make the hideLabel() function do some DOM lookups to 
figure out 
which chart to toggle on or off as opposed to using closures to keep things 
lexically 
local, which a full jquery object allows you to do, like this:

Chart.prototype.makeChartLegendLabel = function (tagName) {

    var tagToggle = $('<span>' + tagName + '</span>')
        .addClass('label')
        .addClass( this.inactivePlots[tagName] ? 'inactive' : 'active' )
    ;

    var selfRef = this;
    tagToggle.click(function() {selfRef.toggleTag(tagName);});

    return tagToggle;
}; 

Original issue reported on code.google.com by mathes....@gmail.com on 7 Oct 2009 at 5:21

GoogleCodeExporter commented 8 years ago
Worth noting that I have a local modified version of flot that behaves exactly 
like 
this, but it only works in some use cases. I haven't made it fully functional 
because 
I'm using it for internal stats tracking tools, and we never use the broken 
cases. 

Original comment by mathes....@gmail.com on 7 Oct 2009 at 5:22

GoogleCodeExporter commented 8 years ago
If it's helpful, here's the re-written loop that builds the <table> for the 
legend, using jquery object 
creation:

var table = $('<table style="font-size:smaller;color:' + options.grid.color + 
'"></table>');
for (i = 0; i < series.length; ++i) {
    if (!series[i].label) {
        continue;
    }

    if ( i % options.legend.noColumns == 0 ) {
        var currentRow = $('<tr></tr>');
        table.append(currentRow);
    }

    // use the raw label text or use the text or jquery object
    // returned by the use-defined labelFormatter function
    var label = series[i].label;
    if (options.legend.labelFormatter != null) {
        label = options.legend.labelFormatter(label);
    }

    var legendColorBox = $(
        '<td class="legendColorBox">'
            + '<div style="border:1px solid ' + options.legend.labelBoxBorderColor + ';padding:1px">'
                + '<div style="width:14px;height:10px;background-color:' + series[i].color + 
';overflow:hidden">'
                + '</div>'
            + '</div>'
        + '</td>'
    );
    var labelBox = $('<td class="legendLabel"></td>').append(label);

    currentRow.append(legendColorBox).append(labelBox);

}

Original comment by mathes....@gmail.com on 7 Oct 2009 at 5:50

GoogleCodeExporter commented 8 years ago
Have you considered just doing a '<span class="foo">' + value + '</span>' then
$(".foo").click(...)? It seems less complex to me?

Original comment by olau%iol...@gtempaccount.com on 21 Oct 2009 at 7:42

GoogleCodeExporter commented 8 years ago
That wouldn't work for my use case. I'ts less about having a jquery object and 
more 
about having a full variable in javascript and all that gets you with closures 
and 
attributes.

I'm using closures to do some OOP stuff with a Chart object wrapped around 
flot. 
Specifically, clicking on the label needs to call a method on the Chart object 
to 
turn the tag on/off. If I were to use the method you described, every label 
would all 
call the same function. Perhaps on some labels different functions need to be 
called? 
Would the .click() function be in the right closure? 

I'd link to an example page, but this is for an internal stats reporting tool 
that's 
behind a VPN. Here's an example screenshot:

http://imgur.com/CrF3Dl.png

Original comment by mathes....@gmail.com on 21 Oct 2009 at 8:31

GoogleCodeExporter commented 8 years ago
I had the same problem, but with a little jquery magic, here may be the start 
of a 
solution..
$("#placeholder table tr").click(function(){
     alert($(this).children(":eq(1)").html());})
will alert the legend names

regards

Original comment by petere...@gmail.com on 11 May 2010 at 6:36

GoogleCodeExporter commented 8 years ago
To Toggle legend items (lines specifically) I just used this.
It depends upon the outer-divs of flot to have a class of 'graph',
and that the return object from $.plot(...) be stored with the div object.
Example:
$('.graph').each(function(){
    // ... fetch your data and options
    var p = plot( this, mydata, myoptions );
    $(this).data('plot', p );

    $('.legendColorBox').bind('click',function(){
        var i = $(this).parents('table').find('.legendColorBox').index(this);
        var g = $(this).parents('.graph');
        var p = $(g).data('plot');
        var d = p.getData();
        var show = d[i].lines.show;
        $(this).css('opacity', (show)? 0.25 : 1.0 );
        d[i].lines.show = (show) ? false: true;
        p.draw();
    }); 

Perhaps someone could grow this into a proper plugin for all graph types?
Also note that, thus far, it seems to work 'most-of-the-time', but after a 
while the 'click' events no longer seem to fire.  Haven't started to debug that 
one yet.

Original comment by erics...@gmail.com on 21 Apr 2011 at 6:47

GoogleCodeExporter commented 8 years ago
I don't see this as high priority, but I think it makes sense to keep this for 
consideration as an enhancement.  We might solve this by adding parameters to 
labelFormatter, or introduce a new hook.

Original comment by dnsch...@gmail.com on 4 Jun 2012 at 8:21