gifted-charts-core 0.0.9 → 0.0.11
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 +1 -1
- package/src/BarChart/Animated2DWithGradient.ts +13 -13
- package/src/BarChart/types.ts +23 -18
- package/src/LineChart/index.ts +76 -20
- package/src/LineChart/types.ts +4 -0
- package/src/components/BarAndLineChartsWrapper/index.ts +6 -2
- package/src/utils/constants.ts +3 -1
- package/src/utils/index.tsx +180 -7
- package/src/utils/types.ts +2 -1
package/package.json
CHANGED
|
@@ -34,10 +34,15 @@ export const getPropsForAnimated2DWithGradient = (props) => {
|
|
|
34
34
|
selectedIndex,
|
|
35
35
|
focusBarOnPress,
|
|
36
36
|
focusedBarConfig,
|
|
37
|
+
isThreeD,
|
|
37
38
|
} = props;
|
|
38
39
|
|
|
39
40
|
const isFocused = focusBarOnPress && selectedIndex === index;
|
|
40
|
-
const
|
|
41
|
+
const itemOrPropsBarBorderRadius =
|
|
42
|
+
item.barBorderRadius ?? barBorderRadius ?? 0;
|
|
43
|
+
const localBarBorderRadius = isFocused
|
|
44
|
+
? focusedBarConfig?.borderRadius ?? itemOrPropsBarBorderRadius
|
|
45
|
+
: itemOrPropsBarBorderRadius;
|
|
41
46
|
const localBarWidth = getBarWidth(
|
|
42
47
|
isFocused,
|
|
43
48
|
focusedBarConfig,
|
|
@@ -48,7 +53,8 @@ export const getPropsForAnimated2DWithGradient = (props) => {
|
|
|
48
53
|
isFocused,
|
|
49
54
|
focusedBarConfig,
|
|
50
55
|
item.frontColor,
|
|
51
|
-
frontColor
|
|
56
|
+
frontColor,
|
|
57
|
+
isThreeD,
|
|
52
58
|
);
|
|
53
59
|
const localGradientColor = item.gradientColor || gradientColor;
|
|
54
60
|
const localOpacity = opacity || 1;
|
|
@@ -60,29 +66,23 @@ export const getPropsForAnimated2DWithGradient = (props) => {
|
|
|
60
66
|
height: "100%",
|
|
61
67
|
borderWidth: barBorderWidth ?? 0,
|
|
62
68
|
borderColor: barBorderColor,
|
|
63
|
-
borderRadius:
|
|
64
|
-
? focusedBarConfig?.borderRadius ?? localBarBorderRadius
|
|
65
|
-
: localBarBorderRadius,
|
|
69
|
+
borderRadius: localBarBorderRadius,
|
|
66
70
|
borderTopLeftRadius:
|
|
67
71
|
item.barBorderTopLeftRadius ??
|
|
68
72
|
barBorderTopLeftRadius ??
|
|
69
|
-
|
|
70
|
-
barBorderRadius,
|
|
73
|
+
localBarBorderRadius,
|
|
71
74
|
borderTopRightRadius:
|
|
72
75
|
item.barBorderTopRightRadius ??
|
|
73
76
|
barBorderTopRightRadius ??
|
|
74
|
-
|
|
75
|
-
barBorderRadius,
|
|
77
|
+
localBarBorderRadius,
|
|
76
78
|
borderBottomLeftRadius:
|
|
77
79
|
item.barBorderBottomLeftRadius ??
|
|
78
80
|
barBorderBottomLeftRadius ??
|
|
79
|
-
|
|
80
|
-
barBorderRadius,
|
|
81
|
+
localBarBorderRadius,
|
|
81
82
|
borderBottomRightRadius:
|
|
82
83
|
item.barBorderBottomRightRadius ??
|
|
83
84
|
barBorderBottomRightRadius ??
|
|
84
|
-
|
|
85
|
-
barBorderRadius,
|
|
85
|
+
localBarBorderRadius,
|
|
86
86
|
},
|
|
87
87
|
];
|
|
88
88
|
|
package/src/BarChart/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ColorValue, GestureResponderEvent } from "react-native";
|
|
1
|
+
import { ColorValue, GestureResponderEvent, ViewStyle } from "react-native";
|
|
2
2
|
import { yAxisSides } from "../utils/constants";
|
|
3
3
|
import {
|
|
4
4
|
CurveType,
|
|
@@ -305,6 +305,8 @@ export type BarChartPropsType = {
|
|
|
305
305
|
|
|
306
306
|
export type FocusedBarConfig = {
|
|
307
307
|
color?: ColorValue;
|
|
308
|
+
sideColor?: ColorValue;
|
|
309
|
+
topColor?: ColorValue;
|
|
308
310
|
gradientColor?: ColorValue;
|
|
309
311
|
width?: number;
|
|
310
312
|
borderRadius?: number;
|
|
@@ -312,7 +314,7 @@ export type FocusedBarConfig = {
|
|
|
312
314
|
roundedBottom?: boolean;
|
|
313
315
|
opacity?: number;
|
|
314
316
|
barInnerComponent?: (item?: barDataItem, index?: number) => ReactNode;
|
|
315
|
-
}
|
|
317
|
+
};
|
|
316
318
|
|
|
317
319
|
type lineConfigType = {
|
|
318
320
|
initialSpacing?: number;
|
|
@@ -460,6 +462,8 @@ export type Animated2DWithGradientPropsType = {
|
|
|
460
462
|
barMarginBottom?: number;
|
|
461
463
|
barStyle?: object;
|
|
462
464
|
barInnerComponent?: (item?: barDataItem, index?: number) => ReactNode;
|
|
465
|
+
commonStyleForBar?: ViewStyle[];
|
|
466
|
+
barStyleWithBackground?: ViewStyle[];
|
|
463
467
|
};
|
|
464
468
|
|
|
465
469
|
export type RenderBarsPropsType = {
|
|
@@ -540,6 +544,7 @@ export type RenderBarsPropsType = {
|
|
|
540
544
|
barStyle?: object;
|
|
541
545
|
xAxisThickness?: number;
|
|
542
546
|
pointerConfig?: Pointer;
|
|
547
|
+
focusBarOnPress?: boolean;
|
|
543
548
|
};
|
|
544
549
|
|
|
545
550
|
export type trianglePropTypes = {
|
|
@@ -579,20 +584,20 @@ export type animatedBarPropTypes = {
|
|
|
579
584
|
|
|
580
585
|
export type CommonPropsFor2Dand3DbarsType = {
|
|
581
586
|
barBackgroundPattern: Function;
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
587
|
+
barInnerComponent: (item?: barDataItem, index?: number) => ReactNode;
|
|
588
|
+
patternId: String;
|
|
589
|
+
barWidth: number;
|
|
590
|
+
barStyle: object;
|
|
591
|
+
item: barDataItem;
|
|
592
|
+
index: number;
|
|
588
593
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
}
|
|
594
|
+
frontColor: ColorValue;
|
|
595
|
+
showGradient: boolean;
|
|
596
|
+
gradientColor: ColorValue;
|
|
597
|
+
opacity: number;
|
|
598
|
+
height: number;
|
|
599
|
+
intactTopLabel: boolean;
|
|
600
|
+
showValuesAsTopLabel: boolean;
|
|
601
|
+
topLabelContainerStyle: any;
|
|
602
|
+
topLabelTextStyle: any;
|
|
603
|
+
};
|
package/src/LineChart/index.ts
CHANGED
|
@@ -17,6 +17,8 @@ import {
|
|
|
17
17
|
getAxesAndRulesProps,
|
|
18
18
|
getCurvePathWithSegments,
|
|
19
19
|
getExtendedContainerHeightWithPadding,
|
|
20
|
+
getInterpolatedData,
|
|
21
|
+
getLineSegmentsForMissingValues,
|
|
20
22
|
getMaxValue,
|
|
21
23
|
getNoOfSections,
|
|
22
24
|
getPathWithHighlight,
|
|
@@ -32,7 +34,12 @@ interface extendedLineChartPropsType extends LineChartPropsType {
|
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
export const useLineChart = (props: extendedLineChartPropsType) => {
|
|
35
|
-
const {
|
|
37
|
+
const {
|
|
38
|
+
animations,
|
|
39
|
+
showDataPointsForMissingValues,
|
|
40
|
+
interpolateMissingValues = true,
|
|
41
|
+
onlyPositive,
|
|
42
|
+
} = props;
|
|
36
43
|
const curvature = props.curvature ?? LineDefaults.curvature;
|
|
37
44
|
const curveType = props.curveType ?? LineDefaults.curveType;
|
|
38
45
|
const [scrollX, setScrollX] = useState(0);
|
|
@@ -110,70 +117,114 @@ export const useLineChart = (props: extendedLineChartPropsType) => {
|
|
|
110
117
|
if (!props.data) {
|
|
111
118
|
return [];
|
|
112
119
|
}
|
|
120
|
+
const nullishHandledData = getInterpolatedData(
|
|
121
|
+
props.data,
|
|
122
|
+
showDataPointsForMissingValues,
|
|
123
|
+
interpolateMissingValues,
|
|
124
|
+
onlyPositive
|
|
125
|
+
);
|
|
113
126
|
if (props.yAxisOffset) {
|
|
114
|
-
return
|
|
127
|
+
return nullishHandledData.map((item) => {
|
|
115
128
|
item.value = item.value - (props.yAxisOffset ?? 0);
|
|
116
129
|
return item;
|
|
117
130
|
});
|
|
118
131
|
}
|
|
119
|
-
return
|
|
132
|
+
return nullishHandledData;
|
|
120
133
|
}, [props.yAxisOffset, props.data]);
|
|
121
134
|
const data2 = useMemo(() => {
|
|
122
135
|
if (!props.data2) {
|
|
123
136
|
return [];
|
|
124
137
|
}
|
|
138
|
+
const nullishHandledData = getInterpolatedData(
|
|
139
|
+
props.data2,
|
|
140
|
+
showDataPointsForMissingValues,
|
|
141
|
+
interpolateMissingValues,
|
|
142
|
+
onlyPositive
|
|
143
|
+
);
|
|
125
144
|
if (props.yAxisOffset) {
|
|
126
|
-
return
|
|
145
|
+
return nullishHandledData.map((item) => {
|
|
127
146
|
item.value = item.value - (props.yAxisOffset ?? 0);
|
|
128
147
|
return item;
|
|
129
148
|
});
|
|
130
149
|
}
|
|
131
|
-
return
|
|
150
|
+
return nullishHandledData;
|
|
132
151
|
}, [props.yAxisOffset, props.data2]);
|
|
133
152
|
const data3 = useMemo(() => {
|
|
134
153
|
if (!props.data3) {
|
|
135
154
|
return [];
|
|
136
155
|
}
|
|
156
|
+
const nullishHandledData = getInterpolatedData(
|
|
157
|
+
props.data3,
|
|
158
|
+
showDataPointsForMissingValues,
|
|
159
|
+
interpolateMissingValues,
|
|
160
|
+
onlyPositive
|
|
161
|
+
);
|
|
137
162
|
if (props.yAxisOffset) {
|
|
138
|
-
return
|
|
163
|
+
return nullishHandledData.map((item) => {
|
|
139
164
|
item.value = item.value - (props.yAxisOffset ?? 0);
|
|
140
165
|
return item;
|
|
141
166
|
});
|
|
142
167
|
}
|
|
143
|
-
return
|
|
168
|
+
return nullishHandledData;
|
|
144
169
|
}, [props.yAxisOffset, props.data3]);
|
|
145
170
|
const data4 = useMemo(() => {
|
|
146
171
|
if (!props.data4) {
|
|
147
172
|
return [];
|
|
148
173
|
}
|
|
174
|
+
const nullishHandledData = getInterpolatedData(
|
|
175
|
+
props.data4,
|
|
176
|
+
showDataPointsForMissingValues,
|
|
177
|
+
interpolateMissingValues,
|
|
178
|
+
onlyPositive
|
|
179
|
+
);
|
|
149
180
|
if (props.yAxisOffset) {
|
|
150
|
-
return
|
|
181
|
+
return nullishHandledData.map((item) => {
|
|
151
182
|
item.value = item.value - (props.yAxisOffset ?? 0);
|
|
152
183
|
return item;
|
|
153
184
|
});
|
|
154
185
|
}
|
|
155
|
-
return
|
|
186
|
+
return nullishHandledData;
|
|
156
187
|
}, [props.yAxisOffset, props.data4]);
|
|
157
188
|
const data5 = useMemo(() => {
|
|
158
189
|
if (!props.data5) {
|
|
159
190
|
return [];
|
|
160
191
|
}
|
|
192
|
+
const nullishHandledData = getInterpolatedData(
|
|
193
|
+
props.data5,
|
|
194
|
+
showDataPointsForMissingValues,
|
|
195
|
+
interpolateMissingValues,
|
|
196
|
+
onlyPositive
|
|
197
|
+
);
|
|
161
198
|
if (props.yAxisOffset) {
|
|
162
|
-
return
|
|
199
|
+
return nullishHandledData.map((item) => {
|
|
163
200
|
item.value = item.value - (props.yAxisOffset ?? 0);
|
|
164
201
|
return item;
|
|
165
202
|
});
|
|
166
203
|
}
|
|
167
|
-
return
|
|
204
|
+
return nullishHandledData;
|
|
168
205
|
}, [props.yAxisOffset, props.data5]);
|
|
169
206
|
|
|
170
207
|
const secondaryData =
|
|
171
208
|
getSecondaryDataWithOffsetIncluded(
|
|
172
209
|
props.secondaryData,
|
|
173
|
-
props.secondaryYAxis
|
|
210
|
+
props.secondaryYAxis,
|
|
211
|
+
showDataPointsForMissingValues,
|
|
212
|
+
interpolateMissingValues,
|
|
213
|
+
onlyPositive
|
|
174
214
|
) || [];
|
|
175
215
|
|
|
176
|
-
|
|
216
|
+
let dataSet = props.dataSet;
|
|
217
|
+
if (dataSet?.length) {
|
|
218
|
+
dataSet = dataSet.map((dataSetItem) => ({
|
|
219
|
+
...dataSetItem,
|
|
220
|
+
data: getInterpolatedData(
|
|
221
|
+
dataSetItem.data,
|
|
222
|
+
showDataPointsForMissingValues,
|
|
223
|
+
interpolateMissingValues,
|
|
224
|
+
onlyPositive
|
|
225
|
+
),
|
|
226
|
+
}));
|
|
227
|
+
}
|
|
177
228
|
const data0 = useMemo(() => {
|
|
178
229
|
if (props.yAxisOffset) {
|
|
179
230
|
return dataSet?.[0]?.data;
|
|
@@ -224,7 +275,9 @@ export const useLineChart = (props: extendedLineChartPropsType) => {
|
|
|
224
275
|
const startIndex5 = props.startIndex5 || 0;
|
|
225
276
|
const endIndex5 = props.endIndex5 ?? data5.length - 1;
|
|
226
277
|
|
|
227
|
-
const lineSegments =
|
|
278
|
+
const lineSegments = !interpolateMissingValues
|
|
279
|
+
? getLineSegmentsForMissingValues(data)
|
|
280
|
+
: props.lineSegments;
|
|
228
281
|
const lineSegments2 = props.lineSegments2;
|
|
229
282
|
const lineSegments3 = props.lineSegments3;
|
|
230
283
|
const lineSegments4 = props.lineSegments4;
|
|
@@ -242,7 +295,7 @@ export const useLineChart = (props: extendedLineChartPropsType) => {
|
|
|
242
295
|
const endSpacing =
|
|
243
296
|
props.endSpacing ?? (adjustToWidth ? 0 : LineDefaults.endSpacing);
|
|
244
297
|
|
|
245
|
-
const thickness = props.thickness
|
|
298
|
+
const thickness = props.thickness ?? LineDefaults.thickness;
|
|
246
299
|
|
|
247
300
|
const yAxisLabelWidth =
|
|
248
301
|
props.yAxisLabelWidth ??
|
|
@@ -693,24 +746,27 @@ export const useLineChart = (props: extendedLineChartPropsType) => {
|
|
|
693
746
|
);
|
|
694
747
|
};
|
|
695
748
|
|
|
696
|
-
const getNextPoint = (data, index, around) => {
|
|
749
|
+
const getNextPoint = (data, index, around, before) => {
|
|
697
750
|
const isLast = index === data.length - 1;
|
|
698
|
-
return isLast && !around
|
|
751
|
+
return isLast && !(around || before)
|
|
699
752
|
? " "
|
|
700
753
|
: " L" +
|
|
701
|
-
(getX(index) +
|
|
754
|
+
(getX(index) +
|
|
755
|
+
(around ? (isLast ? 0 : spacing / 2) : before ? 0 : spacing)) +
|
|
702
756
|
" " +
|
|
703
757
|
getY(data[index].value) +
|
|
704
758
|
" ";
|
|
705
759
|
};
|
|
706
760
|
const getStepPath = (data, i) => {
|
|
707
761
|
const around = edgePosition === EdgePosition.AROUND_DATA_POINT;
|
|
762
|
+
const before = edgePosition === EdgePosition.BEFORE_DATA_POINT;
|
|
708
763
|
return (
|
|
709
764
|
"L" +
|
|
710
|
-
(getX(i) -
|
|
765
|
+
(getX(i) -
|
|
766
|
+
(around && i > 0 ? spacing / 2 : before && i > 0 ? spacing : 0)) +
|
|
711
767
|
" " +
|
|
712
768
|
getY(data[i].value) +
|
|
713
|
-
getNextPoint(data, i, around)
|
|
769
|
+
getNextPoint(data, i, around, before)
|
|
714
770
|
);
|
|
715
771
|
};
|
|
716
772
|
|
package/src/LineChart/types.ts
CHANGED
|
@@ -319,6 +319,10 @@ export type LineChartPropsType = {
|
|
|
319
319
|
onEndReached?: () => void;
|
|
320
320
|
onStartReached?: () => void;
|
|
321
321
|
endReachedOffset?: number;
|
|
322
|
+
|
|
323
|
+
showDataPointsForMissingValues?: boolean;
|
|
324
|
+
interpolateMissingValues?: boolean;
|
|
325
|
+
onlyPositive?: boolean;
|
|
322
326
|
};
|
|
323
327
|
|
|
324
328
|
export type lineDataItem = {
|
|
@@ -323,8 +323,12 @@ export const useBarAndLineChartsWrapper = (
|
|
|
323
323
|
);
|
|
324
324
|
};
|
|
325
325
|
|
|
326
|
-
const isCloseToStart = ({ layoutMeasurement, contentOffset }) => {
|
|
327
|
-
|
|
326
|
+
// const isCloseToStart = ({ layoutMeasurement, contentOffset }) => {
|
|
327
|
+
// return layoutMeasurement.width + contentOffset.x <= initialSpacing;
|
|
328
|
+
// };
|
|
329
|
+
|
|
330
|
+
const isCloseToStart = ({ contentOffset }) => {
|
|
331
|
+
return contentOffset.x <= initialSpacing;
|
|
328
332
|
};
|
|
329
333
|
|
|
330
334
|
useEffect(() => {
|
package/src/utils/constants.ts
CHANGED
|
@@ -146,12 +146,14 @@ export const BarDefaults = {
|
|
|
146
146
|
animationDuration: 800,
|
|
147
147
|
opacity: 1,
|
|
148
148
|
isThreeD: false,
|
|
149
|
+
frontColor: "black",
|
|
149
150
|
threeDBarGradientColor: "white",
|
|
150
151
|
threeDBarFrontColor: "#C0CA3A",
|
|
151
152
|
threeDBarSideColor: "#887A24",
|
|
152
153
|
threeDBarTopColor: "#D9E676",
|
|
153
154
|
endReachedOffset: defaultEndReachedOffset,
|
|
154
155
|
focusedBarFrontColor: 'lightgreen',
|
|
156
|
+
focusedThreeDBarFrontColor: '#B0B929',
|
|
155
157
|
focusedBarSideColor: '#776913',
|
|
156
158
|
focusedBarTopColor: '#C8D565',
|
|
157
159
|
};
|
|
@@ -232,7 +234,7 @@ export const LineDefaults = {
|
|
|
232
234
|
stripWidth: 2,
|
|
233
235
|
unFocusOnPressOut: true,
|
|
234
236
|
delayBeforeUnFocus: 300,
|
|
235
|
-
edgePosition: EdgePosition.
|
|
237
|
+
edgePosition: EdgePosition.AFTER_DATA_POINT,
|
|
236
238
|
endReachedOffset: defaultEndReachedOffset,
|
|
237
239
|
};
|
|
238
240
|
|
package/src/utils/index.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { lineDataItem } from "../LineChart/types";
|
|
1
2
|
import {
|
|
2
3
|
AxesAndRulesDefaults,
|
|
3
4
|
BarDefaults,
|
|
@@ -720,15 +721,25 @@ export const getExtendedContainerHeightWithPadding = (
|
|
|
720
721
|
|
|
721
722
|
export const getSecondaryDataWithOffsetIncluded = (
|
|
722
723
|
secondaryData?: any,
|
|
723
|
-
secondaryYAxis?: any
|
|
724
|
+
secondaryYAxis?: any,
|
|
725
|
+
showDataPointsForMissingValues?: boolean,
|
|
726
|
+
interpolateMissingValues?: boolean,
|
|
727
|
+
onlyPositive?: boolean
|
|
724
728
|
) => {
|
|
725
|
-
if (secondaryData
|
|
726
|
-
|
|
729
|
+
if (!secondaryData) return secondaryData;
|
|
730
|
+
const nullishHandledData = getInterpolatedData(
|
|
731
|
+
secondaryData,
|
|
732
|
+
showDataPointsForMissingValues,
|
|
733
|
+
interpolateMissingValues,
|
|
734
|
+
onlyPositive
|
|
735
|
+
);
|
|
736
|
+
if (secondaryYAxis?.yAxisOffset) {
|
|
737
|
+
return nullishHandledData.map((item) => {
|
|
727
738
|
item.value = item.value - (secondaryYAxis?.yAxisOffset ?? 0);
|
|
728
739
|
return item;
|
|
729
740
|
});
|
|
730
741
|
}
|
|
731
|
-
return
|
|
742
|
+
return nullishHandledData;
|
|
732
743
|
};
|
|
733
744
|
|
|
734
745
|
export const getArrowProperty = (
|
|
@@ -1155,12 +1166,22 @@ export const getBarFrontColor = (
|
|
|
1155
1166
|
isFocused,
|
|
1156
1167
|
focusedBarConfig,
|
|
1157
1168
|
itemFrontColor,
|
|
1158
|
-
frontColor
|
|
1169
|
+
frontColor,
|
|
1170
|
+
isThreeD
|
|
1159
1171
|
) => {
|
|
1160
1172
|
if (isFocused) {
|
|
1161
|
-
return
|
|
1173
|
+
return (
|
|
1174
|
+
focusedBarConfig?.color ??
|
|
1175
|
+
(isThreeD
|
|
1176
|
+
? BarDefaults.focusedThreeDBarFrontColor
|
|
1177
|
+
: BarDefaults.focusedBarFrontColor)
|
|
1178
|
+
);
|
|
1162
1179
|
}
|
|
1163
|
-
return
|
|
1180
|
+
return (
|
|
1181
|
+
itemFrontColor ||
|
|
1182
|
+
frontColor ||
|
|
1183
|
+
(isThreeD ? BarDefaults.threeDBarFrontColor : BarDefaults.frontColor)
|
|
1184
|
+
);
|
|
1164
1185
|
};
|
|
1165
1186
|
|
|
1166
1187
|
export const getBarSideColor = (
|
|
@@ -1199,3 +1220,155 @@ export const getBarWidth = (
|
|
|
1199
1220
|
}
|
|
1200
1221
|
return localBarWidth;
|
|
1201
1222
|
};
|
|
1223
|
+
|
|
1224
|
+
export const getInterpolatedData = (
|
|
1225
|
+
dataParam: lineDataItem[],
|
|
1226
|
+
showDataPointsForMissingValues?: boolean,
|
|
1227
|
+
interpolateMissingValues?: boolean,
|
|
1228
|
+
onlyPositive?: boolean
|
|
1229
|
+
): lineDataItem[] => {
|
|
1230
|
+
if (!interpolateMissingValues) {
|
|
1231
|
+
return dataParam.map((item) => {
|
|
1232
|
+
if (typeof item.value !== "number") {
|
|
1233
|
+
if (showDataPointsForMissingValues) return { ...item, value: 0 };
|
|
1234
|
+
return { ...item, value: 0, hideDataPoint: true };
|
|
1235
|
+
}
|
|
1236
|
+
return item;
|
|
1237
|
+
});
|
|
1238
|
+
}
|
|
1239
|
+
if (!interpolateMissingValues) return dataParam;
|
|
1240
|
+
const data = clone(dataParam);
|
|
1241
|
+
const n = data.length;
|
|
1242
|
+
|
|
1243
|
+
/************** PRE-PROCESSING **************/
|
|
1244
|
+
let numericValue;
|
|
1245
|
+
const numericValuesLength = data.filter((item) => {
|
|
1246
|
+
const isNum = typeof item.value === "number";
|
|
1247
|
+
if (isNum) {
|
|
1248
|
+
numericValue = item.value;
|
|
1249
|
+
return true;
|
|
1250
|
+
}
|
|
1251
|
+
return false;
|
|
1252
|
+
}).length;
|
|
1253
|
+
|
|
1254
|
+
if (!numericValuesLength) return [];
|
|
1255
|
+
|
|
1256
|
+
if (numericValuesLength === 1) {
|
|
1257
|
+
data.forEach((item) => {
|
|
1258
|
+
if (!showDataPointsForMissingValues && typeof item.value !== "number") {
|
|
1259
|
+
item.hideDataPoint = true;
|
|
1260
|
+
}
|
|
1261
|
+
item.value = numericValue;
|
|
1262
|
+
});
|
|
1263
|
+
return data;
|
|
1264
|
+
}
|
|
1265
|
+
/**********************************************************************/
|
|
1266
|
+
|
|
1267
|
+
data.forEach((item, index) => {
|
|
1268
|
+
if (typeof item.value === "number") return;
|
|
1269
|
+
// Cut the line in 2 halves-> pre and post
|
|
1270
|
+
// Now there are 4 possibilities-
|
|
1271
|
+
// 1. Both pre and post have valid values
|
|
1272
|
+
// 2. Only pre has valid value
|
|
1273
|
+
// 3. Only post has valid value
|
|
1274
|
+
// 4. None has valid value -> this is already handled in preprocessing
|
|
1275
|
+
|
|
1276
|
+
const pre = data.slice(0, index);
|
|
1277
|
+
const post = data.slice(index + 1, n);
|
|
1278
|
+
|
|
1279
|
+
const preValidIndex = pre.findLastIndex(
|
|
1280
|
+
(item) => typeof item.value === "number"
|
|
1281
|
+
);
|
|
1282
|
+
const postValidInd = post.findIndex(
|
|
1283
|
+
(item) => typeof item.value === "number"
|
|
1284
|
+
);
|
|
1285
|
+
const postValidIndex = postValidInd + index + 1;
|
|
1286
|
+
|
|
1287
|
+
let count, step;
|
|
1288
|
+
|
|
1289
|
+
// 1. Both pre and post have valid values
|
|
1290
|
+
if (preValidIndex !== -1 && postValidInd !== -1) {
|
|
1291
|
+
count = postValidIndex - preValidIndex;
|
|
1292
|
+
step = (data[postValidIndex].value - data[preValidIndex].value) / count;
|
|
1293
|
+
data[index].value =
|
|
1294
|
+
data[preValidIndex].value + step * (index - preValidIndex);
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
// 2. Only pre has valid value
|
|
1298
|
+
else if (preValidIndex !== -1 && postValidInd === -1) {
|
|
1299
|
+
// Now there are 2 possibilities-
|
|
1300
|
+
// 1. There's only 1 valid value in the pre -> this is already handled in preprocessing
|
|
1301
|
+
// 2. There are more than valid values in pre
|
|
1302
|
+
const secondPre = data.slice(0, preValidIndex);
|
|
1303
|
+
const secondPreIndex = secondPre.findLastIndex(
|
|
1304
|
+
(item) => typeof item.value === "number"
|
|
1305
|
+
);
|
|
1306
|
+
|
|
1307
|
+
count = preValidIndex - secondPreIndex;
|
|
1308
|
+
step = (data[secondPreIndex].value - data[preValidIndex].value) / count;
|
|
1309
|
+
data[index].value =
|
|
1310
|
+
data[preValidIndex].value - step * (index - preValidIndex);
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
// 3. Only post has valid value
|
|
1314
|
+
else if (preValidIndex === -1 && postValidInd !== -1) {
|
|
1315
|
+
// Now there are 2 possibilities-
|
|
1316
|
+
// 1. There's only 1 valid value in the post -> this is already handled in preprocessing
|
|
1317
|
+
// 2. There are more than valid values in post
|
|
1318
|
+
|
|
1319
|
+
const secondPost = data.slice(postValidIndex + 1, n);
|
|
1320
|
+
const secondPostInd = secondPost.findIndex(
|
|
1321
|
+
(item) => typeof item.value === "number"
|
|
1322
|
+
);
|
|
1323
|
+
const secondPostIndex = secondPostInd + postValidIndex + 1;
|
|
1324
|
+
|
|
1325
|
+
count = secondPostIndex - postValidIndex;
|
|
1326
|
+
step = (data[secondPostIndex].value - data[postValidIndex].value) / count;
|
|
1327
|
+
data[index].value =
|
|
1328
|
+
data[postValidIndex].value - step * (postValidIndex - index);
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
// hide data point (since it is interpolated)
|
|
1332
|
+
if (!showDataPointsForMissingValues) {
|
|
1333
|
+
item.hideDataPoint = true;
|
|
1334
|
+
}
|
|
1335
|
+
});
|
|
1336
|
+
return onlyPositive
|
|
1337
|
+
? data.map((item) => ({ ...item, value: Math.max(item.value, 0) }))
|
|
1338
|
+
: data;
|
|
1339
|
+
};
|
|
1340
|
+
|
|
1341
|
+
export const getLineSegmentsForMissingValues = (
|
|
1342
|
+
data: lineDataItem[]
|
|
1343
|
+
): LineSegment[] => {
|
|
1344
|
+
let i,
|
|
1345
|
+
n = data.length;
|
|
1346
|
+
const numericValuesLength = data.filter(
|
|
1347
|
+
(item) => typeof item.value === "number"
|
|
1348
|
+
).length;
|
|
1349
|
+
if (!numericValuesLength) return [];
|
|
1350
|
+
const segments: LineSegment[] = [];
|
|
1351
|
+
for (i = 0; i < n; i++) {
|
|
1352
|
+
if (typeof data[i].value !== "number") {
|
|
1353
|
+
const nextValidInd = data
|
|
1354
|
+
.slice(i + 1, n)
|
|
1355
|
+
.findIndex((item) => typeof item.value === "number");
|
|
1356
|
+
if (nextValidInd === -1) {
|
|
1357
|
+
segments.push({
|
|
1358
|
+
startIndex: Math.max(i - 1, 0),
|
|
1359
|
+
endIndex: n,
|
|
1360
|
+
color: "transparent",
|
|
1361
|
+
});
|
|
1362
|
+
break;
|
|
1363
|
+
}
|
|
1364
|
+
const nextValidIndex = nextValidInd + i + 1;
|
|
1365
|
+
segments.push({
|
|
1366
|
+
startIndex: Math.max(i - 1, 0),
|
|
1367
|
+
endIndex: nextValidIndex,
|
|
1368
|
+
color: "transparent",
|
|
1369
|
+
});
|
|
1370
|
+
i = nextValidIndex;
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
return segments;
|
|
1374
|
+
};
|