Jump to content
Search Community

Draggable.js conflicts with Polymer in Firefox (specifically, webcomponets.js)

marianomiii-arte test
Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Hello,

 

I'm developing a web app that uses polymer to display some custom components and GSAP to drag them around.  It appears that there is a conflict between draggable.js and webcomponents.js.

 

Webcomponents.js is used as a polyfill for Firefox/Safari/IE (none Chrome basically) to provide support for the shadowdom and other such things.

 

In Firefox, when I enable polymer on my site, all of my draggable divs become...undraggable.  No error is thrown.  The draggable events (click, move, etc...) are being thrown but the divs just won't move.  However, as soon as I disable polymer (i.e. removing the javascript includes, webcomponents.js specifically), all the divs become draggable again.

 

I looked into the issue and it looks like webcomponents.js wraps all DOM elements within it's own object and this...can have side effects.  Here's a link to what I'm talking about:

 

http://webcomponents.org/polyfills/shadow-dom/#known-limitations

 

Looking through draggable.js I figured out that the problem is that some of the matrix calculations are returning NaN as a value and this breaks the transform movement.

 

The specific lines that are causing the calculation error are near the bottom of the _getOffset2DMatrix function.  It's these two lines:

m[4] = Number(m[4]) + offsetOrigin.x + (offsets.offsetLeft || 0) - parentOffsetOrigin.x - (isRoot ? 0 : parent.scrollLeft) + (offsetParent ? parseInt(_getStyle(offsetParent, "borderLeftWidth"), 10) || 0 : 0);

m[5] = Number(m[5]) + offsetOrigin.y + (offsets.offsetTop || 0) - parentOffsetOrigin.y - (isRoot ? 0 : parent.scrollTop) + (offsetParent ? parseInt(_getStyle(offsetParent, "borderTopWidth"), 10) || 0 : 0); 

And the specific part of both calculations that returns the NaN value is:

 

(isRoot ? 0 : parent.scrollLeft)

(isRoot ? 0 : parent.scrollTop)

 

When isRoot is false, for some instances of the calculation (this routine gets called a lot) the "parent.scrollLeft" and "parent.scrollTop" properties are "undefined".  

 

Yet, this ONLY happens when webcomponents.js is loaded (which again is needed for Firefox and Safari for Polymer to work).  When webcomponents.js is NOT loaded, "parent.scrollLeft" and "parent.scrollTop" return numeric values as intended.

 

The work around a co-worker of mine was able to figure out is to simply "unwrap" the DOM element being passed into the matrix calculations (basically undoing webcomponents.js wrap business).  This fixes everything BUT of course means a direct update to draggable.js which isn't ideal for the long term.

 

Here's what we did to fix it for now:

_getConcatenatedMatrix = function(e, invert) {
  e = (typeof unwrap === "function") ? unwrap(e) : e;

  if (!e || e === window || !e.parentNode) {
    return [1,0,0,1,0,0];
  }
.... /

We simply added this line at the top of the _getConcatenatedMatrix function.

 

e = (typeof unwrap === "function") ? unwrap(e) : e;

 

The function "unwrap" is defined in webcomponents.js and when executed reverts e to what it is expected to be.

 

Another solution we used that also worked was to update the "isRoot" inline if statement from above to the following:

 

(isRoot ? 0 : (parent.scrollLeft || 0))

(isRoot ? 0 : (parent.scrollTop || 0))

 

And while this seemed to work and draggability was returned to the divs, we weren't sure if this would actually produce other unknown side effects.

 

Using "unwrap" basically passes through exactly what the code was expecting to receive in the first place if webcomponents.js wasn't loaded, so it seems the most non-bug-producing solution BUT it forces a coupling to webcomponents.js specifically.

 

The other solution, seems to work, but could have unforeseen issues later.

 

And both solutions require updating draggable.js which will make keeping our library up-to-date a hassle.

 

So, my questions to you guys is, have any of you experienced this issue?  Did you find a better non-draggable.js modifying solution?  Is there any chance draggable.js could be updated to support webcomponent polyfills?

 

Thanks for any feedback,

 

Mariano Martinez III

  • Like 1
Link to comment
Share on other sites

Hm, that is rather awkward indeed. Thanks for being so detailed with the explanation and potential workarounds. I think I see exactly what you mean. And you're right - it's pretty undesirable to add code to Draggable that couples it with some 3rd party library (polymer in this case) - if we start doing that for every framework that is overzealous in its approach to the DOM, it becomes not only a maintenance nightmare, but it could also bloat the file size and/or cause other errors (what if another library ALSO defines an "unwrap()" function that behaves differently?). 

 

I would definitely argue that this is a clear flaw with Polymer that THEY should address, not us. But I know, that doesn't help you much. And they're trying to do some things that'd likely make it very difficult to keep the DOM clean. 

 

To be candid, I'm reluctant to add anything that accommodates Polymer right now because my personal experience with it has been very, very bad. I dropped it into my speed test a few times (roughly 6 months apart) and saw that not only did it perform quite badly, but there were major memory leaks that caused the browser to crash pretty quickly. Even after all of its animations were killed, it continued to chew up huge amounts of resources. So architecturally it just feels gross to "monkey-patch" a problem like this, and I feel even worse because of my experience with Polymer. 

 

The only thing I can think of right now that's moderately clean would be to expose a Draggable.unwrap() method that you can point at whatever you want, but the down side to that is it'll kinda hurt performance if every element including ancestors must be run through that function every time there's a click/tough. I'll have to chew on this a bit. If anything else comes to mind for you, let me know. 

  • Like 5
Link to comment
Share on other sites

For the record, I didn't mean to insult Polymer or its developers. I totally sympathize with what they're trying to do and how difficult it could be to accomplish it in a "clean" way. And the memory leaks and performance problems probably wouldn't bite too many "normal" developers because they wouldn't be pushing it so hard to animate a bunch of stuff simultaneously. 

Link to comment
Share on other sites

Hi Arte,

 

IMHO FireFox is becoming the new IE... absolutely difficult to work with. Good luck with that.

 

I have a lot of experience working with Polymer, so I understand your frustration. Unfortunately, I doubt there is much the GSAP development team can do to address any perceived or real issues until Polymer stabilizes. There are just too many breaking changes to deal with in each iteration, especially with the web-animations component. Just look at this question I answered on Stack Overflow. Who would've known that???

 

Polymer is awesome, no doubt about it. But it is still several years off from being viable.  To get around this, I have been using Angular directives to recreate Polymer elements, which are loosely based off of Angular's own version of Polymer elements. The only real difference is that I use GSAP for animations, while the Angular Material team uses CSS. I got the idea to create my own version of Polymer elements after looking at this CodePen collection of material designs.

 

If you can recreate a lot of Polymer elements in pure CSS, do you really need to import those elements, let alone Polymer? 

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...