flot in a hidden div

I’m using the insanely awesome Flot JQuery plotting/charting package for the soon-to-be-released range limit plugin for Blacklight.

So one problem I ran into. The place I’d like to put my Flot chart is in a div on screen that is often initially hidden, and only shown when the user expands it by clicking on a heading.

There are at least two problems with that. One is that Flot requires an explicit width and height to be set.  But I’d like to have my plugin be ‘liquid’ in it’s display of flot.  Flot is fine if you set the width and height with javascript, as long as you do it before you draw Flot. Okay, so I figure I can look up the width with JQuery.width(), compute the height using a good ratio.  Except you can’t look up the width of a hidden div, it doesn’t have one.

The other, more obvious problem, is that Flot simply won’t draw in a hidden div, even if you do explicitly set the width and height. It does all sorts of wild calculations to figure out the best places to put labels and such, and it can’t do that unless it’s placeholder container is actually in the DOM, not hidden.

So, I thought, okay, it needs to be shown, but what if it’s shown, but off screen (absolutely positioned somewhere way off the monitor). Does that work?  Well, sort of, sometimes. If I took only the plot placeholder div and moved it off screen, Flot would be willing to draw, but when I later moved it back on-screen to view it, flot’s labels and tick marks and such were all over the place, in the wrong places.

But. If I took the parent div to the flot placeholder, the one that in my page is actually being hidden and shown, and moved it off-screen… everything worked.

So here’s what I do to draw a Flot chart “off screen” without really being off-screen.   Show the parent div; calculate the width/height; move the parent div off screen, have Flot draw itself, re-hide the parent div, put it back on screen. It all happens quick enough that it’s as-if Flot were drawn in a hidden div.

Working in the four browsers. It may not exactly be a general purpose solution, because it may depend to some extent on the surrounding DOM, but it works in my DOM.

Here’s a nice little wrapper routine I wrote that, at least in my case, does the job. (using a javascript closure to wrap the actual drawing).

// example use:

wrapPrepareForFlot( $(placeholder_div), $(parent_that_might_be_hidden),
                    desired_width_to_height_ratio,
                    function(placeholder) {
                       //code to actually draw Flot goes here
                    });

// definition:
  /* Set up dom for flot rendering: flot needs to render in a non-hidden
     div with explicitly set width and height. The non-hidden thing
     is annoying to us, since it might be in a hidden facet limit.
     Can we get away with moving it off-screen? Not JUST the flot
     container, or it will render weird. But the whole parent
     limit content, testing reveals we can. */
    function wrapPrepareForFlot(container, parent_section, widthToHeight, call_block) {
        var parent_originally_hidden = $(parent_section).css("display") == "none";
        if (parent_originally_hidden) {
          $(parent_section).show();
        }
        $(container).width( $(parent_section).width() );
        $(container).height( $(parent_section).width() * widthToHeight );
        if (parent_originally_hidden) {
          parent_section.addClass("ui-helper-hidden-accessible");
        }

        call_block(container);

        if (parent_originally_hidden) {
          $(parent_section).removeClass("ui-helper-hidden-accessible");
          $(parent_section).hide();
        }
    }

There’s a different approach you could take too, that I might revisit later, which would have it’s own tricks: Instead of trying to pre-render the plot in a ‘hidden’ div, don’t load it until the user actually shows the div, then start loading it. Because JS/JQuery doesn’t have a built in “onshow” event, this would take some tricks too, but should also be do-able. Wonder if there’s a JQuery plugin to provide a general purpose on-show event somehow?

This entry was posted in General. Bookmark the permalink.

3 Responses to flot in a hidden div

  1. This is much shorter :)

    $(document).ready(function() {
    drawFlot(); // draw it to #initialPlaceHolder
    $(‘#finalPlaceHolder’).append( $(‘#initialPlaceHolder’) );
    });

    HTML:

  2. Sorry, HTML got cropped.

    <div style=”position: absolute; left: -2000px;”>
    <div id=”initialPlaceHolder” style=”width:600px;height:300px”></div>
    </div>

    Good job, BTW, I did base myself on your work.

  3. jrochkind says:

    Nice, that works? That does seem better. I always forget about the crazy position negative a lot trick. I still am trying to be as unobtrusive as possible on my html, so I’d want to dynamically add the div instead of including it on the original html , but that’s just one more line to add to yours. Thanks!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s