react-native-gifted-charts 1.2.24 → 1.2.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-gifted-charts",
3
- "version": "1.2.24",
3
+ "version": "1.2.27",
4
4
  "description": "The most complete library for Bar, Line, Area, Pie, Donut and Stacked Bar charts in React Native. Allows 2D, 3D, gradient, animations and live data updates.",
5
5
  "main": "src/index.tsx",
6
6
  "files": [
@@ -49,10 +49,6 @@ type Props = {
49
49
  capThickness?: number;
50
50
  capColor?: ColorValue;
51
51
  capRadius?: number;
52
- showVerticalLines: Boolean;
53
- verticalLinesThickness: number;
54
- verticalLinesColor: ColorValue;
55
- verticalLinesZIndex: number;
56
52
  showXAxisIndices: Boolean;
57
53
  xAxisIndicesHeight: number;
58
54
  xAxisIndicesWidth: number;
@@ -379,7 +375,7 @@ const RenderBars = (props: Props) => {
379
375
  // { backgroundColor: item.frontColor || props.frontColor || 'black' },
380
376
  side !== 'right' && {zIndex: data.length - index},
381
377
  ]}>
382
- {props.showVerticalLines && (
378
+ {/* {props.showVerticalLines && (
383
379
  <View
384
380
  style={{
385
381
  zIndex: props.verticalLinesZIndex,
@@ -391,7 +387,7 @@ const RenderBars = (props: Props) => {
391
387
  backgroundColor: props.verticalLinesColor,
392
388
  }}
393
389
  />
394
- )}
390
+ )} */}
395
391
  {props.showXAxisIndices && (
396
392
  <View
397
393
  style={{
@@ -25,10 +25,6 @@ type Props = {
25
25
  barWidth?: number;
26
26
 
27
27
  rotateLabel?: Boolean;
28
- showVerticalLines: Boolean;
29
- verticalLinesThickness: number;
30
- verticalLinesColor: ColorValue;
31
- verticalLinesZIndex: number;
32
28
  showXAxisIndices: Boolean;
33
29
  xAxisIndicesHeight: number;
34
30
  xAxisIndicesWidth: number;
@@ -256,7 +252,7 @@ const RenderStackBars = (props: Props) => {
256
252
  marginRight: spacing,
257
253
  },
258
254
  ]}>
259
- {props.showVerticalLines && (
255
+ {/* {props.showVerticalLines && (
260
256
  <View
261
257
  style={{
262
258
  zIndex: props.verticalLinesZIndex,
@@ -268,7 +264,7 @@ const RenderStackBars = (props: Props) => {
268
264
  backgroundColor: props.verticalLinesColor,
269
265
  }}
270
266
  />
271
- )}
267
+ )} */}
272
268
  {props.showXAxisIndices && (
273
269
  <View
274
270
  style={{
@@ -82,8 +82,11 @@ type PropTypes = {
82
82
  referenceLine3Position?: number;
83
83
  showVerticalLines?: Boolean;
84
84
  verticalLinesThickness?: number;
85
+ verticalLinesHeight?: number;
85
86
  verticalLinesColor?: ColorValue;
86
87
  verticalLinesZIndex?: number;
88
+ noOfVerticalLines?: number;
89
+ verticalLinesSpacing?: number;
87
90
 
88
91
  showYAxisIndices?: Boolean;
89
92
  showXAxisIndices?: Boolean;
@@ -346,8 +349,16 @@ export const BarChart = (props: PropTypes) => {
346
349
  const rulesColor = props.rulesColor || 'lightgray';
347
350
  const verticalLinesThickness =
348
351
  props.verticalLinesThickness === 0 ? 0 : props.verticalLinesThickness || 1;
352
+ const verticalLinesHeight = props.verticalLinesHeight;
349
353
  const verticalLinesColor = props.verticalLinesColor || 'lightgray';
350
354
  const verticalLinesZIndex = props.verticalLinesZIndex || -1;
355
+ let verticalLinesAr = [];
356
+ props.noOfVerticalLines
357
+ ? (verticalLinesAr = [...Array(props.noOfVerticalLines).keys()])
358
+ : (verticalLinesAr = [
359
+ ...Array(props.stackData ? props.stackData.length : data.length).keys(),
360
+ ]);
361
+ const verticalLinesSpacing = props.verticalLinesSpacing || 0;
351
362
 
352
363
  const showYAxisIndices = props.showYAxisIndices || false;
353
364
  const showXAxisIndices = props.showXAxisIndices || false;
@@ -1372,6 +1383,78 @@ export const BarChart = (props: PropTypes) => {
1372
1383
  // data={props.stackData || data}
1373
1384
  keyExtractor={(item, index) => index.toString()}>
1374
1385
  <Fragment>
1386
+ {showVerticalLines &&
1387
+ verticalLinesAr.map((item: itemType, index: number) => {
1388
+ let totalSpacing = initialSpacing;
1389
+ if (verticalLinesSpacing) {
1390
+ totalSpacing = verticalLinesSpacing * (index + 1);
1391
+ } else {
1392
+ if (props.stackData) {
1393
+ totalSpacing +=
1394
+ (props.stackData[0].barWidth || props.barWidth || 30) / 2;
1395
+ } else {
1396
+ totalSpacing +=
1397
+ (props.data[0].barWidth || props.barWidth || 30) / 2;
1398
+ }
1399
+ for (let i = 0; i < index; i++) {
1400
+ let actualSpacing = spacing;
1401
+ if (props.stackData) {
1402
+ if (i >= props.stackData.length - 1) {
1403
+ actualSpacing += (props.barWidth || 30) / 2;
1404
+ } else {
1405
+ if (
1406
+ props.stackData[i].spacing ||
1407
+ props.stackData[i].spacing === 0
1408
+ ) {
1409
+ actualSpacing = props.stackData[i].spacing;
1410
+ }
1411
+ if (props.stackData[i + 1].barWidth) {
1412
+ actualSpacing += props.stackData[i + 1].barWidth;
1413
+ } else {
1414
+ actualSpacing += props.barWidth || 30;
1415
+ }
1416
+ }
1417
+ } else {
1418
+ if (i >= props.data.length - 1) {
1419
+ actualSpacing += (props.barWidth || 30) / 2;
1420
+ } else {
1421
+ if (
1422
+ props.data[i].spacing ||
1423
+ props.data[i].spacing === 0
1424
+ ) {
1425
+ console.log('here for index ' + index + ' and i ' + i);
1426
+ actualSpacing = props.data[i].spacing;
1427
+ }
1428
+ if (props.data[i + 1].barWidth) {
1429
+ actualSpacing += props.data[i + 1].barWidth;
1430
+ } else {
1431
+ actualSpacing += props.barWidth || 30;
1432
+ }
1433
+ }
1434
+ }
1435
+ console.log('i = ' + i + ' actualSpacing ' + actualSpacing);
1436
+ totalSpacing += actualSpacing;
1437
+ }
1438
+ }
1439
+
1440
+ return (
1441
+ <View
1442
+ key={index}
1443
+ style={{
1444
+ position: 'absolute',
1445
+ zIndex: verticalLinesZIndex || -1,
1446
+ marginBottom: xAxisThickness,
1447
+ height:
1448
+ verticalLinesHeight ||
1449
+ containerHeight + 15 - xAxisThickness,
1450
+ width: verticalLinesThickness,
1451
+ backgroundColor: verticalLinesColor,
1452
+ bottom: 60 + labelsExtraHeight,
1453
+ left: totalSpacing,
1454
+ }}
1455
+ />
1456
+ );
1457
+ })}
1375
1458
  {showLine
1376
1459
  ? lineConfig.isAnimated
1377
1460
  ? renderAnimatedLine()
@@ -1394,10 +1477,6 @@ export const BarChart = (props: PropTypes) => {
1394
1477
  opacity={opacity}
1395
1478
  disablePress={item.disablePress || props.disablePress}
1396
1479
  rotateLabel={rotateLabel}
1397
- showVerticalLines={showVerticalLines}
1398
- verticalLinesThickness={verticalLinesThickness}
1399
- verticalLinesColor={verticalLinesColor}
1400
- verticalLinesZIndex={verticalLinesZIndex}
1401
1480
  showXAxisIndices={showXAxisIndices}
1402
1481
  xAxisIndicesHeight={xAxisIndicesHeight}
1403
1482
  xAxisIndicesWidth={xAxisIndicesWidth}
@@ -1459,10 +1538,6 @@ export const BarChart = (props: PropTypes) => {
1459
1538
  capThickness={props.capThickness}
1460
1539
  capColor={props.capColor}
1461
1540
  capRadius={props.capRadius}
1462
- showVerticalLines={showVerticalLines}
1463
- verticalLinesThickness={verticalLinesThickness}
1464
- verticalLinesColor={verticalLinesColor}
1465
- verticalLinesZIndex={verticalLinesZIndex}
1466
1541
  showXAxisIndices={showXAxisIndices}
1467
1542
  xAxisIndicesHeight={xAxisIndicesHeight}
1468
1543
  xAxisIndicesWidth={xAxisIndicesWidth}
@@ -108,8 +108,11 @@ type propTypes = {
108
108
  showVerticalLines?: Boolean;
109
109
  verticalLinesUptoDataPoint?: Boolean;
110
110
  verticalLinesThickness?: number;
111
+ verticalLinesHeight?: number;
111
112
  verticalLinesColor?: ColorValue;
112
113
  verticalLinesZIndex?: number;
114
+ noOfVerticalLines?: number;
115
+ verticalLinesSpacing?: number;
113
116
  hideAxesAndRules?: Boolean;
114
117
  areaChart?: Boolean;
115
118
 
@@ -1367,6 +1370,7 @@ export const LineChart = (props: propTypes) => {
1367
1370
  const rulesColor = props.rulesColor || 'lightgray';
1368
1371
  const verticalLinesThickness =
1369
1372
  props.verticalLinesThickness === 0 ? 0 : props.verticalLinesThickness || 1;
1373
+ const verticalLinesHeight = props.verticalLinesHeight;
1370
1374
  const verticalLinesColor = props.verticalLinesColor || 'lightgray';
1371
1375
  const verticalLinesZIndex = props.verticalLinesZIndex || -1;
1372
1376
 
@@ -1377,6 +1381,12 @@ export const LineChart = (props: propTypes) => {
1377
1381
  const hideRules = props.hideRules || false;
1378
1382
  const showVerticalLines = props.showVerticalLines || false;
1379
1383
  const verticalLinesUptoDataPoint = props.verticalLinesUptoDataPoint || false;
1384
+ let verticalLinesAr = [];
1385
+ props.noOfVerticalLines
1386
+ ? (verticalLinesAr = [...Array(props.noOfVerticalLines).keys()])
1387
+ : (verticalLinesAr = [...Array(data.length).keys()]);
1388
+
1389
+ const verticalLinesSpacing = props.verticalLinesSpacing || 0;
1380
1390
 
1381
1391
  const showYAxisIndices = props.showYAxisIndices || false;
1382
1392
  const showXAxisIndices = props.showXAxisIndices || false;
@@ -3290,7 +3300,7 @@ export const LineChart = (props: propTypes) => {
3290
3300
  props.width && {width: props.width + 10},
3291
3301
  ]}>
3292
3302
  {showVerticalLines &&
3293
- data.map((item: itemType, index: number) => {
3303
+ verticalLinesAr.map((item: itemType, index: number) => {
3294
3304
  return (
3295
3305
  <View
3296
3306
  key={index}
@@ -3299,13 +3309,18 @@ export const LineChart = (props: propTypes) => {
3299
3309
  zIndex: verticalLinesZIndex || -1,
3300
3310
  marginBottom: xAxisThickness,
3301
3311
  height: verticalLinesUptoDataPoint
3302
- ? (item.value * containerHeight) / maxValue - xAxisThickness
3303
- : containerHeight + 15 - xAxisThickness,
3312
+ ? index < data.length
3313
+ ? (data[index].value * containerHeight) / maxValue -
3314
+ xAxisThickness
3315
+ : verticalLinesHeight || 0
3316
+ : verticalLinesHeight ||
3317
+ containerHeight + 15 - xAxisThickness,
3304
3318
  width: verticalLinesThickness,
3305
3319
  backgroundColor: verticalLinesColor,
3306
- bottom: 60,
3307
- left:
3308
- index * spacing + (initialSpacing - dataPointsWidth1 / 2),
3320
+ bottom: 60 + labelsExtraHeight,
3321
+ left: verticalLinesSpacing
3322
+ ? verticalLinesSpacing * (index + 1)
3323
+ : index * spacing + (initialSpacing - dataPointsWidth1 / 2),
3309
3324
  }}
3310
3325
  />
3311
3326
  );
@@ -0,0 +1,10 @@
1
+ export const colors = [
2
+ 'cyan',
3
+ 'green',
4
+ 'orange',
5
+ 'purple',
6
+ '#bbff00',
7
+ 'red',
8
+ 'blue',
9
+ 'pink',
10
+ ];
@@ -1,14 +1,8 @@
1
- import React from 'react';
2
- import {ColorValue, View} from 'react-native';
3
- import Svg, {
4
- Path,
5
- Circle,
6
- Text as SvgText,
7
- FontStyle,
8
- Defs,
9
- RadialGradient,
10
- Stop,
11
- } from 'react-native-svg';
1
+ import React, {useState} from 'react';
2
+ import {View, ColorValue} from 'react-native';
3
+ import {colors} from './colors';
4
+ import {PieChartMain} from './main';
5
+ import {FontStyle} from 'react-native-svg';
12
6
 
13
7
  type propTypes = {
14
8
  radius?: number;
@@ -47,7 +41,12 @@ type propTypes = {
47
41
  showGradient?: boolean;
48
42
  gradientCenterColor?: string;
49
43
  onPress?: Function;
44
+ focusOnPress?: Boolean;
45
+ toggleFocusOnPress?: Boolean;
46
+ selectedIndex?: number;
47
+ setSelectedIndex?: Function;
50
48
  onLabelPress?: Function;
49
+ extraRadiusForFocused?: number;
51
50
  };
52
51
  type itemType = {
53
52
  value: number;
@@ -71,399 +70,69 @@ type itemType = {
71
70
  };
72
71
 
73
72
  export const PieChart = (props: propTypes) => {
74
- const {data, isThreeD} = props;
75
73
  const radius = props.radius || 120;
76
- const canvasWidth = radius * 2;
77
- const canvasHeight = isThreeD ? radius * 2.3 : radius * 2;
78
- const shadowWidth = props.shadowWidth || radius / 5;
79
- const backgroundColor = props.backgroundColor || 'transparent';
80
- const shadowColor = props.shadowColor || 'lightgray';
81
- const semiCircle = props.semiCircle || false;
82
- let pi = Math.PI;
83
- const initialAngle = props.initialAngle || (semiCircle ? pi / -2 : 0);
84
- const shadow = props.shadow || false;
85
- const donut = props.donut || false;
86
- const strokeWidth = props.strokeWidth || 0;
87
- const strokeColor =
88
- props.strokeColor || (strokeWidth ? 'gray' : 'transparent');
89
- const innerRadius = props.innerRadius || radius / 2.5;
90
- const innerCircleColor =
91
- props.innerCircleColor || props.backgroundColor || 'white';
92
- const innerCircleBorderWidth =
93
- props.innerCircleBorderWidth ||
94
- (props.innerCircleBorderColor ? strokeWidth || 2 : 0);
95
- const innerCircleBorderColor = props.innerCircleBorderColor || 'lightgray';
96
- const shiftInnerCenterX = props.shiftInnerCenterX || 0;
97
- const shiftInnerCenterY = props.shiftInnerCenterY || 0;
98
-
99
- const showText = props.showText || false;
100
- const textColor = props.textColor || '';
101
- const textSize = props.textSize ? Math.min(props.textSize, radius / 5) : 16;
102
- let tiltAngle = props.tiltAngle || '55deg';
103
- if (
104
- tiltAngle &&
105
- !isNaN(Number(tiltAngle)) &&
106
- !(tiltAngle + '').endsWith('deg')
107
- ) {
108
- tiltAngle += 'deg';
109
- }
110
- // const tilt = props.tilt ? Math.min(props.tilt, 1) : props.isThreeD ? 0.5 : 1;
111
- const labelsPosition = props.labelsPosition
112
- ? props.labelsPosition
113
- : donut || props.centerLabelComponent
114
- ? 'outward'
115
- : 'mid';
116
-
117
- const showTextBackground = props.showTextBackground || false;
118
- const textBackgroundColor = props.textBackgroundColor || 'white';
119
- const showValuesAsLabels = props.showValuesAsLabels || false;
120
- const showGradient = props.showGradient || false;
121
- const gradientCenterColor = props.gradientCenterColor || 'white';
122
-
123
- const colors = [
124
- 'cyan',
125
- 'green',
126
- 'orange',
127
- 'purple',
128
- 'yellow',
129
- 'red',
130
- 'blue',
131
- 'pink',
132
- ];
133
- let isDataShifted = false;
134
- let minShiftX = 0,
135
- maxShiftX = 0,
136
- minShiftY = 0,
137
- maxShiftY = 0;
138
- data.forEach((item: any) => {
139
- total += item.value;
140
- if (item.shiftX || item.shiftY) {
141
- isDataShifted = true;
142
- if (minShiftX > item.shiftX) {
143
- minShiftX = item.shiftX;
144
- }
145
- if (minShiftY > item.shiftY) {
146
- minShiftY = item.shiftY;
147
- }
148
- if (maxShiftX < item.shiftX) {
149
- maxShiftX = item.shiftX;
150
- }
151
- if (maxShiftY < item.shiftY) {
152
- maxShiftY = item.shiftY;
74
+ const extraRadiusForFocused = props.extraRadiusForFocused || radius / 10;
75
+ const pi = props.semiCircle ? Math.PI / 2 : Math.PI;
76
+ const [selectedIndex, setSelectedIndex] = useState(-1);
77
+
78
+ if (props.data.length <= 1 || !props.focusOnPress || selectedIndex === -1) {
79
+ return (
80
+ <PieChartMain
81
+ {...props}
82
+ key="pie"
83
+ setSelectedIndex={setSelectedIndex}
84
+ selectedIndex={selectedIndex}
85
+ />
86
+ );
87
+ } else {
88
+ let startAngle = props.initialAngle || (props.semiCircle ? -pi : 0);
89
+ // let startColor;
90
+ let total = 0;
91
+ props.data.forEach(item => {
92
+ total += item.value;
93
+ });
94
+ if (selectedIndex !== 0) {
95
+ let start = 0;
96
+ for (let i = 0; i < selectedIndex; i++) {
97
+ start += props.data[i].value;
153
98
  }
99
+ startAngle += (2 * pi * start) / total;
154
100
  }
155
- });
156
-
157
- const horizAdjustment = maxShiftX - minShiftX;
158
- const vertAdjustment = maxShiftY - minShiftY;
159
-
160
- if (semiCircle) {
161
- pi = Math.PI / 2;
162
- }
163
-
164
- let cx = radius,
165
- cy = radius;
166
-
167
- let total =
168
- data && data.length
169
- ? data.map(item => item.value).reduce((v, a) => v + a)
170
- : 0;
171
- let acc = 0;
172
- let pData = data.map(item => {
173
- acc += item.value / total;
174
- return acc;
175
- });
176
- acc = 0;
177
- let mData = data.map(item => {
178
- let pAcc = acc;
179
- acc += item.value / total;
180
- return pAcc + (acc - pAcc) / 2;
181
- });
182
- pData = [0, ...pData];
183
-
184
- return (
185
- <View
186
- style={[
187
- {
188
- backgroundColor: backgroundColor,
189
- height: semiCircle ? canvasHeight / 2 : canvasHeight,
190
- width: canvasWidth,
191
- overflow: 'hidden',
192
- },
193
- isThreeD && {transform: [{rotateX: tiltAngle}]},
194
- ]}>
195
- <Svg
196
- viewBox={`${strokeWidth / -2 + minShiftX} ${
197
- strokeWidth / -2 + minShiftY
198
- } ${
199
- (radius + strokeWidth) * 2 +
200
- horizAdjustment +
201
- (horizAdjustment ? strokeWidth : 0)
202
- } ${
203
- (radius + strokeWidth) * 2 +
204
- +vertAdjustment +
205
- (vertAdjustment ? strokeWidth : 0)
206
- }`}
207
- height={radius * 2 + strokeWidth}
208
- width={radius * 2 + strokeWidth}>
209
- <Defs>
210
- {data.map((item, index) => {
211
- return (
212
- <RadialGradient
213
- key={index + ''}
214
- id={'grad' + index}
215
- cx="50%"
216
- cy="50%"
217
- rx="50%"
218
- ry="50%"
219
- fx="50%"
220
- fy="50%"
221
- gradientUnits="userSpaceOnUse">
222
- <Stop
223
- offset="0%"
224
- stopColor={item.gradientCenterColor || gradientCenterColor}
225
- stopOpacity="1"
226
- />
227
- <Stop
228
- offset="100%"
229
- stopColor={item.color || colors[index % 9]}
230
- stopOpacity="1"
231
- />
232
- </RadialGradient>
233
- );
234
- })}
235
- </Defs>
236
- {data.length === 1 ? (
237
- <>
238
- <Circle
239
- cx={cx}
240
- cy={cy}
241
- r={radius}
242
- fill={
243
- showGradient ? `url(#grad${0})` : data[0].color || colors[0 % 9]
244
- }
245
- onPress={() => {
246
- data[0].onPress
247
- ? data[0].onPress
248
- : props.onPress
249
- ? props.onPress(data[0], 0)
250
- : null;
251
- }}
252
- />
253
- </>
254
- ) : (
255
- data.map((item, index) => {
256
- // console.log('index', index);
257
- let nextItem;
258
- if (index === pData.length - 1) nextItem = pData[0];
259
- else nextItem = pData[index + 1];
260
- let sx =
261
- cx * (1 + Math.sin(2 * pi * pData[index] + initialAngle)) +
262
- (item.shiftX || 0);
263
- let sy =
264
- cy * (1 - Math.cos(2 * pi * pData[index] + initialAngle)) +
265
- (item.shiftY || 0);
266
- let ax =
267
- cx * (1 + Math.sin(2 * pi * nextItem + initialAngle)) +
268
- (item.shiftX || 0);
269
- let ay =
270
- cy * (1 - Math.cos(2 * pi * nextItem + initialAngle)) +
271
- (item.shiftY || 0);
272
-
273
- // console.log('sx', sx);
274
- // console.log('sy', sy);
275
- // console.log('ax', ax);
276
- // console.log('ay', ay);
277
- return (
278
- <Path
279
- key={index + 'a'}
280
- d={`M ${cx + (item.shiftX || 0)} ${
281
- cy + (item.shiftY || 0)
282
- } L ${sx} ${sy} A ${radius} ${radius} 0 ${
283
- semiCircle ? 0 : data[index].value > total / 2 ? 1 : 0
284
- } 1 ${ax} ${ay} L ${cx + (item.shiftX || 0)} ${
285
- cy + (item.shiftY || 0)
286
- }`}
287
- stroke={strokeColor}
288
- strokeWidth={strokeWidth}
289
- fill={
290
- showGradient
291
- ? `url(#grad${index})`
292
- : item.color || colors[index % 9]
293
- }
294
- onPress={() => {
295
- item.onPress
296
- ? item.onPress
297
- : props.onPress
298
- ? props.onPress(item, index)
299
- : null;
300
- }}
301
- />
302
- );
303
- })
304
- )}
305
-
306
- {showText &&
307
- data.map((item, index) => {
308
- let mx = cx * (1 + Math.sin(2 * pi * mData[index] + initialAngle));
309
- let my = cy * (1 - Math.cos(2 * pi * mData[index] + initialAngle));
310
-
311
- let midx = (mx + cx) / 2;
312
- let midy = (my + cy) / 2;
313
-
314
- let x = midx,
315
- y = midy;
316
-
317
- const labelPosition = item.labelPosition || labelsPosition;
318
-
319
- if (labelPosition === 'onBorder') {
320
- x = mx;
321
- y = my;
322
- } else if (labelPosition === 'outward') {
323
- x = (midx + mx) / 2;
324
- y = (midy + my) / 2;
325
- } else if (labelPosition === 'inward') {
326
- x = (midx + cx) / 2;
327
- y = (midy + cy) / 2;
328
- }
329
-
330
- x += item.shiftX || 0;
331
- y += item.shiftY || 0;
332
-
333
- if (data.length === 1) {
334
- if (donut) {
335
- y =
336
- (radius -
337
- innerRadius +
338
- (item.textBackgroundRadius ||
339
- props.textBackgroundRadius ||
340
- item.textSize ||
341
- textSize)) /
342
- 2;
343
- } else {
344
- y = cy;
345
- }
346
- }
347
-
348
- // console.log('sx', sx);
349
- // console.log('sy', sy);
350
- // console.log('ax', ax);
351
- // console.log('ay', ay);
352
- return (
353
- <>
354
- {/* <Line x1={mx} x2={cx} y1={my} y2={cy} stroke="black" /> */}
355
- {showTextBackground && (
356
- <Circle
357
- key={index + 'b'}
358
- cx={x}
359
- cy={y - (item.textSize || textSize) / 4}
360
- r={
361
- item.textBackgroundRadius ||
362
- props.textBackgroundRadius ||
363
- item.textSize ||
364
- textSize
365
- }
366
- fill={item.textBackgroundColor || textBackgroundColor}
367
- onPress={() => {
368
- item.onLabelPress
369
- ? item.onLabelPress()
370
- : props.onLabelPress
371
- ? props.onLabelPress(item, index)
372
- : item.onPress
373
- ? item.onPress()
374
- : props.onPress
375
- ? props.onPress(item, index)
376
- : null;
377
- }}
378
- />
379
- )}
380
- <SvgText
381
- fill={item.textColor || textColor || colors[(index + 2) % 9]}
382
- fontSize={item.textSize || textSize}
383
- fontFamily={item.font || props.font}
384
- fontWeight={item.fontWeight || props.fontWeight}
385
- fontStyle={item.fontStyle || props.fontStyle || 'normal'}
386
- x={
387
- x +
388
- (item.shiftTextX || 0) -
389
- (item.textSize || textSize) / 1.8
390
- }
391
- y={y + (item.shiftTextY || 0)}
392
- onPress={() => {
393
- item.onLabelPress
394
- ? item.onLabelPress()
395
- : props.onLabelPress
396
- ? props.onLabelPress(item, index)
397
- : item.onPress
398
- ? item.onPress()
399
- : props.onPress
400
- ? props.onPress(item, index)
401
- : null;
402
- }}>
403
- {item.text || (showValuesAsLabels ? item.value + '' : '')}
404
- </SvgText>
405
- </>
406
- );
407
- })}
408
- </Svg>
409
- {(props.centerLabelComponent || (donut && !isDataShifted)) && (
410
- <View
411
- style={[
412
- {
413
- height: innerRadius * 2,
414
- width: innerRadius * 2,
415
- borderRadius: innerRadius,
416
- position: 'absolute',
417
- zIndex: 100,
418
- alignSelf: 'center',
419
- backgroundColor: innerCircleColor,
420
- left: canvasWidth / 2 - innerRadius + shiftInnerCenterX,
421
- top:
422
- canvasHeight / 2 -
423
- innerRadius +
424
- shiftInnerCenterY -
425
- (isThreeD ? radius / 5 : 0),
426
- borderWidth: innerCircleBorderWidth,
427
- borderColor: innerCircleBorderColor,
428
- justifyContent: 'center',
429
- alignItems: 'center',
430
- },
431
- isThreeD && {
432
- borderTopWidth: innerCircleBorderWidth * 5,
433
- borderLeftWidth: shiftInnerCenterX
434
- ? innerCircleBorderWidth * 2
435
- : innerCircleBorderWidth,
436
- },
437
- semiCircle &&
438
- isThreeD && {
439
- borderTopWidth: isThreeD
440
- ? innerCircleBorderWidth * 5
441
- : innerCircleBorderWidth,
442
- borderLeftWidth: 0.5,
443
- borderLeftColor: innerCircleColor,
444
- borderBottomWidth: 0,
445
- borderRightWidth: 0.5,
446
- borderRightColor: innerCircleColor,
447
- },
448
- ]}>
449
- <View style={{marginTop: semiCircle ? -0.5 * innerRadius : 0}}>
450
- {props.centerLabelComponent ? props.centerLabelComponent() : null}
451
- </View>
452
- </View>
453
- )}
454
- {isThreeD && shadow && !semiCircle ? (
101
+ return (
102
+ <View>
455
103
  <View
456
104
  style={{
457
- width: radius * 2,
458
- height: radius * 2,
459
- backgroundColor: shadowColor,
460
- borderRadius: radius,
461
105
  position: 'absolute',
462
- top: shadowWidth,
463
- zIndex: -1,
464
- }}
465
- />
466
- ) : null}
467
- </View>
468
- );
106
+ top: -extraRadiusForFocused,
107
+ left: -extraRadiusForFocused,
108
+ }}>
109
+ <PieChartMain
110
+ {...props}
111
+ data={[
112
+ {
113
+ value: props.data[selectedIndex].value,
114
+ color:
115
+ props.data[selectedIndex].color || colors[selectedIndex % 9],
116
+ },
117
+ {
118
+ value: total - props.data[selectedIndex].value,
119
+ color: 'transparent',
120
+ },
121
+ ]}
122
+ key="pie"
123
+ radius={radius + extraRadiusForFocused}
124
+ initialAngle={startAngle}
125
+ />
126
+ </View>
127
+ <View style={{position: 'absolute'}}>
128
+ <PieChartMain
129
+ {...props}
130
+ key="pie"
131
+ selectedIndex={selectedIndex}
132
+ setSelectedIndex={setSelectedIndex}
133
+ />
134
+ </View>
135
+ </View>
136
+ );
137
+ }
469
138
  };
@@ -0,0 +1,492 @@
1
+ import React from 'react';
2
+ import {ColorValue, View} from 'react-native';
3
+ import Svg, {
4
+ Path,
5
+ Circle,
6
+ Text as SvgText,
7
+ FontStyle,
8
+ Defs,
9
+ RadialGradient,
10
+ Stop,
11
+ } from 'react-native-svg';
12
+ import {colors} from './colors';
13
+
14
+ type propTypes = {
15
+ radius?: number;
16
+ isThreeD?: Boolean;
17
+ donut?: Boolean;
18
+ innerRadius?: number;
19
+ shadow?: Boolean;
20
+ innerCircleColor?: ColorValue;
21
+ innerCircleBorderWidth?: number;
22
+ innerCircleBorderColor?: ColorValue;
23
+ shiftInnerCenterX?: number;
24
+ shiftInnerCenterY?: number;
25
+ shadowColor?: string;
26
+ shadowWidth?: number;
27
+ strokeWidth?: number;
28
+ strokeColor?: string;
29
+ backgroundColor?: string;
30
+ data: Array<itemType>;
31
+ semiCircle?: Boolean;
32
+
33
+ showText?: Boolean;
34
+ textColor?: string;
35
+ textSize?: number;
36
+ fontStyle?: FontStyle;
37
+ fontWeight?: string;
38
+ font?: string;
39
+ showTextBackground?: Boolean;
40
+ textBackgroundColor?: string;
41
+ textBackgroundRadius?: number;
42
+ showValuesAsLabels?: Boolean;
43
+
44
+ centerLabelComponent?: Function;
45
+ tiltAngle?: string;
46
+ initialAngle?: number;
47
+ labelsPosition?: 'onBorder' | 'outward' | 'inward' | 'mid';
48
+ showGradient?: boolean;
49
+ gradientCenterColor?: string;
50
+ onPress?: Function;
51
+ focusOnPress?: Boolean;
52
+ toggleFocusOnPress?: Boolean;
53
+ selectedIndex?: number;
54
+ setSelectedIndex?: Function;
55
+ onLabelPress?: Function;
56
+ };
57
+ type itemType = {
58
+ value: number;
59
+ shiftX?: number;
60
+ shiftY?: number;
61
+ color?: string;
62
+ gradientCenterColor?: string;
63
+ text?: string;
64
+ textColor?: string;
65
+ textSize?: number;
66
+ fontStyle?: FontStyle;
67
+ fontWeight?: string;
68
+ font?: string;
69
+ textBackgroundColor?: string;
70
+ textBackgroundRadius?: number;
71
+ shiftTextX?: number;
72
+ shiftTextY?: number;
73
+ labelPosition?: 'onBorder' | 'outward' | 'inward' | 'mid';
74
+ onPress?: Function;
75
+ onLabelPress?: Function;
76
+ };
77
+
78
+ export const PieChartMain = (props: propTypes) => {
79
+ const {data, isThreeD} = props;
80
+ const radius = props.radius || 120;
81
+ const canvasWidth = radius * 2;
82
+ const canvasHeight = isThreeD ? radius * 2.3 : radius * 2;
83
+ const shadowWidth = props.shadowWidth || radius / 5;
84
+ const backgroundColor = props.backgroundColor || 'transparent';
85
+ const shadowColor = props.shadowColor || 'lightgray';
86
+ const semiCircle = props.semiCircle || false;
87
+ let pi = Math.PI;
88
+ const initialAngle = props.initialAngle || (semiCircle ? pi / -2 : 0);
89
+ const shadow = props.shadow || false;
90
+ const donut = props.donut || false;
91
+ const strokeWidth = props.strokeWidth || 0;
92
+ const strokeColor =
93
+ props.strokeColor || (strokeWidth ? 'gray' : 'transparent');
94
+ const innerRadius = props.innerRadius || radius / 2.5;
95
+ const innerCircleColor =
96
+ props.innerCircleColor || props.backgroundColor || 'white';
97
+ const innerCircleBorderWidth =
98
+ props.innerCircleBorderWidth ||
99
+ (props.innerCircleBorderColor ? strokeWidth || 2 : 0);
100
+ const innerCircleBorderColor = props.innerCircleBorderColor || 'lightgray';
101
+ const shiftInnerCenterX = props.shiftInnerCenterX || 0;
102
+ const shiftInnerCenterY = props.shiftInnerCenterY || 0;
103
+
104
+ const showText = props.showText || false;
105
+ const textColor = props.textColor || '';
106
+ const textSize = props.textSize ? Math.min(props.textSize, radius / 5) : 16;
107
+ let tiltAngle = props.tiltAngle || '55deg';
108
+ if (
109
+ tiltAngle &&
110
+ !isNaN(Number(tiltAngle)) &&
111
+ !(tiltAngle + '').endsWith('deg')
112
+ ) {
113
+ tiltAngle += 'deg';
114
+ }
115
+ // const tilt = props.tilt ? Math.min(props.tilt, 1) : props.isThreeD ? 0.5 : 1;
116
+ const labelsPosition = props.labelsPosition
117
+ ? props.labelsPosition
118
+ : donut || props.centerLabelComponent
119
+ ? 'outward'
120
+ : 'mid';
121
+
122
+ const showTextBackground = props.showTextBackground || false;
123
+ const textBackgroundColor = props.textBackgroundColor || 'white';
124
+ const showValuesAsLabels = props.showValuesAsLabels || false;
125
+ const showGradient = props.showGradient || false;
126
+ const gradientCenterColor = props.gradientCenterColor || 'white';
127
+ const toggleFocusOnPress = props.toggleFocusOnPress === false ? false : true;
128
+
129
+ let isDataShifted = false;
130
+ let minShiftX = 0,
131
+ maxShiftX = 0,
132
+ minShiftY = 0,
133
+ maxShiftY = 0;
134
+ data.forEach((item: any) => {
135
+ total += item.value;
136
+ if (item.shiftX || item.shiftY) {
137
+ isDataShifted = true;
138
+ if (minShiftX > item.shiftX) {
139
+ minShiftX = item.shiftX;
140
+ }
141
+ if (minShiftY > item.shiftY) {
142
+ minShiftY = item.shiftY;
143
+ }
144
+ if (maxShiftX < item.shiftX) {
145
+ maxShiftX = item.shiftX;
146
+ }
147
+ if (maxShiftY < item.shiftY) {
148
+ maxShiftY = item.shiftY;
149
+ }
150
+ }
151
+ });
152
+
153
+ const horizAdjustment = maxShiftX - minShiftX;
154
+ const vertAdjustment = maxShiftY - minShiftY;
155
+
156
+ if (semiCircle) {
157
+ pi = Math.PI / 2;
158
+ }
159
+
160
+ let cx = radius,
161
+ cy = radius;
162
+
163
+ let total =
164
+ data && data.length
165
+ ? data.map(item => item.value).reduce((v, a) => v + a)
166
+ : 0;
167
+ let acc = 0;
168
+ let pData = data.map(item => {
169
+ acc += item.value / total;
170
+ return acc;
171
+ });
172
+ acc = 0;
173
+ let mData = data.map(item => {
174
+ let pAcc = acc;
175
+ acc += item.value / total;
176
+ return pAcc + (acc - pAcc) / 2;
177
+ });
178
+ pData = [0, ...pData];
179
+
180
+ return (
181
+ <View
182
+ style={[
183
+ {
184
+ backgroundColor: backgroundColor,
185
+ height: semiCircle ? canvasHeight / 2 : canvasHeight,
186
+ width: canvasWidth,
187
+ overflow: 'hidden',
188
+ },
189
+ isThreeD && {transform: [{rotateX: tiltAngle}]},
190
+ ]}>
191
+ <Svg
192
+ viewBox={`${strokeWidth / -2 + minShiftX} ${
193
+ strokeWidth / -2 + minShiftY
194
+ } ${
195
+ (radius + strokeWidth) * 2 +
196
+ horizAdjustment +
197
+ (horizAdjustment ? strokeWidth : 0)
198
+ } ${
199
+ (radius + strokeWidth) * 2 +
200
+ +vertAdjustment +
201
+ (vertAdjustment ? strokeWidth : 0)
202
+ }`}
203
+ height={radius * 2 + strokeWidth}
204
+ width={radius * 2 + strokeWidth}>
205
+ <Defs>
206
+ {data.map((item, index) => {
207
+ return (
208
+ <RadialGradient
209
+ key={index + ''}
210
+ id={'grad' + index}
211
+ cx="50%"
212
+ cy="50%"
213
+ rx="50%"
214
+ ry="50%"
215
+ fx="50%"
216
+ fy="50%"
217
+ gradientUnits="userSpaceOnUse">
218
+ <Stop
219
+ offset="0%"
220
+ stopColor={item.gradientCenterColor || gradientCenterColor}
221
+ stopOpacity="1"
222
+ />
223
+ <Stop
224
+ offset="100%"
225
+ stopColor={item.color || colors[index % 9]}
226
+ stopOpacity="1"
227
+ />
228
+ </RadialGradient>
229
+ );
230
+ })}
231
+ </Defs>
232
+ {data.length === 1 ? (
233
+ <>
234
+ <Circle
235
+ cx={cx}
236
+ cy={cy}
237
+ r={radius}
238
+ fill={
239
+ showGradient ? `url(#grad${0})` : data[0].color || colors[0 % 9]
240
+ }
241
+ onPress={() => {
242
+ data[0].onPress
243
+ ? data[0].onPress()
244
+ : props.onPress
245
+ ? props.onPress(data[0], 0)
246
+ : null;
247
+ }}
248
+ />
249
+ </>
250
+ ) : (
251
+ data.map((item, index) => {
252
+ // console.log('index', index);
253
+ let nextItem;
254
+ if (index === pData.length - 1) nextItem = pData[0];
255
+ else nextItem = pData[index + 1];
256
+ let sx =
257
+ cx * (1 + Math.sin(2 * pi * pData[index] + initialAngle)) +
258
+ (item.shiftX || 0);
259
+ let sy =
260
+ cy * (1 - Math.cos(2 * pi * pData[index] + initialAngle)) +
261
+ (item.shiftY || 0);
262
+ let ax =
263
+ cx * (1 + Math.sin(2 * pi * nextItem + initialAngle)) +
264
+ (item.shiftX || 0);
265
+ let ay =
266
+ cy * (1 - Math.cos(2 * pi * nextItem + initialAngle)) +
267
+ (item.shiftY || 0);
268
+
269
+ // console.log('sx', sx);
270
+ // console.log('sy', sy);
271
+ // console.log('ax', ax);
272
+ // console.log('ay', ay);
273
+ return (
274
+ <Path
275
+ key={index + 'a'}
276
+ d={`M ${cx + (item.shiftX || 0)} ${
277
+ cy + (item.shiftY || 0)
278
+ } L ${sx} ${sy} A ${radius} ${radius} 0 ${
279
+ semiCircle ? 0 : data[index].value > total / 2 ? 1 : 0
280
+ } 1 ${ax} ${ay} L ${cx + (item.shiftX || 0)} ${
281
+ cy + (item.shiftY || 0)
282
+ }`}
283
+ stroke={strokeColor}
284
+ strokeWidth={strokeWidth}
285
+ fill={
286
+ showGradient
287
+ ? `url(#grad${index})`
288
+ : item.color || colors[index % 9]
289
+ }
290
+ onPress={() => {
291
+ if (item.onPress) {
292
+ item.onPress();
293
+ } else if (props.onPress) {
294
+ props.onPress(item, index);
295
+ }
296
+ if (props.focusOnPress) {
297
+ if (props.selectedIndex === index) {
298
+ if (toggleFocusOnPress) {
299
+ props.setSelectedIndex(-1);
300
+ }
301
+ } else {
302
+ props.setSelectedIndex(index);
303
+ }
304
+ }
305
+ }}
306
+ />
307
+ );
308
+ })
309
+ )}
310
+
311
+ {showText &&
312
+ data.map((item, index) => {
313
+ let mx = cx * (1 + Math.sin(2 * pi * mData[index] + initialAngle));
314
+ let my = cy * (1 - Math.cos(2 * pi * mData[index] + initialAngle));
315
+
316
+ let midx = (mx + cx) / 2;
317
+ let midy = (my + cy) / 2;
318
+
319
+ let x = midx,
320
+ y = midy;
321
+
322
+ const labelPosition = item.labelPosition || labelsPosition;
323
+
324
+ if (labelPosition === 'onBorder') {
325
+ x = mx;
326
+ y = my;
327
+ } else if (labelPosition === 'outward') {
328
+ x = (midx + mx) / 2;
329
+ y = (midy + my) / 2;
330
+ } else if (labelPosition === 'inward') {
331
+ x = (midx + cx) / 2;
332
+ y = (midy + cy) / 2;
333
+ }
334
+
335
+ x += item.shiftX || 0;
336
+ y += item.shiftY || 0;
337
+
338
+ if (data.length === 1) {
339
+ if (donut) {
340
+ y =
341
+ (radius -
342
+ innerRadius +
343
+ (item.textBackgroundRadius ||
344
+ props.textBackgroundRadius ||
345
+ item.textSize ||
346
+ textSize)) /
347
+ 2;
348
+ } else {
349
+ y = cy;
350
+ }
351
+ }
352
+
353
+ // console.log('sx', sx);
354
+ // console.log('sy', sy);
355
+ // console.log('ax', ax);
356
+ // console.log('ay', ay);
357
+ return (
358
+ <>
359
+ {/* <Line x1={mx} x2={cx} y1={my} y2={cy} stroke="black" /> */}
360
+ {showTextBackground && (
361
+ <Circle
362
+ key={index + 'b'}
363
+ cx={x}
364
+ cy={y - (item.textSize || textSize) / 4}
365
+ r={
366
+ item.textBackgroundRadius ||
367
+ props.textBackgroundRadius ||
368
+ item.textSize ||
369
+ textSize
370
+ }
371
+ fill={item.textBackgroundColor || textBackgroundColor}
372
+ onPress={() => {
373
+ item.onLabelPress
374
+ ? item.onLabelPress()
375
+ : props.onLabelPress
376
+ ? props.onLabelPress(item, index)
377
+ : item.onPress
378
+ ? item.onPress()
379
+ : props.onPress
380
+ ? props.onPress(item, index)
381
+ : null;
382
+ if (props.focusOnPress) {
383
+ if (props.selectedIndex === index) {
384
+ if (toggleFocusOnPress) {
385
+ props.setSelectedIndex(-1);
386
+ }
387
+ } else {
388
+ props.setSelectedIndex(index);
389
+ }
390
+ }
391
+ }}
392
+ />
393
+ )}
394
+ <SvgText
395
+ fill={item.textColor || textColor || colors[(index + 2) % 9]}
396
+ fontSize={item.textSize || textSize}
397
+ fontFamily={item.font || props.font}
398
+ fontWeight={item.fontWeight || props.fontWeight}
399
+ fontStyle={item.fontStyle || props.fontStyle || 'normal'}
400
+ x={
401
+ x +
402
+ (item.shiftTextX || 0) -
403
+ (item.textSize || textSize) / 1.8
404
+ }
405
+ y={y + (item.shiftTextY || 0)}
406
+ onPress={() => {
407
+ item.onLabelPress
408
+ ? item.onLabelPress()
409
+ : props.onLabelPress
410
+ ? props.onLabelPress(item, index)
411
+ : item.onPress
412
+ ? item.onPress()
413
+ : props.onPress
414
+ ? props.onPress(item, index)
415
+ : null;
416
+ if (props.focusOnPress) {
417
+ if (props.selectedIndex === index) {
418
+ if (toggleFocusOnPress) {
419
+ props.setSelectedIndex(-1);
420
+ }
421
+ } else {
422
+ props.setSelectedIndex(index);
423
+ }
424
+ }
425
+ }}>
426
+ {item.text || (showValuesAsLabels ? item.value + '' : '')}
427
+ </SvgText>
428
+ </>
429
+ );
430
+ })}
431
+ </Svg>
432
+ {(props.centerLabelComponent || (donut && !isDataShifted)) && (
433
+ <View
434
+ style={[
435
+ {
436
+ height: innerRadius * 2,
437
+ width: innerRadius * 2,
438
+ borderRadius: innerRadius,
439
+ position: 'absolute',
440
+ zIndex: 100,
441
+ alignSelf: 'center',
442
+ backgroundColor: innerCircleColor,
443
+ left: canvasWidth / 2 - innerRadius + shiftInnerCenterX,
444
+ top:
445
+ canvasHeight / 2 -
446
+ innerRadius +
447
+ shiftInnerCenterY -
448
+ (isThreeD ? radius / 5 : 0),
449
+ borderWidth: innerCircleBorderWidth,
450
+ borderColor: innerCircleBorderColor,
451
+ justifyContent: 'center',
452
+ alignItems: 'center',
453
+ },
454
+ isThreeD && {
455
+ borderTopWidth: innerCircleBorderWidth * 5,
456
+ borderLeftWidth: shiftInnerCenterX
457
+ ? innerCircleBorderWidth * 2
458
+ : innerCircleBorderWidth,
459
+ },
460
+ semiCircle &&
461
+ isThreeD && {
462
+ borderTopWidth: isThreeD
463
+ ? innerCircleBorderWidth * 5
464
+ : innerCircleBorderWidth,
465
+ borderLeftWidth: 0.5,
466
+ borderLeftColor: innerCircleColor,
467
+ borderBottomWidth: 0,
468
+ borderRightWidth: 0.5,
469
+ borderRightColor: innerCircleColor,
470
+ },
471
+ ]}>
472
+ <View style={{marginTop: semiCircle ? -0.5 * innerRadius : 0}}>
473
+ {props.centerLabelComponent ? props.centerLabelComponent() : null}
474
+ </View>
475
+ </View>
476
+ )}
477
+ {isThreeD && shadow && !semiCircle ? (
478
+ <View
479
+ style={{
480
+ width: radius * 2,
481
+ height: radius * 2,
482
+ backgroundColor: shadowColor,
483
+ borderRadius: radius,
484
+ position: 'absolute',
485
+ top: shadowWidth,
486
+ zIndex: -1,
487
+ }}
488
+ />
489
+ ) : null}
490
+ </View>
491
+ );
492
+ };
package/src/todos.md CHANGED
@@ -15,6 +15,9 @@
15
15
  9. Prepare a doc for labelsPosition in Pie and Donut charts
16
16
  8. Prepare a doc for adjustToWidth in Line and Area charts
17
17
  9. Prepare a doc for xAxisLabelTexts and xAxisLabelTextStyle in Bar, Line And Area Charts
18
+ 10. Prepare a doc for vertical lines to explain noOfVerticalLines and verticalLinesSpacing props. https://github.com/Abhinandan-Kushwaha/react-native-gifted-charts/issues/205
19
+ 11. Prepare a doc for negative marginBottom instead of marginTop for x axis labels. https://github.com/Abhinandan-Kushwaha/react-native-gifted-charts/issues/190
20
+
18
21
 
19
22
  ## Architecture Enhancement
20
23