You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
After calling resize() and fit() or contain() on a SVG that is not visible, the user should be able to restore full functionality by making the SVG visible again and then using resize() and fit() or contain() in order to restore a usable viewport.
Actual behaviour
If the fit() or contain() method is run on a SVG while it's not visible due to it or its parent element not being displayed on the DOM, those methods (as well as the zoom, pan, and reset methods) will all become broken and will cause a Javascript error on subsequent uses. Since the error also affects fit() and contain(), it's impossible to get back into a usable state without refreshing.
The error is "InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable" in Firefox and "Uncaught InvalidStateError: Failed to execute 'inverse' on 'SVGMatrix': The matrix is not invertible" in Chrome.
Click the "Hide SVG" button to hide the SVG with "display:none".
Click the "fit()" button to run the resize() and fit() methods on the SVG while it's hidden.
Click the "Show All" button to make the SVG visible again.
Click the "fit()" button to run the resize() and fit() methods on the SVG now that it's visible.
The fit() method will cause the embedded controls to appear appropriately, but will then fail with a Javascript error which will be displayed in the browser console.
Refresh the page to clear this broken state.
Click the "Hide Container" button to hide the container div that the SVG is inside.
Click the "contain()" button to run the resize() and contain() methods on the SVG, which is not visible because its parent element is not displayed.
Click the "Show All" button to make the container visible again.
Click the "contain()" button to run the resize() and contain() methods on the SVG, which is now visible again because its parent element is visible.
The fit() method will cause the embedded controls to appear appropriately, but will then fail with a Javascript error which will be displayed in the browser console.
Click the zoom in or zoom out button on the SVG. You will get the same Javascript error.
Click the Reset button on the SVG. You will get the same Javascript error.
Try to pan the SVG by clicking and dragging. You will get the same Javascript error.
Calling resize() and then fit() or contain() while the SVG is not visible essentially zeroes out the CTM. Later operations will then fetch the current CTM, which will be all zeroes, and attempt to transform them, leading to a Javascript error on the inverse() call because inverting a zeroed-out SVGMatrix appears to be an invalid operation. Since this issue affects all further zooming, panning, resetting, and both fit() and contain(), the user is put into an unrecoverable state in which the SVG is impossible to interact with until the instance is destroyed and recreated or the page is refreshed.
That being said, it's easy enough for developers to work around once the issue is understood - just make sure not to resize() and fit()/contain() when the SVG isn't displayed. That shouldn't affect functionality, since there's no real need to make those calls when the SVG isn't displayed, so it's typically just tied to a resize call that runs whether or not the SVG is currently visible. It's just a matter of knowing about this issue and making sure to account for it and ensure that these calls aren't run when the SVG isn't displayed.
The text was updated successfully, but these errors were encountered:
Thank you for this very detailed report.
There were few related bug reports in past (although not that detailed: #105, #247). From what I remember the issue was that some browsers simply remove the entire SVG element from DOM when it (or it's parent) have display: hidden. It is probably an optimisation technique, but it just makes the SVG unusable.
I don't think we can do much about it, and I don't think we should check if the element and all it's parents are visible on each method call. It will just add overhead (mostly in terms of reasoning about code and behaviour) for an edge case.
I'll keep this issue open so that other people who'll stumble upon it will know that it's an expected behaviour.
Adding a console message or throwing a clearer error when a zeroed-out SVGMatrix passes through getCTM() might help, since the standard error message is a bit vague (especially on Firefox). Other than that, though, I agree - I thought about it a while, and while detecting the potential failure state is easy enough, actually handling it introduces a fair amount of complexity for something that's not terribly difficult for people to just work around.
Bug report
Expected behaviour
After calling resize() and fit() or contain() on a SVG that is not visible, the user should be able to restore full functionality by making the SVG visible again and then using resize() and fit() or contain() in order to restore a usable viewport.
Actual behaviour
If the fit() or contain() method is run on a SVG while it's not visible due to it or its parent element not being displayed on the DOM, those methods (as well as the zoom, pan, and reset methods) will all become broken and will cause a Javascript error on subsequent uses. Since the error also affects fit() and contain(), it's impossible to get back into a usable state without refreshing.
The error is "InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable" in Firefox and "Uncaught InvalidStateError: Failed to execute 'inverse' on 'SVGMatrix': The matrix is not invertible" in Chrome.
Steps to reproduce the behaviour
simple reproduction case: https://codepen.io/mdb07a/pen/YYMLqW
Click the "Hide SVG" button to hide the SVG with "display:none".
Click the "fit()" button to run the resize() and fit() methods on the SVG while it's hidden.
Click the "Show All" button to make the SVG visible again.
Click the "fit()" button to run the resize() and fit() methods on the SVG now that it's visible.
The fit() method will cause the embedded controls to appear appropriately, but will then fail with a Javascript error which will be displayed in the browser console.
Refresh the page to clear this broken state.
Click the "Hide Container" button to hide the container div that the SVG is inside.
Click the "contain()" button to run the resize() and contain() methods on the SVG, which is not visible because its parent element is not displayed.
Click the "Show All" button to make the container visible again.
Click the "contain()" button to run the resize() and contain() methods on the SVG, which is now visible again because its parent element is visible.
The fit() method will cause the embedded controls to appear appropriately, but will then fail with a Javascript error which will be displayed in the browser console.
Click the zoom in or zoom out button on the SVG. You will get the same Javascript error.
Click the Reset button on the SVG. You will get the same Javascript error.
Try to pan the SVG by clicking and dragging. You will get the same Javascript error.
Configuration
3.5.2
IE11, Firefox, Chrome
Windows 10
Other Notes
Calling resize() and then fit() or contain() while the SVG is not visible essentially zeroes out the CTM. Later operations will then fetch the current CTM, which will be all zeroes, and attempt to transform them, leading to a Javascript error on the inverse() call because inverting a zeroed-out SVGMatrix appears to be an invalid operation. Since this issue affects all further zooming, panning, resetting, and both fit() and contain(), the user is put into an unrecoverable state in which the SVG is impossible to interact with until the instance is destroyed and recreated or the page is refreshed.
That being said, it's easy enough for developers to work around once the issue is understood - just make sure not to resize() and fit()/contain() when the SVG isn't displayed. That shouldn't affect functionality, since there's no real need to make those calls when the SVG isn't displayed, so it's typically just tied to a resize call that runs whether or not the SVG is currently visible. It's just a matter of knowing about this issue and making sure to account for it and ensure that these calls aren't run when the SVG isn't displayed.
The text was updated successfully, but these errors were encountered: