Showing
4 changed files
with
260 additions
and
7 deletions
| ... | @@ -10,12 +10,16 @@ | ... | @@ -10,12 +10,16 @@ |
| 10 | "lint": "eslint ." | 10 | "lint": "eslint ." |
| 11 | }, | 11 | }, |
| 12 | "dependencies": { | 12 | "dependencies": { |
| 13 | + "d3": "^5.14.2", | ||
| 13 | "express": "^4.17.1", | 14 | "express": "^4.17.1", |
| 14 | "react": "16.9.0", | 15 | "react": "16.9.0", |
| 15 | "react-native": "0.61.4", | 16 | "react-native": "0.61.4", |
| 16 | "react-native-gesture-handler": "^1.5.0", | 17 | "react-native-gesture-handler": "^1.5.0", |
| 17 | "react-native-reanimated": "^1.4.0", | 18 | "react-native-reanimated": "^1.4.0", |
| 18 | "react-native-screens": "^2.0.0-alpha.8", | 19 | "react-native-screens": "^2.0.0-alpha.8", |
| 20 | + "react-native-segmented-control-tab": "^3.4.1", | ||
| 21 | + "react-native-svg": "^9.13.6", | ||
| 22 | + "react-native-svg-charts": "^5.3.0", | ||
| 19 | "react-native-table-component": "^1.2.1", | 23 | "react-native-table-component": "^1.2.1", |
| 20 | "react-native-vector-icons": "^6.6.0", | 24 | "react-native-vector-icons": "^6.6.0", |
| 21 | "react-navigation": "^4.0.10", | 25 | "react-navigation": "^4.0.10", | ... | ... |
| 1 | import React, { Component } from 'react'; | 1 | import React, { Component } from 'react'; |
| 2 | -import { View, Text, StyleSheet } from 'react-native'; | 2 | +import { View, Text, StyleSheet,ScrollView, RefreshControl } from 'react-native'; |
| 3 | +import { BarChart, Grid } from 'react-native-svg-charts' | ||
| 4 | +import HistoryGraph from '../component/HistoryGraph' | ||
| 5 | +import SegmentedControlTab from "react-native-segmented-control-tab"; | ||
| 6 | +const data1 = [ | ||
| 7 | + { label: 'MON', value: 1.8 }, | ||
| 8 | + { label: 'TUE', value: 4.2 }, | ||
| 9 | + { label: 'WEN', value: 1.6 }, | ||
| 10 | + { label: 'THU', value: 0 }, | ||
| 11 | + { label: 'FRI', value: 2.0 }, | ||
| 12 | + { label: 'SAT', value: 3.3 }, | ||
| 13 | + { label: 'SUN', value: 1.3 } | ||
| 14 | +] | ||
| 15 | +const data2 = [ | ||
| 16 | + { label: '1', value: 4.6 }, | ||
| 17 | + { label: '8', value: 3.7 }, | ||
| 18 | + { label: '15', value: 3.0 }, | ||
| 19 | + { label: '22', value: 5.2 }, | ||
| 20 | + { label: '29', value: 3.1 } | ||
| 21 | +] | ||
| 22 | +const data3 = [ | ||
| 23 | + { label: 'Jan', value: 500 }, | ||
| 24 | + { label: 'Feb', value: 312 }, | ||
| 25 | + { label: 'Mar', value: 424 }, | ||
| 26 | + { label: 'Apr', value: 745 }, | ||
| 27 | + { label: 'May', value: 89 }, | ||
| 28 | + { label: 'Jun', value: 434 }, | ||
| 29 | + { label: 'Jul', value: 650 }, | ||
| 30 | + { label: 'Aug', value: 980 }, | ||
| 31 | + { label: 'Sep', value: 123 }, | ||
| 32 | + { label: 'Oct', value: 186 }, | ||
| 33 | + { label: 'Nov', value: 689 }, | ||
| 34 | + { label: 'Dec', value: 643 } | ||
| 35 | +] | ||
| 36 | + | ||
| 37 | +const data4 = [ | ||
| 38 | + { label: 'C', value: 500 }, | ||
| 39 | + { label: 'H', value: 312 }, | ||
| 40 | + { label: 'A', value: 424 }, | ||
| 41 | + { label: 'N', value: 745 }, | ||
| 42 | + { label: 'G', value: 89 }, | ||
| 43 | + { label: 'E', value: 434 } | ||
| 44 | +] | ||
| 45 | + | ||
| 46 | +const kg1 = "총 3.5kg" | ||
| 47 | +const kg2 = "총 9,6kg" | ||
| 48 | +const kg3 = "총 21.3kg" | ||
| 3 | 49 | ||
| 4 | export default class HomeTab extends Component { | 50 | export default class HomeTab extends Component { |
| 51 | + constructor(){ | ||
| 52 | + super(); | ||
| 53 | + this.state = { | ||
| 54 | + selectedIndex: 0, | ||
| 55 | + data: data1, | ||
| 56 | + title: "총 3.5kg", | ||
| 57 | + spane: "", | ||
| 58 | + refreshing: false | ||
| 59 | + } | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + _onRefresh = () => { | ||
| 63 | + this.setState({refresing: true}); | ||
| 64 | + this.setState({data: data4}) | ||
| 65 | + this.setState({refreshing: false}); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + handleIndexChange = index => { | ||
| 69 | + this.setState({selectedIndex: index}); | ||
| 70 | + switch(index){ | ||
| 71 | + case 0: | ||
| 72 | + this.setState({data: data1, title: kg1}); | ||
| 73 | + break; | ||
| 74 | + case 1: | ||
| 75 | + this.setState({data: data2, title: kg2}); | ||
| 76 | + break; | ||
| 77 | + case 2: | ||
| 78 | + this.setState({data: data3, title: kg3}); | ||
| 79 | + break; | ||
| 80 | + } | ||
| 81 | + }; | ||
| 82 | + | ||
| 5 | render() { | 83 | render() { |
| 6 | - return ( | 84 | + // const fill = 'rgb(134, 65, 244)' |
| 7 | - <View style={style.container}> | 85 | + // const data = [50, 10, 40, 95, -4, -24, null, 85, undefined, 0, 35, 53, -53, 24, 50, -20, -80] |
| 8 | - <Text>HistoryTab</Text> | 86 | + |
| 9 | - </View> | 87 | + // return ( |
| 10 | - ); | 88 | + // <BarChart style={{ height: 200 }} data={data} svg={{ fill }} contentInset={{ top: 30, bottom: 30 }}> |
| 89 | + // <Grid /> | ||
| 90 | + // </BarChart> | ||
| 91 | + // ); | ||
| 92 | + | ||
| 93 | + return( | ||
| 94 | + <ScrollView | ||
| 95 | + refreshControl={ | ||
| 96 | + <RefreshControl | ||
| 97 | + refreshing={this.state.refreshing} | ||
| 98 | + onRefresh={this._onRefresh} | ||
| 99 | + tintColor="#ff0000" | ||
| 100 | + title="Loading..." | ||
| 101 | + titleColor="#00ff00" | ||
| 102 | + colors={["#ff0000",'#00ff00','#0000ff']} | ||
| 103 | + progressBackgroundColor="#ffff00" | ||
| 104 | + /> | ||
| 105 | + } | ||
| 106 | + > | ||
| 107 | + <Text>{this.state.title}</Text> | ||
| 108 | + <SegmentedControlTab | ||
| 109 | + values={["Week", "Month", "Year"]} | ||
| 110 | + selectedIndex={this.state.selectedIndex} | ||
| 111 | + onTabPress={this.handleIndexChange} | ||
| 112 | + /> | ||
| 113 | + <HistoryGraph data={this.state.data} round={100} unit="kg"/> | ||
| 114 | + </ScrollView> | ||
| 115 | + ) | ||
| 11 | } | 116 | } |
| 12 | } | 117 | } |
| 13 | 118 | ||
| ... | @@ -17,4 +122,4 @@ const style = StyleSheet.create({ | ... | @@ -17,4 +122,4 @@ const style = StyleSheet.create({ |
| 17 | alignItems: 'center', | 122 | alignItems: 'center', |
| 18 | justifyContent: 'center', | 123 | justifyContent: 'center', |
| 19 | } | 124 | } |
| 20 | -}); | 125 | +}) |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
source/component/HistoryGraph.js
0 → 100644
| 1 | +import React, { PureComponent } from 'react' | ||
| 2 | +import { View, Text, StyleSheet } from 'react-native'; | ||
| 3 | +import { Svg, G, Line, Rect } from 'react-native-svg' | ||
| 4 | +import { Text as SvgText } from 'react-native-svg' | ||
| 5 | +import * as d3 from 'd3' | ||
| 6 | +// import Showkg from './ShowKg' | ||
| 7 | + | ||
| 8 | +const GRAPH_MARGIN = 20 | ||
| 9 | +const GRAPH_BAR_WIDTH = 5 | ||
| 10 | +const colors = { | ||
| 11 | + axis: '#E4E4E4', | ||
| 12 | + bars: '#15AD13', | ||
| 13 | + bardefult: '#CED4DA' | ||
| 14 | +} | ||
| 15 | + | ||
| 16 | +export default class HistoryGraph extends PureComponent { | ||
| 17 | + | ||
| 18 | + constructor(props){ | ||
| 19 | + super(props); | ||
| 20 | + this.handleClick = this.handleClick.bind(this); | ||
| 21 | + this.state = { | ||
| 22 | + kg: this.props.data[this.props.data.length - 1].label, | ||
| 23 | + index: this.props.data.length-1 | ||
| 24 | + } | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + handleClick = inkg => { | ||
| 28 | + this.setState({kg: inkg}); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + componentDidUpdate(prevProps, prevState){ | ||
| 32 | + if (this.props.data !== prevProps.data) { | ||
| 33 | + this.setState({ | ||
| 34 | + ...this.state, | ||
| 35 | + kg : this.props.data[this.props.data.length - 1].label, | ||
| 36 | + index: this.props.data.length-1 | ||
| 37 | + }) | ||
| 38 | + } } | ||
| 39 | + | ||
| 40 | + render() { | ||
| 41 | + // Dimensions | ||
| 42 | + const SVGHeight = 300 | ||
| 43 | + const SVGWidth = 300 | ||
| 44 | + const graphHeight = SVGHeight - 2 * GRAPH_MARGIN | ||
| 45 | + const graphWidth = SVGWidth - 2 * GRAPH_MARGIN | ||
| 46 | + const data = this.props.data | ||
| 47 | + | ||
| 48 | + // X scale point | ||
| 49 | + const xDomain = data.map(item => item.label) | ||
| 50 | + const xRange = [0, graphWidth] | ||
| 51 | + const x = d3.scalePoint() | ||
| 52 | + .domain(xDomain) | ||
| 53 | + .range(xRange) | ||
| 54 | + .padding(1) | ||
| 55 | + | ||
| 56 | + // Y scale linear | ||
| 57 | + const maxValue = d3.max(data, d => d.value) | ||
| 58 | + const topValue = Math.ceil(maxValue / this.props.round) * this.props.round | ||
| 59 | + const yDomain = [0, topValue] | ||
| 60 | + const yRange = [0, graphHeight] | ||
| 61 | + const y = d3.scaleLinear() | ||
| 62 | + .domain(yDomain) | ||
| 63 | + .range(yRange) | ||
| 64 | + | ||
| 65 | + // top axis and middle axis | ||
| 66 | + const middleValue = topValue / 2 | ||
| 67 | + | ||
| 68 | + return ( | ||
| 69 | + <View> | ||
| 70 | + <Svg width={SVGWidth} height={SVGHeight}> | ||
| 71 | + <G y={graphHeight + GRAPH_MARGIN}> | ||
| 72 | + {/* Top value label */} | ||
| 73 | + <SvgText | ||
| 74 | + x={graphWidth} | ||
| 75 | + textAnchor="end" | ||
| 76 | + y={y(topValue) * -1 - 5} | ||
| 77 | + fontSize={12} | ||
| 78 | + fill="black" | ||
| 79 | + fillOpacity={0.4}> | ||
| 80 | + {topValue + ' ' + this.props.unit} | ||
| 81 | + </SvgText> | ||
| 82 | + | ||
| 83 | + {/* top axis */} | ||
| 84 | + <Line | ||
| 85 | + x1="0" | ||
| 86 | + y1={y(topValue) * -1} | ||
| 87 | + x2={graphWidth} | ||
| 88 | + y2={y(topValue) * -1} | ||
| 89 | + stroke={colors.axis} | ||
| 90 | + strokeDasharray={[3, 3]} | ||
| 91 | + strokeWidth="0.5" | ||
| 92 | + /> | ||
| 93 | + | ||
| 94 | + {/* middle axis */} | ||
| 95 | + <Line | ||
| 96 | + x1="0" | ||
| 97 | + y1={y(middleValue) * -1} | ||
| 98 | + x2={graphWidth} | ||
| 99 | + y2={y(middleValue) * -1} | ||
| 100 | + stroke={colors.axis} | ||
| 101 | + strokeDasharray={[3, 3]} | ||
| 102 | + strokeWidth="0.5" | ||
| 103 | + /> | ||
| 104 | + | ||
| 105 | + {/* bottom axis */} | ||
| 106 | + <Line | ||
| 107 | + x1="0" | ||
| 108 | + y1="2" | ||
| 109 | + x2={graphWidth} | ||
| 110 | + y2="2" | ||
| 111 | + stroke={colors.axis} | ||
| 112 | + strokeWidth="0.5" | ||
| 113 | + /> | ||
| 114 | + | ||
| 115 | + {/* bars */} | ||
| 116 | + {data.map(item => ( | ||
| 117 | + <Rect | ||
| 118 | + key={'bar' + item.label} | ||
| 119 | + x={x(item.label) - (GRAPH_BAR_WIDTH / 2)} | ||
| 120 | + y={y(item.value) * -1} | ||
| 121 | + rx={2.5} | ||
| 122 | + width={GRAPH_BAR_WIDTH} | ||
| 123 | + height={y(item.value)} | ||
| 124 | + fill = {this.state.kg == item.label ? colors.bars : colors.bardefult} | ||
| 125 | + onPress={()=>this.handleClick(item.label)} | ||
| 126 | + /> | ||
| 127 | + ))} | ||
| 128 | + | ||
| 129 | + {/* labels */} | ||
| 130 | + {data.map(item => ( | ||
| 131 | + <SvgText | ||
| 132 | + key={'label' + item.label} | ||
| 133 | + fontSize="8" | ||
| 134 | + x={x(item.label)} | ||
| 135 | + y="10" | ||
| 136 | + textAnchor="middle">{item.label}</SvgText> | ||
| 137 | + ))} | ||
| 138 | + </G> | ||
| 139 | + </Svg> | ||
| 140 | + <Text>{this.state.kg}</Text> | ||
| 141 | + </View> | ||
| 142 | + ) | ||
| 143 | + } | ||
| 144 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
This diff is collapsed. Click to expand it.
-
Please register or login to post a comment