Share Posted May 1 Hi, I'm trying to figure out how to reposition and scale an element that has been scaled by a previous animation. The previous animation may have been completed and killed at the time the next animation is called. Overwrite appeared to work only if the animation that positioned and scaled the element previously had not been killed. In this example, I'd like to first apply new position and size attributes, and then apply a new scale. I'd like ellipse1 to end up at the position and scale of ellipse2 after the sequence is completed. Is a sequence like this best accomplished by recording several states in a different order with gsap flip, and animating to those states in the order I'd like them to be played? Thanks for your help! See the Pen ZEqXpje by fcdobbs (@fcdobbs) on CodePen Link to comment Share on other sites More sharing options...
Share Posted May 2 Hi, I have limited experience in SVG but in this cases I always remember what @OSUblake recommends: "keep everything in the center of the SVG view box at startup and then create a coordinate system based on that". So taking his extremely wise words I forked your codepen and came up with this: See the Pen GRYMbRj by GreenSock (@GreenSock) on CodePen As I mentioned SVG is not the sharpest tool on my development drawer. I'll invoque @Cassie and @PointC, our SVG wizards so they can either confirm what I'm saying or expose me as a fraud and post a better solution Hopefully this helps. Happy Tweening! 1 Link to comment Share on other sites More sharing options...
Author Share Posted May 3 Thanks, Rodrigo. If it's easy, I'd be curious if you have formulae for the x and y values you've applied to the svg's to keep them centered. If I can calculate these values from the element's current properties, this could be a good solution. I came up with a solution that keeps the svg centered through scale and attribute transitions by tweening the transformation matrix like this: transform: (i,e)=> "matrix(" + new_scale + "," + gsap.getProperty(e,"skewY") + "," + gsap.getProperty(e,"skewX") + "," + new_scale + "," + (gsap.getProperty(e,"cx") - gsap.getProperty(e,"cx") * new_scale) + "," + (gsap.getProperty(e,"cy") - gsap.getProperty(e,"cy") * new_scale) + ")" }}) See the Pen BaqwgOr?editors=0010 by fcdobbs (@fcdobbs) on CodePen I also put together a version using gsap Flip. It's more verbose but could prove useful if other properties are involved in the animation. I didn't find Flip.fromTo in the docs, but I tried it, and it appears to work! See the Pen MWPOErE?editors=0011 by fcdobbs (@fcdobbs) on CodePen I thought there could be a more compact version that would allow gsap to make the transform matrix calculations by using CSS's transform-box. CSS correctly scales and positions the elements, but I couldn't find a syntax that would allow gsap to animate through these values. This syntax throws an Error: <ellipse> attribute transform: Expected transform function, "null". t1.to("#ellipse1",{duration: duration, "transform-origin":"50% 50%", "transform-box":"fill-box", "transform":"scale(.5, .5)",}) gsap looses track of the center point with both of these syntaxes, but maybe there's a formula that will adjust the transformation matrix based on the data-svg-origin attribute: t1.to("#ellipse1",{duration: duration, transformOrigin:"50% 50%", transformBox:"fill-box", "transform":"scale(.5, .5)",}) t1.to("#ellipse1",{duration: duration, transformOrigin:"50% 50%", transformBox:"fill-box", scale:.5,}) See the Pen dygZZOo?editors=0011 by fcdobbs (@fcdobbs) on CodePen If you have formulae handy for calculating the x and y offsets based on the current element's properties, I'll give that a try. It's unclear to me if tweening the transformation matrix values directly might throw gsap off in subsequent animations of these elements. Thanks for your help! Link to comment Share on other sites More sharing options...
Share Posted May 3 Hi, I didn't do a single calculation Actually I just used the viewbox value you had in your SVG and took it from there. If you use just this JS in the codepen I created: gsap.set("#ellipse1", { opacity: 1, }); gsap.set("#ellipse2", { opacity: 1, }); You'll see both ellipses centered in the SVG container: See the Pen gOBXvXO by GreenSock (@GreenSock) on CodePen Starting at that point both ellipses are at the center of the SVG canvas and their X and Y values are both zero, so given the dimensions of your view box: viewBox="0 0 100 100" you know that the bounds are 100 on each axis. Then with the radius on each axis I set their positions using a couple of set() instances: gsap.set("#ellipse1", { y: -40, opacity: 1, }); gsap.set("#ellipse2", { x: 25, y: 40, opacity: 1, }); And then all I had to do is move ellipse1 to the same coordinates ellipse2 has: t2.to("#ellipse1", { duration: duration, x: 25, y: 40, attr: { rx: new_rx, ry: new_ry, } }) And that's it. Sometimes the simplest solution just works Hopefully this helps. Happy Tweening! Link to comment Share on other sites More sharing options...
Author Share Posted May 5 Thanks, Rodrigo. Is there any syntax that utilizes the CSS transform-box property to keep an svg element centered without manually calculating x and y offsets? This syntax throws an error, but it does match the rendering of the CSS transform-box property until the svg attributes are updated: t1.to("#ellipse1",{duration: duration, transformOrigin:"50% 50%", transformBox:"fill-box", "transform":"scale(2, 2)",}) See the Pen KKGZBQQ?editors=0010 by fcdobbs (@fcdobbs) on CodePen Thanks for your help! Link to comment Share on other sites More sharing options...
Share Posted May 5 Hi, SVG is not something I have a lot of experience with, but my guess is that you're looking for SVG Origin: svgOrigin [Only for SVG elements] Works exactly like transformOrigin but it uses the SVG’s global coordinate space instead of the element’s local coordinate space. This can be very useful if, for example, you want to make a bunch of SVG elements rotate around a common point. You can either define an svgOrigin or a transformOrigin, not both (for obvious reasons). So you can do gsap.to(svgElement, {duration: 1, rotation: 270, svgOrigin: "250 100"}) if you’d like to rotate svgElement as though its origin is at x: 250, y: 100 in the SVG canvas’s global coordinates. Units are not required. It also records the value in a data-svg-origin attribute so that it can be parsed back in. svgOrigin doesn’t accommodate percentage-based values. You can read more about it in the CSS Plugin docs (scroll about the middle of the page) https://greensock.com/docs/v3/GSAP/CorePlugins/CSSPlugin Hopefully this helps. Happy Tweening! Link to comment Share on other sites More sharing options...
Share Posted May 6 On 5/3/2023 at 2:22 PM, fcdobbs said: I came up with a solution that keeps the svg centered through scale and attribute transitions by tweening the transformation matrix like this: transform: (i,e)=> "matrix(" + new_scale + "," + gsap.getProperty(e,"skewY") + "," + gsap.getProperty(e,"skewX") + "," + new_scale + "," + (gsap.getProperty(e,"cx") - gsap.getProperty(e,"cx") * new_scale) + "," + (gsap.getProperty(e,"cy") - gsap.getProperty(e,"cy") * new_scale) + ")" }}) That formula is not correct, sorry. The skew values are definitely wrong - that's not how matrices work. I have very limited time right now. Is there any way you could simplify your question? A lot of the stuff in your CodePen looked odd to me. I want to keep the advice focused on what you need. For example, maybe just provide a CodePen and say "how can I get the green oval to animate to the position where its center is aligned with the center of the purple oval?" Again, the simpler the better. No need to include a bunch of extra code in there that isn't working. 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