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