1 | import React from "react";
|
2 | import { View } from "react-native";
|
3 | import { Svg, Rect, G, Text } from "react-native-svg";
|
4 | import AbstractChart from "./abstract-chart";
|
5 |
|
6 | const barWidth = 32;
|
7 |
|
8 | class StackedBarChart extends AbstractChart {
|
9 | renderBars = config => {
|
10 | const {
|
11 | data,
|
12 | width,
|
13 | height,
|
14 | paddingTop,
|
15 | paddingRight,
|
16 | border,
|
17 | colors
|
18 | } = config;
|
19 | return data.map((x, i) => {
|
20 | const barWidth = 32;
|
21 | const ret = [];
|
22 | let h = 0;
|
23 | let st = paddingTop;
|
24 | for (let z = 0; z < x.length; z++) {
|
25 | h = (height - 55) * (x[z] / border);
|
26 | const y = (height / 4) * 3 - h + st;
|
27 | const xC =
|
28 | (paddingRight +
|
29 | (i * (width - paddingRight)) / data.length +
|
30 | barWidth / 2) *
|
31 | 0.7;
|
32 | ret.push(
|
33 | <Rect
|
34 | key={Math.random()}
|
35 | x={xC}
|
36 | y={y}
|
37 | width={barWidth}
|
38 | height={h}
|
39 | fill={colors[z]}
|
40 | />
|
41 | );
|
42 | ret.push(
|
43 | <Text
|
44 | key={Math.random()}
|
45 | x={xC + 7 + barWidth / 2}
|
46 | textAnchor="end"
|
47 | y={h > 15 ? y + 15 : y + 7}
|
48 | {...this.getPropsForLabels()}
|
49 | >
|
50 | {x[z]}
|
51 | </Text>
|
52 | );
|
53 |
|
54 | st -= h;
|
55 | }
|
56 |
|
57 | return ret;
|
58 | });
|
59 | };
|
60 |
|
61 | renderLegend = config => {
|
62 | const { legend, colors, width, height } = config;
|
63 | return legend.map((x, i) => {
|
64 | return (
|
65 | <G key={Math.random()}>
|
66 | <Rect
|
67 | width="16px"
|
68 | height="16px"
|
69 | fill={colors[i]}
|
70 | rx={8}
|
71 | ry={8}
|
72 | x={width * 0.71}
|
73 | y={height * 0.7 - i * 50}
|
74 | />
|
75 | <Text
|
76 | x={width * 0.78}
|
77 | y={height * 0.76 - i * 50}
|
78 | {...this.getPropsForLabels()}
|
79 | >
|
80 | {x}
|
81 | </Text>
|
82 | </G>
|
83 | );
|
84 | });
|
85 | };
|
86 |
|
87 | render() {
|
88 | const paddingTop = 15;
|
89 | const paddingRight = 50;
|
90 | const {
|
91 | width,
|
92 | height,
|
93 | style = {},
|
94 | data,
|
95 | withHorizontalLabels = true,
|
96 | withVerticalLabels = true
|
97 | } = this.props;
|
98 | const { borderRadius = 0 } = style;
|
99 | const config = {
|
100 | width,
|
101 | height
|
102 | };
|
103 | let border = 0;
|
104 | for (let i = 0; i < data.data.length; i++) {
|
105 | const actual = data.data[i].reduce((pv, cv) => pv + cv, 0);
|
106 | if (actual > border) {
|
107 | border = actual;
|
108 | }
|
109 | }
|
110 |
|
111 | return (
|
112 | <View style={style}>
|
113 | <Svg height={height} width={width}>
|
114 | {this.renderDefs({
|
115 | ...config,
|
116 | ...this.props.chartConfig
|
117 | })}
|
118 | <Rect
|
119 | width="100%"
|
120 | height={height}
|
121 | rx={borderRadius}
|
122 | ry={borderRadius}
|
123 | fill="url(#backgroundGradient)"
|
124 | />
|
125 | <G>
|
126 | {this.renderHorizontalLines({
|
127 | ...config,
|
128 | count: 4,
|
129 | paddingTop
|
130 | })}
|
131 | </G>
|
132 | <G>
|
133 | {withHorizontalLabels
|
134 | ? this.renderHorizontalLabels({
|
135 | ...config,
|
136 | count: 4,
|
137 | data: [0, border],
|
138 | paddingTop,
|
139 | paddingRight
|
140 | })
|
141 | : null}
|
142 | </G>
|
143 | <G>
|
144 | {withVerticalLabels
|
145 | ? this.renderVerticalLabels({
|
146 | ...config,
|
147 | labels: data.labels,
|
148 | paddingRight: paddingRight + 28,
|
149 | stackedBar: true,
|
150 | paddingTop,
|
151 | horizontalOffset: barWidth
|
152 | })
|
153 | : null}
|
154 | </G>
|
155 | <G>
|
156 | {this.renderBars({
|
157 | ...config,
|
158 | data: data.data,
|
159 | border,
|
160 | colors: this.props.data.barColors,
|
161 | paddingTop,
|
162 | paddingRight: paddingRight + 20
|
163 | })}
|
164 | </G>
|
165 | {this.renderLegend({
|
166 | ...config,
|
167 | legend: data.legend,
|
168 | colors: this.props.data.barColors
|
169 | })}
|
170 | </Svg>
|
171 | </View>
|
172 | );
|
173 | }
|
174 | }
|
175 | export default StackedBarChart;
|