Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

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