Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

Me → Software Engineer at M3, Inc. → AngularJS, Rails, Babel, etc. → GitHub, Qiita: @shuhei → Twitter: @shuheikagawa

Slide 4

Slide 4 text

EcmaScript & Me Stage 0 Method Parameter Decorators -> babel/babylon @Component({ /* ... */ }) class App { constructor(@Inject('something') foo) { } }

Slide 5

Slide 5 text

React Native

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

23°?

Slide 9

Slide 9 text

I only remember yesterday's temperature

Slide 10

Slide 10 text

Let's compare!

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

Let’s drawing charts in React-Native without any library by WangZixiao

Slide 14

Slide 14 text

==

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

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 } });

Slide 18

Slide 18 text

const bars = days.map((day, i) => ); {bars} const styles = StyleSheet.create({ container: { alignItems: 'flex-end', flexDirection: 'row', }, barBox: { width: 10, marginHorizontal: 2, alignItems: 'flex-end', flexDirection: 'row', } });

Slide 19

Slide 19 text

Animation in React Native → Explicit: Animated → Implicit: LayoutAnimation

Slide 20

Slide 20 text

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 => ); return {bars}; } // ... }

Slide 21

Slide 21 text

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(); } }

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

Not so bad.

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

LayoutAnimation // Somewhere in a container component... LayoutAnimation.spring(); this.setState({ ...whatever }); // Just render as if no animation. function TemperatureBar({ temperature }) { return }

Slide 26

Slide 26 text

But I want curves...

Slide 27

Slide 27 text

gl-react-native?

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

react-art! → SVG-like vector graphics API on React → Canvas, SVG, VML (IE8), React Native, etc.

Slide 30

Slide 30 text

import { Surface, Shape } from 'ReactNativeART'; function Square() { const d = Path() .moveTo(100, 100) .lineTo(200, 100) .lineTo(200, 200) .lineTo(100, 200) .close(); return ; }

Slide 31

Slide 31 text

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 ; }

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

Path animation Before: ; After: const AnimatedShape = Animated.createAnimatedComponent(Shape); ;

Slide 34

Slide 34 text

d is made of multiple heights. // Non-animated (heights: number[]) => Path // Animated (animatedHeights: Animated[]) => Animated

Slide 35

Slide 35 text

// We have: Animated.add, Animated.multiply: (a: Animated, b: Animated) => Animated // We want: Animated.aggregate: (xs: Animated[], f: (number[]) => T) => Animated

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

const animatedHeights = Array.from(Array(24)) .map(() => new Animated.Value(0)); const animatedPath = aggregate( animatedHeights, heights => areaChartPath(CHART_WIDTH, CHART_HEIGHT, heights) );

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

Thanks! https://github.com/shuhei/Compare