svgdotjs / svg.js

The lightweight library for manipulating and animating SVG
https://svgjs.dev
Other
11.04k stars 1.07k forks source link

Creating a composite, concurrent animation #1104

Closed pragdave closed 4 years ago

pragdave commented 4 years ago

Here's a chunk of code that animates a rect:

https://codepen.io/pragdave/pen/dyYNBpO?editors=1111

There are two groups of animations on the timeline. The first group changes the box color and spins it. The second group scales it and changes the color again.

The first group runs for 3s. The second group also runs for 3s, but is specified to run 1s after the first.

The problem I have is that I couldn't find a way to schedule a runner at the same time as the start of the latest runner, so instead in the second group I had to do

b1.animate({duration: 3000, delay: 1000, when: "after"})
  .queue(() => console.log("running second", Date.now()-timer))
  .scale(2)
  .animate({when: "last", delay: -3000})
  .fill("#ff0000")

Note that the delay on the second runnier in the group is minus the duration of the first.

If I'm doing this wrong, let me know. Otherwise I'd be happy to submit a PR with a new when: option (perhaps "same" or "with-previous"

Dave

Fuzzyma commented 4 years ago

To compose an animation its often easier to use when: absolute. This way you can specify the time (in delay) at which the animation starts in terms of timeline time:

b1.animate({duration: 3000, delay: 1000, when: "absolute"})
  .queue(() => console.log("running second", Date.now()-timer))
  .scale(2)
  .animate({when: "absolute", delay: 1000})
  .fill("#ff0000")

There is also the relative option which starts an animation relative to the start time of the last runner. This would also fit your needs:

b1.animate({duration: 3000, delay: 1000, when: "after"}) // the mode here doesnt really matter
  .queue(() => console.log("running second", Date.now()-timer))
  .scale(2)
  .animate({when: "relative", delay: 0})
  .fill("#ff0000")

However, your solution is also valid and works.

pragdave commented 4 years ago

Thanks for the quick response. I didn't want to use absolute, because then I'd need to keep track of all the timings outside the timeline, and the chances of me getting out of step with the actual timeline are pretty close to 100% :)

I didn't think to look at "relative" as the documentation seemed to suggest not using it with animate(), but if it's relative to the start of the last, that sounds perfect.

(btw: I'm here because I'm abandoning GSAP; I just can't get it to work with SVG reliably for my requirement)

Fuzzyma commented 4 years ago

I didn't think to look at "relative" as the documentation seemed to suggest not using it with animate(), but if it's relative to the start of the last, that sounds perfect.

Yes the docs for the whole animation section is a bit... short :D I struggle to find the time and motivation to write more.

(btw: I'm here because I'm abandoning GSAP; I just can't get it to work with SVG reliably for my requirement)

I feel honored! I only see people praising GSAP to the highest and wonder why we even have animations in svg.js (after all it is like 800 line of code only for the animation part)

pragdave commented 4 years ago

The problem with GSAP is that it assumes it has absolute control of the SVG elements. If you run them through an animation, then move them manually (say using svg.js), the run the animation again, it gets terribly confused: it seems to use a fairly arbitrary combination of direct attributes and transforms to manipulate positions, and if you change one underneath it, bad things happen (even if you clear its cache).

Given that I'm only animating SVG, I like the simplicity and consistency of svg.js code.

(I also find their forums quite offputting. If I ask a question about how do I do X, they typical answer is "You don't want to do X, see, look how fast «some random demo» is." But, actually, yes, I do want to do X... :)

Anyway, thanks a lot for a great library.

@pragdave

Fuzzyma commented 4 years ago

Thanks :). Lets see when you hit the limits of svg.js ^^

Fuzzyma commented 4 years ago

@pragdave while writing tests I realized I wrote crap about the 'relative' mode. This mode actually moves an already scheduled runner by the relative amount on the timeline. So the mode you need is actually missing. I will add it right away under the option: when: with-last