Draw Animated Chart on React Native

Draw Animated Chart on React Native

Meguro.es #4


  • How to draw chart with only & StyleSheet like
    & CSS
  • How to draw chart with React ART

  • How to animate them



Ca0ab6e450f894e06652ee257df9d647?s=128

Shuhei Kagawa

June 21, 2016
Tweet

More Decks by Shuhei Kagawa

Other Decks in Programming

Transcript

  1. Draw Animated Chart on React Native (from scratch) @shuheikagawa

  2. 1. div & CSS 2. Animation 3. React ART 4.

    Animation again
  3. Me → Software Engineer at M3, Inc. → AngularJS, Rails,

    Babel, etc. → GitHub, Qiita: @shuhei → Twitter: @shuheikagawa
  4. EcmaScript & Me Stage 0 Method Parameter Decorators -> babel/babylon

    @Component({ /* ... */ }) class App { constructor(@Inject('something') foo) { } }
  5. React Native

  6. None
  7. None
  8. 23°?

  9. I only remember yesterday's temperature

  10. Let's compare!

  11. None
  12. There are some iOS/Android-only libraries, but..... → tomauty/react-native-chart → Jpadilla1/react-native-ios-charts

    → hongyin163/react-native-chart-android
  13. Let’s drawing charts in React-Native without any library by WangZixiao

  14. <View> == <div>

  15. → Flexbox: A Complete Guide to Flexbox → position: absolute;

  16. None
  17. <View style={[styles.barBox]}> <View style={[styles.bar, styles.barPast]} /> <View style={[styles.bar, styles.barFuture]} />

    </View> const styles = StyleSheet.create({ barBox: { alignItems: 'flex-end', flexDirection: 'row', }, bar: { width: 10, borderTopLeftRadius: 5, borderTopRightRadius: 5 }, barPast: { backgroundColor: 'gray' }, barFuture: { backgroundColor: '#bbccbbff' marginLeft: -10 } });
  18. const bars = days.map((day, i) => <View key={i} style={[styles.barBox]}> <View

    ... /> <View ... /> </View> ); <View style={styles.container}> {bars} </View> const styles = StyleSheet.create({ container: { alignItems: 'flex-end', flexDirection: 'row', }, barBox: { width: 10, marginHorizontal: 2, alignItems: 'flex-end', flexDirection: 'row', } });
  19. Animation in React Native → Explicit: Animated → Implicit: LayoutAnimation

  20. Animated class BarChart extends Component { constructor(props) { // Prepare

    *animated* value holders. this.state = { heights: props.heights.map(h => new Animated.Value(h)) }; } render() { // `Animated.View` subscribes to changes of *animated* value // and update underneath props. const bars = this.state.heights .map(h => <Animated.View style={[{ height: h }, otherStyle]} />); return <View>{bars}</View>; } // ... }
  21. componentWillReceiveProps(nextProps) { if (this.props.heights !== nextProps.heights) { // Trigger animation.

    const anims = this.state.heights .map((h, i) => Animated.spring(h, { toValue: nextProps.heights[i] })); Animated.parallel(anims).start(); } }
  22. None
  23. Not so bad.

  24. None
  25. LayoutAnimation // Somewhere in a container component... LayoutAnimation.spring(); this.setState({ ...whatever

    }); // Just render as if no animation. function TemperatureBar({ temperature }) { return <View style={[otherStyle, { height: temperatureToHeight(temperature) }]} /> }
  26. But I want curves...

  27. gl-react-native?

  28. gl-react-native? It's only for effects with shaders!

  29. react-art! → SVG-like vector graphics API on React → Canvas,

    SVG, VML (IE8), React Native, etc.
  30. import { Surface, Shape } from 'ReactNativeART'; function Square() {

    const d = Path() .moveTo(100, 100) .lineTo(200, 100) .lineTo(200, 200) .lineTo(100, 200) .close(); return <Surface width={300} height={300}> <Shape fill="#000000" d={d} /> <Surface>; }
  31. function AreaChart({ width, height, points }) { let i =

    0; let path = Path().moveTo(0, h) .lineTo(0, points[i].y) .lineTo(points[i].x, points[i].y); for (i = 1; i < 24 - 2; i++) { const p = points[i]; const q = points[i + 1]; const xc = (p.x + q.x) / 2; const yc = (p.y + q.y) / 2; path = path.curveTo(p.x, p.y, xc, yc); } path = path .curveTo(points[i].x, points[i].y, points[i + 1].x, points[i + 1].y) .lineTo(CHART_WIDTH, points[i + 1].y); const d = path.lineTo(w, h).close(); return <Surface width={width} height={height}> <Shape fill="#ff9999" d={d} /> </Surface>; }
  32. None
  33. Path animation Before: <Surface width={width} height={height}> <Shape fill="#ff9999" d={d} />

    </Surface>; After: const AnimatedShape = Animated.createAnimatedComponent(Shape); <Surface width={width} height={height}> <AnimatedShape fill="#ff9999" d={d} /> </Surface>;
  34. d is made of multiple heights. // Non-animated (heights: number[])

    => Path // Animated (animatedHeights: Animated<number>[]) => Animated<Path>
  35. // We have: Animated.add, Animated.multiply: (a: Animated<number>, b: Animated<number>) =>

    Animated<number> // We want: Animated.aggregate<T>: (xs: Animated<number>[], f: (number[]) => T) => Animated<T>
  36. None
  37. None
  38. const animatedHeights = Array.from(Array(24)) .map(() => new Animated.Value(0)); const animatedPath

    = aggregate( animatedHeights, heights => areaChartPath(CHART_WIDTH, CHART_HEIGHT, heights) );
  39. None
  40. None
  41. Recap → You can draw (almost) anything with View &

    CSS → LayoutAnimation is super easy → Draw curves with React ART → Path animation is feasible but (a bit) slow
  42. Thanks! https://github.com/shuhei/Compare