Jump to content
Search Community

Controlling drawSVG start and end with separate tweens/easings?

katerlouis test
Moderator Tag

Recommended Posts

drawSVG: "0% 50%" is nice! But what if I want to separate easings for start and endpoint? See the codepen as an example for why this might be useful (with a workaround using vue). 

 

Maybe something like this could be implemented in the plugin:

gsap.timeline({ repeat: -1 })
  .set(elem, { drawSVG: "0% 0%" })
  .to(elem, {
    ease: 'power1.out',
    drawSVG: {
      start: "100%",
    },
  }, 0)
  .to(elem, {
    ease: 'power1.in',
    drawSVG: {
      end: "100%",
    },
  }, 0)

 

See the Pen abvPajM by katerlouis (@katerlouis) on CodePen

Link to comment
Share on other sites

Your solution is waaay smaller in code, I like that! But unfortunately the animation feels very different. Although my easings aren't perfect yet (the ease visualisers custom ease builder has it's limits, and my designer will give me a proper path tomorrow :D), it already feels much smoother and "organic" – I don't think you can achieve that without separate easings. 

 

You could also make random easings and timings for start and end point each rotation; you can go all sorts of crazy! :D

Link to comment
Share on other sites

I spent all of about 10 seconds tweaking values, I'm sure you could change my approach above to your liking more :) 

 

Most likely @GreenSock will drop in and say something about not very many users wanting this and it not warranting the extra kb for everyone. And that if there's an dramatic increase in requests for this feature we may add it ;) 

  • Like 2
Link to comment
Share on other sites

It's hard to imagine that it would be that much more code to accept an object to set start and endpoint 😎

 

Uh, the helper funciton looks really helpful! 

But ultimately blending results in a single ease. I'm quite sure for this effect to work, the start- and endpoint need to be tweened separately.

Link to comment
Share on other sites

Yep, @ZachSaucier is right about what I'd say :) I think you're the only person who'd use this, and it's definitely not a simple thing to bake into DrawSVGPlugin cheaply kb-wise. Remember, we'd have to handle overwriting and various edge cases. Like what if someone animates just the "end" in one tween, but in another tween they're doing a normal drawSVG: "20% 60%" or whatever? It's probably a lot more complex than you might think and it doesn't seem fair to make everyone pay the kb price for that especially when you could get the behavior you're after with an external helper function as I show here:

 

See the Pen b37e4720c4ee4a295febfec4a1006812?editors=0010 by GreenSock (@GreenSock) on CodePen

 

And here's the code:

function drawSVGProxy(targets) {
  targets = gsap.utils.toArray(targets);
  let setter = gsap.quickSetter(targets, "drawSVG"),
      start = "0%",
      end = "100%",
      self = {
        targets: targets,
        start(value) {
          if (arguments.length) {
            start = value;
            setter(start + " " + end);
            return self;
          }
          return start;
        },
        end(value) {
          if (arguments.length) {
            end = value;
            setter(start + " " + end);
            return self;
          }
          return end;
        }
      };
  return self;
}

// USAGE: 
let proxy = drawSVGProxy("#path");
proxy.start("50%").end("50%"); // start in the center
gsap.to(proxy, {start:"0%", duration: 3, ease: "power2.in"});
gsap.to(proxy, {end: "100%", duration: 3, ease: "power2.out"});

So basically you just create a proxy object like drawSVGProxy(".selector") and then tween THAT because it has "start" and "end" properties. 

 

Make sense? 

 

Does that help?

  • Like 3
Link to comment
Share on other sites

Crazy–

the "proxy part" is kinda what I'm doing, right? Just not tied so tightly to gsap :D

 

Never seen quickSetter before; 

the return of `self` and especially the early return of `self` inside `start` and `end` functions is a mistery to me. And what is `arguments.length` – I don't see it declared anywhere.

 

If you find the time I'd appreciate a more in depth rundown of whats going on there.

 

Feels like I'm close to getting a new item– you know, like in Rogue-likes, where you finally get the High jump boots and can't wait to backtrack to all the places where you bashed your head against the wall for hours thinking "this must be possible!" – Nerdtalk over

  • Like 1
Link to comment
Share on other sites

7 minutes ago, kreativzirkel said:

Feels like I'm close to getting a new item– you know, like in Rogue-likes, where you finally get the High jump boots and can't wait to backtrack to all the places where you bashed your head against the wall for hours thinking "this must be possible!" – Nerdtalk over

🤣👍

 

Welcome to the world of GSAP Elites ;) 

  • Haha 3
Link to comment
Share on other sites

22 minutes ago, kreativzirkel said:

Never seen quickSetter before; 

It's new in GSAP 3. :)

 

23 minutes ago, kreativzirkel said:

the return of `self` and especially the early return of `self` inside `start` and `end` functions is a mistery to me. And what is `arguments.length` – I don't see it declared anywhere.

"arguments" is an implicit object in every non-arrow function - it's an Array-like object containing all the arguments/parameters. I tap into that to figure out if the function is being used as a getter or setter in that particular case. If someone passes a value in (arguments.length is non-zero), it's a setter. 

 

I return "self" just as a convenience for chaining so you can do proxy.start("50%").end("50%"), etc. And "self" just refers to the proxy object. 

 

Does that clear things up? 

  • Like 3
Link to comment
Share on other sites

6 hours ago, kreativzirkel said:

If you find the time I'd appreciate a more in depth rundown of whats going on there.

 

Just some getters and setters. You know, the backbone of Vue. So it could be written like this. I didn't include the quickSetter to make it clearer.

 

function drawSVGProxy(targets) {
  
  return {
    _start: "0%",
    _end: "100%",
    get start() {
      return this._start;
    },
    set start(value) {
      this._start = value;
      gsap.set(targets, { drawSVG: this._start + " " + this._end });
    },
    get end() {
      return this._end;
    },
    set end(value) {
      this._end = value;
      gsap.set(targets, { drawSVG: this._start + " " + this._end });
    }
  };
}

let proxy = drawSVGProxy("#path");
proxy.start = "50%";
proxy.end = "50%";
gsap.to(proxy, {start:"0%", duration: 3, ease: "power2.in"});
gsap.to(proxy, {end: "100%", duration: 3, ease: "power2.out"});

 

 

6 hours ago, GreenSock said:

It's probably a lot more complex than you might think and it doesn't seem fair to make everyone pay the kb price for that especially when you could get the behavior you're after with an external helper function as I show here:

 

I've always wanted the plugin to be able to do that. Even better would be able to loop stuff, like this.

 

See the Pen 38f8c8f8057d451747ee4b4bd7656723 by osublake (@osublake) on CodePen

 

 

  • Like 3
Link to comment
Share on other sites

Hey @OSUblake, how does your solution (without quickSetter) differ from mine? I also use a "proxy", which in my case is the Vue data object, and on every change I gsap.set the `drawSVG`-prop accordingly. 

 

My concerns with this solution lie in:

– how often is the "watch" triggered in Vue? Will the animation always be smooth?

– Technically this proxy solution `gsap.set`s twice as much. Could that have impact on performance?

Link to comment
Share on other sites

2 hours ago, kreativzirkel said:

how often is the "watch" triggered in Vue?

 

Every single time the value changes. 

 

Some videos from the man himself about how Vue works. Notice the get/set I'm doing. 

 

https://www.youtube.com/watch?v=anzA27c7F5g

https://www.youtube.com/watch?v=jnZi4rma2Fs&t=1s

https://www.youtube.com/watch?v=u95SaDglVbI

 

 

2 hours ago, kreativzirkel said:

Will the animation always be smooth?

 

I don't think it's a good idea to animate reactive properties as there is a lot of overhead involved, and no guarantees about the timing. 

 

2 hours ago, kreativzirkel said:

Technically this proxy solution `gsap.set`s twice as much. Could that have impact on performance?

 

Sure, it twice as much work. But you're probably not going to notice it for something simple. And using the quickSetter is faster because it doesn't create a tween like set does. It just directly sets the property.

 

The ideal workflow for a lot of animations would be to animate the properties first, and THEN set the values after both have been updated, like in onComplete callback or ticker, but that's probably not needed for what you're doing.

 

2 hours ago, kreativzirkel said:

how does your solution (without quickSetter) differ from mine?

 

Same concept, but you're using a library to do it.

 

And JavaScript does have a proxy object. I think that's what Vue 3 is going to use.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy

 

Using the new proxy object. Really don't need to use get.

 

var proxy = new Proxy({
  target: path,
  start: "0%",
  end: "100%"
}, {
  set(obj, prop, value) {
        
    obj[prop] = value;
    
    if (prop === "start" || prop === "end") {
      gsap.set(obj.target, { drawSVG: obj.start + " " + obj.end });
    }
    
    return true;
  }
});

proxy.start = proxy.end = "50%";
gsap.to(proxy, {start:"0%", duration: 3, ease: "power2.in"});
gsap.to(proxy, {end: "100%", duration: 3, ease: "power2.out"});

 

  • Like 2
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...