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

On end method of a group of concurrent transitions...is possible? #76

Closed
ElPsyCongro opened this issue Nov 28, 2017 · 5 comments
Closed

Comments

@ElPsyCongro
Copy link

Hi, I would like to know if it's posible to somehow group certain concurrent transitions and execute a function when all of them are finished.
The thing is that I needed to do a transition to animate the modification of two attributes for the same d3 selection so I needed to use concurrent transitions the way that is here:
https://bl.ocks.org/mbostock/5348789

But now I need to execute a specific function after all transitions are finished. Anyone know a way to achieve this?

@mindrones
Copy link

mindrones commented Nov 28, 2017

This is something I have to do sometimes too and I always end up doing something like this:

const size = selection.size();
const done = 0;
const finalFunction = () => {
  console.log('all done');
}

selection
.transition()
.delay(d => {
  // return a delay that depends on d
})
.duration(d => {
  // return a duration that depends on d
})
.on('end', d => {
  // ...
  done += 1;
  if (done === size) {
    finalFunction()
  }
}

but I too would like something cleaner.

It would be nice to have something generic so that we can detect if a particular transition is the first or the last one like:

const transition = selection.transition();

transition
.delay(d => {
  // return a delay that depends on d
})
.duration(d => {
  // return a duration that depends on d
})
.on('start', d => {
  if (transition.isFirst) { // ... }
  if (transition.isLast) { // ... }
})
.on('end', d => {
  if (transition.isFirst) { // ... }
  if (transition.isLast) { // ... }
})

so keeping that count on the transition object.
Or it could be something like:

.on('start', (d, i, event) => {
  if (event.isFirst) { // ... }
  if (event.isLast) { // ... }
})

This new event object would have properties like:

  • isFirst
  • isLast
  • size of the transition
  • index in time (so that you would be able to execute code, say, only on 'end' events of transitions with even index)
  • delay and duration of the executed transition (the ones calculated in .delay() and .duration() to avoid recomputing them in the start/end listeners) (*)

I'm not sure this would be good design, just throwing ideas here, but sure this is something I'd use.

EDIT
(*) we could attach delay and duration as attributes to the datum like in the snippet below but sometimes we need the datum to be immutable, or simply we don't want to pollute it with temporary values, as that would require us to clean it up at the end of the transition.

.duration(d => {
  d.duration = 2 * d.value;
  return d.duration;
})
.on('end', d => {
  // use d.duration
  delete d.duration;
})

@mindrones
Copy link

mindrones commented Nov 28, 2017

On second thought, supposing to have the transition index in time we wouldn't need isFirst and isLast, we could just compare index and size; on the other hand, I'm not sure what it should happen if 2 or more elements end the transition concurrently as if they get the same index, comparing index and size becomes useless. 🤔 Maybe index should be a count instead 😄

@mindrones
Copy link

Here's a quite naïve example of what I mean: https://bl.ocks.org/mindrones/123832bbf5b08ce4b28dab66fae21a69

@mbostock
Copy link
Member

Now that await-async is a thing, I’ve been thinking that transitions could have some Promise-based APIs. One such idea that would address this issue is a transition.end method #77.

@mbostock
Copy link
Member

Folding into #77.

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

3 participants