gcmn Posted October 11 Share Posted October 11 So what I'm trying to do might just be unsupportable, but I'm trying to use GSAP and Draggable to make the tiles in the NYT Connections game draggable using Draggable. I got it working fine on Desktop (with some hiccups where I have to call `update` with sticky which feels like a bit of a hack), but on mobile (Firefox and Chrome) the dragging is unusably slow. The codepen shows my code, but the issue doesn't actually replicate there, so I suspect this is just an issue that Draggable on top of all the other stuff the page is doing is just too much for the phone processor. I attached a (very compressed) screen recording of the issue though. I think based on the HTML attributes that the page is probably using React. Would following the guides in https://gsap.com/resources/React help with the performance issues? Any other suggestions, or should I just give up on this fool's errand? screen-20241011-094440~2(1).mp4 See the Pen YzmNGEq by gcmn (@gcmn) on CodePen Link to comment Share on other sites More sharing options...
Solution mvaneijgen Posted October 11 Solution Share Posted October 11 Hi @gcmn welcome to the forum! Will be hard to debug if the issue isn't in the Codepen. My advise is always to try to disable big chunks of your code base to see if the issue goes a way and than start introduce things back in one by one until the issue is back that way you can find the culprit. For this particular issue I might suspect the css transition property. Do you maybe load some CSS that adds transition: all .3s ease-in; or along those lines, that would explain the slowness you're experiencing read more here https://gsap.com/resources/mistakes/#using-css-transitions-and-gsap-on-the-same-properties Hope it helps and happy tweening! Link to comment Share on other sites More sharing options...
gcmn Posted October 11 Author Share Posted October 11 (edited) Thanks for the response. Yeah, the issue is that since I'm just trying to layer an extension on top of an existing site, it's not my codebase that is causing whatever conflicts (sorry, I should've explicitly said that this was for a browser extension in my original post, though the same issue applies to copy-pasting the JS into the dev console or running a bookmarklet). The codepen is me extracting the relevant part of the DOM and the corresponding CSS styles (via Chrome's copy>styles), but I think there's a whole React app underneath that I may be fighting against, which is why this is maybe just all silly. To run what I'm actually running, you can go to https://www.nytimes.com/games/connections (and click "play") and paste the following code into the dev console: function loadError(oError) { throw new URIError(`The script ${oError.target.src} didn't load correctly.`); } function maybeLoadScript(url, onloadFunction) { if (document.head.querySelector(`script[src="${url}"]`)) { console.log(`Draggable Connections: Script element with ${url} already exists. Aborting.`); return; } const newScript = document.createElement("script"); newScript.onerror = loadError; if (onloadFunction) { newScript.onload = onloadFunction; } document.head.appendChild(newScript); newScript.src = url; } maybeLoadScript("https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js", () => { console.log("Draggable Connections: gsap loaded"); maybeLoadScript("https://cdn.jsdelivr.net/npm/[email protected]/dist/Draggable.min.js", () => { console.log("Draggable Connections: Draggable loaded"); gsap.registerPlugin(Draggable); outerContainer = document.getElementsByTagName("fieldset")[0]; tiles = outerContainer.querySelectorAll('[data-testid="card-label"]'); tileContainer = tiles[0].parentNode; deselectBtn = document.querySelector('[data-testid="deselect-btn"]'); for (const tile of tiles) { tile.style["will-change"] = "transform"; } function onDragEnd() { // Just return the element to where it was. gsap.to(this.target, { x: 0, y: 0 }); // Unselect everything. I couldn't figure out how to interrupt whatever // event listener the page is using to select things, so this is the best we // can do. Note that this needs to be in `onDragEnd` not `onRelease` or you // could never select anything. deselectBtn.click(); } function destroyDraggables() { for (const tile of tiles) { const draggable = Draggable.get(tile); if (draggable != null) { draggable.kill(); } } } destroyDraggables(); Draggable.create(tiles, { onDragEnd, minimumMovement: 1, dragResistance: 0 }); }); }); or since that can be a bit tricky on mobile, it can also be done as a bookmarklet: javascript:void%20function(){function%20a(a){throw%20new%20URIError(`The%20script%20${a.target.src}%20didn't%20load%20correctly.`)}function%20b(b,c){if(document.head.querySelector(`script[src=%22${b}%22]`))return%20void%20console.log(`Draggable%20Connections:%20Script%20element%20with%20${b}%20already%20exists.%20Aborting.`);const%20d=document.createElement(%22script%22);d.onerror=a,c%26%26(d.onload=c),document.head.appendChild(d),d.src=b}b(%22https://cdn.jsdelivr.net/npm/gsap%403.12.5/dist/gsap.min.js%22,()=%3E{console.log(%22Draggable%20Connections:%20gsap%20loaded%22),b(%22https://cdn.jsdelivr.net/npm/gsap%403.12.5/dist/Draggable.min.js%22,()=%3E{function%20a(){gsap.to(this.target,{x:0,y:0}),deselectBtn.click()}console.log(%22Draggable%20Connections:%20Draggable%20loaded%22),gsap.registerPlugin(Draggable),outerContainer=document.getElementsByTagName(%22fieldset%22)[0],tiles=outerContainer.querySelectorAll(%22[data-testid=\%22card-label\%22]%22),tileContainer=tiles[0].parentNode,deselectBtn=document.querySelector(%22[data-testid=\%22deselect-btn\%22]%22);for(const%20a%20of%20tiles)a.style[%22will-change%22]=%22transform%22;(function(){for(const%20a%20of%20tiles){const%20b=Draggable.get(a);null!=b%26%26b.kill()}})(),Draggable.create(tiles,{onDragEnd:a,minimumMovement:1,dragResistance:0})})})}(); (after creating a bookmarklet, you can run it in android firefox or chrome by searching its name in the address bar while on the target page, see https://paul.kinlan.me/use-bookmarklets-on-chrome-on-android/). This is just the code to create the Draggables and demo the latency issues, I actually have additional code that does something other than send them back to their start point I do see some CSS-defined animations in the stylesheets, but I'm not sure whether they're firing here. One thing I did notice is that if I clone one of the elements, make its position absolute (and set its height and width to match the automatically calculated original) and make that Draggable, it doesn't seem to experience the same slowness. Not sure if that's just because it's one element instead of 16 or if there's a substantive difference as well. Edited October 11 by gcmn Copy-pasted code was rendered terribly after submission (but not in editor) Link to comment Share on other sites More sharing options...
Rodrigo Posted October 11 Share Posted October 11 Hi, Unfortunately if the demo doesn't reflect the issue I'm afraid that there isn't much we can do to help. I tested the debug version of your demo (no iframes) on my android device and everything runs very smoothly 🤷♂️ My only guess is that you have a lot of logic running on the onDrag callback or as Mitchel mentions some CSS transition could be interfering here. Sorry I can't be of more assistance 😞 Link to comment Share on other sites More sharing options...
gcmn Posted October 11 Author Share Posted October 11 And yet your assistance was still very helpful! Mitchel's guess about CSS transitions was spot on. I put an event listener on "transitionrun" and sure enough they were firing off all over the place. I've hacked "transition: none" into the element style and now everything is smooth! Maybe I can find a more elegant way to do that at some point 😆 Thank you 2 Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now