GraFiddle / angular-chart

AngularJS directive for adjustable dynamically updating c3 charts
http://grafiddle.github.io/angular-chart/
MIT License
127 stars 40 forks source link

.getbbox error with firefox #106

Open btm1 opened 9 years ago

btm1 commented 9 years ago

I would do a pull request for this but I just don't have the time:

Have you guys heard of this error in FF? https://bugzilla.mozilla.org/show_bug.cgi?id=612118 it's been around for quite some time and moz seems to have no intention of fixing it because it would require a pretty extensive rework because of gecko.

To make a long story short c3.js and just about every other svg library on the planet uses a method .getbBox() to get the dimensions of a given element. With FF however if this method is called too quickly before the parent svg element that contains the text node is actually rendered than the browser will break with a DOM exception that looks something like this (the one from C3 looks a bit different but it's the same concept):

Error: uncaught exception: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIDOMSVGLocatable.getBBox]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: file:///home/laaglu/workspaces/lab/svglab/pbFirefoxBBox.html :: earlyBbox :: line 34"  data: no]

So in most cases angular-char is fine where ever it's used and I use it in a pretty large production level application. However if the directive is rendered inside of a directive that uses ng-if which then conditionally renders the directive element than you get this error.

I hate "timeout zero" but I ended up having to mod your directive code so that it waits until the DOM element is fully rendered before calling that activate function. Again this wasn't needed in all cases but I was using the chart inside of angular ui bootstrap tabs and it was failing anywhere inside of this directive but not failing outside of it.

I would suggest adding this to the directive where you use activate() either that or I suppose you could be more clever and do something like this:

try {
//somehow test the .getbBox() method on something inside of the directive and if it works than just activate()
} catch (e) {
// if it fails the .getbBox() method than just $timeout(activate,0);
}

This way it wouldn't wait all the time but would only wait in the situations where it's needed

Or you could just do what I did and wait all the time:

var isFirefox = typeof InstallTrigger !== 'undefined';
    if(isFirefox) {
        $timeout(activate,0);
    } else {
        activate();
    }
maxklenk commented 9 years ago

Thank you, I will look into this and will get back to you.