Skip to content
This repository has been archived by the owner on Sep 7, 2020. It is now read-only.

integrating support for animations #40

Closed
krawaller opened this issue Mar 3, 2016 · 2 comments
Closed

integrating support for animations #40

krawaller opened this issue Mar 3, 2016 · 2 comments

Comments

@krawaller
Copy link
Contributor

The createHook animation helper

In this blog post I detail a solution on how to make D3 animations work with react-faux-dom, using a small helper function createHook. You call it with a reference to the component, the faux element you intend to feed to D3, and the state prop name you want the resulting virtual DOM to end up in:

let hook = createHook(this,fauxnode,"chart");

The returned hook is then attached to all D3 animations like this:

rect.transition()
    .duration(500)
    .attr("y", function(d) { return y(d.y0 + d.y); })
    .call(hook);

This will ensure that the following line of code runs while the animation is playing:

component.setState({[statename]:fauxelement.toReact()});

...allowing your render function to simply output this.state.chart (or whatever statename you chose).

An integration proposal

This helper could be added to react-faux-dom itself, however it kind of itches to add something D3-specific to an otherwise library-agnostic library, intended to work with any DOM-manipulating lib.

Here's my current thinking - the only reason right now to attach stuff to the D3 anims is to be able to stop updating state when the animation is done playing. However, I haven't managed to make the cleanup fool-proof; if you spam transitions, sometimes the relevant listeners won't fire, and my little helper lib will update state indefinitely.

So now I'm thinking we could make a general version that works like this:

You connect a React component to a faux element using the same signature as createHook:

ReactFauxDOM.connect(this,faux,"chart");

This will give you an updateFauxDOM method on the component which you can call whenever you like (and probably the connect call should schedule an automatic first call much like createHook works).

// after doing something to the faux node:
this.updateFauxDOM();

And now for the killer feature - the update method takes an optional millisecond argument, which will update the DOM for that amount of time!

rect.transition()
    .duration(500)
    .delay(function(d, i) { return i * 10; })
    .attr("height", function(d) { return y(d.y0) - y(d.y0 + d.y); })

this.updateFauxDOM(1000); // allowing for duration + max delay, with a bit of a margin

So no more brittle cleanup, and no more D3-specific stuff - we simply let the developer tell us how long to animate for. Super easy to implement in a safe way. This could be coupled with an option to animate forever and a .stopAnimating method, and why not also the isAnimating method that createHook added.

Potentially we could make this into a mixin which adds some automagic cleanup in a componentWillUnmount call.

What do you think, @Olical?

@krawaller
Copy link
Contributor Author

As a PS: I was also toying with the idea of using React to compare the old and new faux DOM to see if anything has changed, and if not then we stop animating. But although a neat idea that I would feel smart implementing, it probably is needlessly complicated. Also there might be animations that have identical frames (like a pulsar) which a bit of bad luck may cause faulty stops for. So all in all I think passing on the duration responsibility to the user is the best call.

@krawaller
Copy link
Contributor Author

Implemented in #41, discussion should move there.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant