svgdotjs / svg.js

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

animate() with duration 0 impossible #1225

Closed edemaine closed 1 year ago

edemaine commented 2 years ago

Bug report

For complex multi-operation animations, I'd like to be able to write something like:

circle.animate(0, 0, 'after').attr('cx', 5)

to make something happen instantaneously (here, set cx attribute to 0) after a sequence of animations in a timeline. (I've already assigned a shared timeline via elt.timeline(timeline).)

Unfortunately, the following code causes the first 0 to turn into a 400:

https://github.com/svgdotjs/svg.js/blob/361d241c802ae144493a3f222b03c826d0e74b63/src/animation/Runner.js#L79-L80

Explanation

The behaviour I expected was for 0 to be treated like a time, and only undefined (or null) to trigger a default value.

Assuming you agree (and this wouldn't break too many things), I'd be happy to write a PR.

I believe Timeline.schedule already behaves this way (it lacks a sanitization process.)

A workaround is to use a very small time, like 0.1, in place of 0.

Fuzzyma commented 2 years ago

Let me start by saying how much I value your issue reports. There are always great to read and reproduce. Thank you!

This seems to be a classical matter of something || default going wrong. I agree that this is a bug and a PR is really welcome :). Also: To to instant changes to your element in a timeline, you can try queuing a function without animate. It should work by just calling runner.queue(fn).schedule(timeline, delay, when).

Fuzzyma commented 3 months ago

I am sorry, I somehow forgot to publish all the fixes I made. I just released it: https://github.com/svgdotjs/svg.js/releases/tag/3.2.1

edemaine commented 3 months ago

Thanks! Sorry, I forgot to make a PR as well. 😅

Fuzzyma commented 3 months ago

btw: for you actual problem: You can queue up functions that are immediately executed in a timeline. You can use queue(runOnceFn, runStepFn) for that. If you only pass the runOnceFn, it will execute right away when its time :)

edemaine commented 3 months ago

Thanks! I didn't know about the queue interface. I'll probably find applications for that.

I found the repo where I originally ran into this issue. (The 0.1 is an approximation of zero.) This could be rewritten with queue, but it's maybe a little nicer to use .attr directly on the result of animate instead of wrapping in a function. (To see some of the generated animations, go here and press the right arrow key.

Another application I can imagine is an interactive speed slider where the maximum speed is instantaneous, though I've never built that. (For fun: an example with a speed slider. This code uses svg.js but doesn't actually use animate for some reason I don't recall. Also the maximum speed isn't instantaneous.)