Olical / react-faux-dom

DOM like structure that renders to React (unmaintained, archived)
http://oli.me.uk/2015/09/09/d3-within-react-the-right-way/
The Unlicense
1.21k stars 87 forks source link

How to integrate with React-Motion for animation? #2

Closed wuxianliang closed 9 years ago

wuxianliang commented 9 years ago

Dear @Olical Glad to see this progress of the integration between D3 and React. I ever intended to use dc.js and react.js for analyzing data of stocks. When I want to show changes of data, animation does matter. In your approach, how to show animation? I suggest React-Motion which is a promising package.

https://github.com/dc-js/dc.js https://github.com/chenglou/react-motion

how to generate jsx in D3 manner? Maybe something like:

// Create your element.
var el = ReactFauxDOM.createElement('div')

// Change stuff using actual DOM functions.
// Even perform CSS selections.
el.style.setProperty('color', 'red')
el.setAttribute('class', 'box')
el.Spring.setDefaultValue({val: 0})
el.Spring.setEndValue({val: this.state.open?  400 : 0})

// Render it to React elements.
return el.toReact()

// Yields: 
<Spring defaultValue={{val: 0}} endValue={{val: this.state.open ? 400 : 0}}>
    {interpolated =>
        <div className='box' style={{
              transform: `translate3d(${interpolated.val}px, 0, 0)`,
              color: 'red'
            }} ></div>
    }
</Spring>
Olical commented 9 years ago

Oh, that's a cool library! I haven't put a huge amount of thought into animations yet, partially because I simply don't need them but also because I was confident that there would be a great React way of doing it.

The bottom line is that we can't use D3s transitions because they involve timeouts and state, which obviously doesn't work unless tightly integrated into React.

This approach looks great and should work fine. I haven't tried it but this should work.

function renderBox(interpolated) {
  // Create your element.
  var el = ReactFauxDOM.createElement('div')

  el.style.setProperty('color', 'red')
  el.setAttribute('class', 'box')
  el.setAttribute('transform', `translate3d(${interpolated.val}px, 0, 0)`)

  return el.toReact()
}

return (
  <Spring defaultValue={{val: 0}} endValue={{val: this.state.open ? 400 : 0}}>
      {interpolated =>
          {renderBox(interpolated)}
      }
  </Spring>
)

Because it returns react elements you can return the result of el.toReact() into any part of a React tree. This should work beautifully!

An addition to react-faux-dom that would make this even better would be allowing you to perform el.appendChild etc with functions or React components that are yet to be instantiated. So you could call createElement(Spring), modify it, add a child div with properties and then render it.

Not sure how you'd get the interpolated value though, it looks like you need to set the Spring elements children array to a function. The example I gave should do the trick though :)

I'd love to know if this works well for you or not. Animations have been playing on my mind.

wuxianliang commented 9 years ago

Thank you for response. But the code does not work.

Uncaught Error: Invariant Violation: Spring.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.
wuxianliang commented 9 years ago

actually we do not need { } in

{interpolated =>
  {renderBox(interpolated)}
}

the following works

{interpolated =>
  renderBox(interpolated)
}

Thank you very much. @Olical

renderChart : function(interpolated){
    var el = ReactFauxDOM.createElement('div');
    el.style.setProperty('backgroundColor', 'red')
    el.setAttribute('class', 'button')
    el.style.setProperty('height', '50px')
    el.style.setProperty('border','border:5px solid red')
    el.style.setProperty('width', `${interpolated.val}` + "px")
    return el.toReact()
},
render:function() {    
   return (
     <Spring defaultValue={{val: 0}} endValue={{val:  800 }}>
        {interpolated =>    
          this.renderChart(interpolated)
        }
     </Spring>
    )
}
Olical commented 9 years ago

I didn't get a notification for this (that's been happening a lot recently!) but that's excellent. I hope it's working well for you. Do you get a smooth experience?

Also you can set style using a full inline style string now, like these new tests. I think you can just set an object too. Just a heads up :)