euan.cowie Posted December 6, 2020 Share Posted December 6, 2020 Hi there! I'm working on a React project and am using GSAP for my animations. The animations I'm performing are on SVGs using the timeline. The problem I've run in to is that I'm unable to perform the animations (.to() transforms) on <svg> elements themselves. This seems to part of the specification: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform. My code contains an outermost <svg> with nested <svg> elements within. It is these nested SVGs I am trying to animate. NB. The reason I need to use nested SVGs is that I want to keep relative positioning of their child elements and not have to programmatically maintain position of each child element... However, things work perfectly fine if I wrap each of these nested SVGs with a <g> and perform the GSAP timeline.to() calls on those elements. I feel like this is a cop out and leaves the semantics of the XML much to be desired (it doesn't look good if each group only ever has a singular child). I'm wondering if I'm missing something in the Greensock API or maybe even perhaps something fundamental with regards to the SVG spec. I've attached a simple codepen to give an idea of what I'm on about :) I appreciate any help offered! Thank you! Euan See the Pen YzGqvOy by euan-cowie (@euan-cowie) on CodePen Link to comment Share on other sites More sharing options...
Solution GreenSock Posted December 6, 2020 Solution Share Posted December 6, 2020 If I understand your question correctly, the problem is that you're actually animating transforms but you're intending to animate "x" and "y" ATTRIBUTES (not transforms). So your #svg-player initially has no transforms applied, but it has an "x" attribute of 120, and "y" attribute of 80. In GSAP, animating transforms is probably the most common thing people do, so "x" and "y" are aliases for transform: translateX() and transform: translateY() CSS values. In your animation, you're animating x and y (transforms) to 0...but they're ALREADY at 0 (no transforms). If you want to animate the attributes, use the AttrPlugin which is already built into the core, so just wrap your values in attr:{}: // BAD: timeline.to("#svg-player", { x: 0, y: 0, duration: 2 }, 2); // GOOD: timeline.to("#svg-player", { attr:{x: 0, y: 0}, duration: 2 }, 2); Also, for the record, I've seen browsers behave oddly when you try to nest SVGs like that. I can't remember exactly what happened, but I believe it had something to do with ignoring transforms on the nested SVGs. So use at your own risk - it has nothing to do with GSAP at all; it's just a browser thing. Happy tweening! 2 1 Link to comment Share on other sites More sharing options...
euan.cowie Posted December 7, 2020 Author Share Posted December 7, 2020 Thanks for the feedback! You were, of course, right on the money $$$. I was completely unaware of the "attr" var and the AttrPlugin. I'll definitely take your experience of nested SVGs in to account and do a little experimenting. I'm just not aware at this time of any other method as convenient when it comes to keeping elements neatly positioned in their respective "containers". Thanks again! Link to comment Share on other sites More sharing options...
GreenSock Posted December 7, 2020 Share Posted December 7, 2020 On 12/6/2020 at 8:03 AM, euan.cowie said: However, things work perfectly fine if I wrap each of these nested SVGs with a <g> and perform the GSAP timeline.to() calls on those elements. I feel like this is a cop out and leaves the semantics of the XML much to be desired (it doesn't look good if each group only ever has a singular child). I didn't quite follow the objection there. How is wrapping it all in <svg> somehow "better" than <g>? If I understood your goal correctly, I'd personally opt for using a <g> for sure. Glad you got things working. 👍 3 Link to comment Share on other sites More sharing options...
PointC Posted December 7, 2020 Share Posted December 7, 2020 Yeah - I was just typing as Jack responded, but I can't really think of a good reason not to use a group tag. Nested SVGs are just too problematic and groups are made for... well... groups. You can often create everything at 0,0 and then positioning things is super easy. Just my two cents. YMMV. 3 Link to comment Share on other sites More sharing options...
euan.cowie Posted December 8, 2020 Author Share Posted December 8, 2020 I see! I had another look at what I was doing. With the <g> elements I can no longer position my "Player(s)" by x,y coordinates as attributes but I can still use a transform attribute. I've made a new codepen, here: See the Pen ExgyKLO by euan-cowie (@euan-cowie) on CodePen Would this be the best way of creating them (w/o <svg> nesting, w/ <g> "grouping") then? This updated codepen uses React to show what I'm really trying to get at - from a hierarchical POV. This codepen also shows the current problem I'm working on - which is how to update the rectangle above the "Player" <circle> with the current position of the player while animating. My presumption is to use the onUpdate var of timeline.to() but I don't know the best way to pass this information from a parent component to a child component without breaking encapsulation. This is more a question for a React forum or something though... Thanks for all your help. It's been very informative! Link to comment Share on other sites More sharing options...
ZachSaucier Posted December 8, 2020 Share Posted December 8, 2020 I'm not a React guy, but isn't there a way of binding the value displayed to a reference that you have to where it updates automatically? You could animate that ref to get the visual state to update. 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