Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transition start gets delayed if execution is stalled before it is created (and d3-timer clock has started) #73

Closed
magjac opened this issue Sep 5, 2017 · 2 comments

Comments

@magjac
Copy link

magjac commented Sep 5, 2017

See this block: https://bl.ocks.org/magjac/29911a2c697813463475c2f39c8d720a

The expected behavior is that the red box shall transition smoothly from the smaller black box to the larger during 6 seconds. However, it gets 3 seconds delayed because execution is stalled for 3 seconds before it is created and therefore jumps from start to half-done. If either the d3-timer has not been started (by calling d3.now()) or there is no stalling, the transition works as expected.

I'm not sure if this is a bug in d3-transition or in d3-timer. See also related issues d3/d3-timer#26 and d3/d3-timer#27 and the fix in d3/d3-timer#28.

@magjac magjac changed the title Transition start gets delayed if execution is stalled beforeit i Transition start gets delayed if execution is stalled before it is created (and d3-timer clock has started) Sep 5, 2017
@magjac
Copy link
Author

magjac commented Sep 5, 2017

The reason for this behavior is that selections.transition() calls d3.now() here and that d3.now() here returns the clockNow (if it isn't the first time d3.now() is called) computed on the last wake, from which the current time has advanced substantially.

@mbostock
Copy link
Member

mbostock commented Sep 5, 2017

This is the intended behavior.

If you schedule multiple timers (or transitions) within one pass of the “event loop” (i.e., before a queued promise microtask is invoked), those timers have the same reference time. We must capture the reference time to synchronize the timers.

The surprise here is that the reference time is captured lazily when you call d3.now or, by extension, d3.timer, selection.transition, etc. So by calling d3.now before waste, the reference time changes. (The same behavior would apply if you scheduled transitions both before and after waste.)

It would be better if D3 could somehow capture the reference time before your code runs. But it can’t, because it doesn’t control the browser event loop. Your code runs here on load, but in general your code could run for a variety of reasons, and D3 has no way of intercepting your code before it runs to capture the reference time.

An alternative would be for D3 to capture the reference time in the microtask, rather than when d3.now (and d3.timer, selection.transition, etc.) is called. If we did that, then in your example the transition would always run for the six seconds following the end of the event loop, rather than the six seconds following the start (or middle) of the event loop. But I’m not sure it’s desirable to do this, because in another common case, a reference time is set when timers are invoked (see the assignment to clockNow in wake)), so that you can schedule new timers during this invocation and the new timers are scheduled consistently relative to the old timers.

@mbostock mbostock closed this as completed Sep 5, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants