Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SVG 'getBBox' fails in a jQueryUI tab

I have a stand-alone SVG chart generator that works with all the major browsers. However, I've just added code to display the charts inside a jQuery UI tab, and the code has broken. Specifically, 'getBBox' now generally fails. It throws an exception in FF, works as expected in Opera, and gives the wrong answer in Chrome and Safari.

The difference between the old and new code is only, I think, in my understanding of what a 'document' is inside a tab. In the old stand-alone code, I could display a rectangle and get it's bbox as follows (in all browsers):

var svgDocument;
var svgNS = "http://www.w3.org/2000/svg";
...
if(window.svgDocument == null)
   svgDocument = evt.target.ownerDocument;
...
var lbox = svgDocument.createElementNS(svgNS, "rect");
lbox.setAttributeNS(null, "x",                50);
lbox.setAttributeNS(null, "y",                50);
lbox.setAttributeNS(null, "width",            40);
lbox.setAttributeNS(null, "height",           40);
lbox.setAttributeNS(null, "stroke",           "#E810D6");
lbox.setAttributeNS(null, "stroke-width",     2);
lbox.setAttributeNS(null, "fill-opacity",     1);
lbox.setAttributeNS(null, "stroke-opacity",   1);
lbox.setAttributeNS(null, "stroke-dasharray", 0);
svgDocument.documentElement.appendChild(lbox);     // displays the box
var bbox = lbox.getBBox();                         // gets the box bounds

The problem is that, when I try to display inside a tab, it's not obvious what svgDocument should be. This is my current code:

var svgDocument = document;
var svgNS       = "http://www.w3.org/2000/svg";
var svgRoot;
...
// handle jQuery UI tabs as follows:
var top, svg, chart;
top   = $(ui.panel).get(0);
svg   = svgDocument.createElementNS(svgNS, "svg");
chart = "chart" + "-" + ui.panel.id;
svg.setAttributeNS(null, "id", chart);
top.appendChild(svg);
svgRoot = svgDocument.getElementById(chart);
...
// SVG draw is identical, except that svgDocument.documentElement is now svgRoot:
var lbox = svgDocument.createElementNS(svgNS, "rect");
lbox.setAttributeNS(null, "x",                50);
lbox.setAttributeNS(null, "y",                50);
lbox.setAttributeNS(null, "width",            40);
lbox.setAttributeNS(null, "height",           40);
lbox.setAttributeNS(null, "stroke",           "#E810D6");
lbox.setAttributeNS(null, "stroke-width",     2);
lbox.setAttributeNS(null, "fill-opacity",     1);
lbox.setAttributeNS(null, "stroke-opacity",   1);
lbox.setAttributeNS(null, "stroke-dasharray", 0);
svgRoot.appendChild(lbox);
var bbox = lbox.getBBox();

The new code works "correctly" in Opera. FF, Chrome, and Safari display the rectangle correctly in the new tab, but get the bbox calculation wrong.

Any idea what I'm doing wrong here? Thanks.

[this is probably the same issue as Doing Ajax updates in SVG breaks getBBox, is there a workaround?, but there were no answers on that].

EDIT

I failed to mention that I'm rendering into a hidden tab, which is only displayed when the chart completes. Googling the FF exception code (in the comment below) indicates that there's some issue with getBBox when the element is not displayed. However, I don't understand this. I routinely use getBBox with visibility:hidden to size complex elements before displaying them, on all browsers (when I'm not using tabs). Besides, the rectangle in the example does actually render, as I can see it when the tab becomes visible, so shouldn't getBBox should also work?

like image 444
EML Avatar asked Jan 01 '12 22:01

EML


1 Answers

Fixed - the answer is actually in the tabs documentation. Whoops.

From http://docs.jquery.com/UI/Tabs#...my_slider.2C_Google_Map.2C_sIFR_etc._not_work_when_placed_in_a_hidden_.28inactive.29_tab.3F

Any component that requires some dimensional computation for its initialization won't work in a hidden tab, because the tab panel itself is hidden via display: none so that any elements inside won't report their actual width and height (0 in most browsers).

There's an easy workaround. Use the off-left technique for hiding inactive tab panels. E.g. in your style sheet replace the rule for the class selector ".ui-tabs .ui-tabs-hide" with

.ui-tabs .ui-tabs-hide {
    position: absolute;
    left: -10000px;
}
like image 133
EML Avatar answered Oct 23 '22 16:10

EML