@oliasoft-open-source/charts-library 0.0.2-beta-1

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.
Files changed (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/index.js +13 -0
  4. package/package.json +100 -0
  5. package/release-notes.md +178 -0
  6. package/src/assets/icons/line-and-point.svg +1 -0
  7. package/src/assets/icons/line-only.svg +1 -0
  8. package/src/assets/icons/list-hide.svg +1 -0
  9. package/src/assets/icons/point-only.svg +1 -0
  10. package/src/components/bar-chart/bar-chart-prop-types.js +188 -0
  11. package/src/components/bar-chart/bar-chart.interface.ts +84 -0
  12. package/src/components/bar-chart/bar-chart.jsx +243 -0
  13. package/src/components/bar-chart/bar-chart.module.less +61 -0
  14. package/src/components/bar-chart/get-bar-chart-data-labels.js +42 -0
  15. package/src/components/bar-chart/get-bar-chart-scales.js +123 -0
  16. package/src/components/bar-chart/get-bar-chart-tooltips.js +100 -0
  17. package/src/components/controls/axes-options/axes-options-form-state.js +95 -0
  18. package/src/components/controls/axes-options/axes-options.jsx +166 -0
  19. package/src/components/controls/controls.jsx +104 -0
  20. package/src/components/controls/controls.module.less +12 -0
  21. package/src/components/controls/drag-options.jsx +77 -0
  22. package/src/components/controls/legend-options.jsx +25 -0
  23. package/src/components/controls/line-options.jsx +54 -0
  24. package/src/components/line-chart/axis-scales/axis-scales.js +165 -0
  25. package/src/components/line-chart/datalabels-alignment/get-alignment-condition.js +13 -0
  26. package/src/components/line-chart/datalabels-alignment/get-alignment-data.js +20 -0
  27. package/src/components/line-chart/datalabels-alignment/get-datalabels-position.js +25 -0
  28. package/src/components/line-chart/get-axes-ranges-from-chart.js +10 -0
  29. package/src/components/line-chart/get-line-chart-data-labels.js +21 -0
  30. package/src/components/line-chart/get-line-chart-scales.js +120 -0
  31. package/src/components/line-chart/get-line-chart-tooltips.js +91 -0
  32. package/src/components/line-chart/line-chart-consts.js +7 -0
  33. package/src/components/line-chart/line-chart-prop-types.js +212 -0
  34. package/src/components/line-chart/line-chart-utils.js +192 -0
  35. package/src/components/line-chart/line-chart.interface.ts +107 -0
  36. package/src/components/line-chart/line-chart.jsx +531 -0
  37. package/src/components/line-chart/line-chart.minor-gridlines-plugin.js +88 -0
  38. package/src/components/line-chart/line-chart.module.less +77 -0
  39. package/src/components/line-chart/state/action-types.js +11 -0
  40. package/src/components/line-chart/state/initial-state.js +69 -0
  41. package/src/components/line-chart/state/line-chart-reducer.js +101 -0
  42. package/src/components/pie-chart/pie-chart-prop-types.js +111 -0
  43. package/src/components/pie-chart/pie-chart-utils.js +32 -0
  44. package/src/components/pie-chart/pie-chart.interface.ts +61 -0
  45. package/src/components/pie-chart/pie-chart.jsx +450 -0
  46. package/src/components/pie-chart/pie-chart.module.less +61 -0
  47. package/src/components/scatter-chart/scatter-chart.intefrace.ts +33 -0
  48. package/src/components/scatter-chart/scatter-chart.jsx +21 -0
  49. package/src/components/scatter-chart/scatter-chart.module.less +4 -0
  50. package/src/helpers/chart-border-plugin.js +19 -0
  51. package/src/helpers/chart-consts.js +62 -0
  52. package/src/helpers/chart-interface.ts +76 -0
  53. package/src/helpers/chart-utils.js +183 -0
  54. package/src/helpers/container.jsx +60 -0
  55. package/src/helpers/disabled-context.js +8 -0
  56. package/src/helpers/enums.js +87 -0
  57. package/src/helpers/get-chart-annotation.js +143 -0
  58. package/src/helpers/get-custom-legend-plugin-example.js +80 -0
  59. package/src/helpers/numbers/numbers.js +44 -0
  60. package/src/helpers/range/estimate-data-series-have-close-values.js +54 -0
  61. package/src/helpers/range/range.js +95 -0
  62. package/src/helpers/styles.js +68 -0
  63. package/src/helpers/text.js +6 -0
  64. package/src/style/external.less +4 -0
  65. package/src/style/fonts/lato/Lato-Bold.woff2 +0 -0
  66. package/src/style/fonts/lato/Lato-BoldItalic.woff2 +0 -0
  67. package/src/style/fonts/lato/Lato-Italic.woff2 +0 -0
  68. package/src/style/fonts/lato/Lato-Regular.woff2 +0 -0
  69. package/src/style/fonts.less +27 -0
  70. package/src/style/global.less +43 -0
  71. package/src/style/reset/reset.less +28 -0
  72. package/src/style/shared.less +24 -0
  73. package/src/style/variables.less +91 -0
@@ -0,0 +1,120 @@
1
+ import {
2
+ generateRandomColor,
3
+ getAxisPosition,
4
+ } from '../../helpers/chart-utils';
5
+ import { COLORS, LOGARITHMIC_STEPS } from '../../helpers/chart-consts';
6
+ import { generateAxisId, truncateDecimals } from './line-chart-utils';
7
+ import { AxisType, ScaleType } from '../../helpers/enums';
8
+
9
+ /**
10
+ * @param {import('./line-chart.interface').ILineChartOptions} options - line chart options object
11
+ * @param {'x'|'y'} axisType
12
+ * @param {import('../../helpers/chart-interface').IInitialState} state - chart state object controlled by useReducer or similar
13
+ * @param {import('./line-chart.interface').ILineChartAxis[]} [currentScales]
14
+ * @param {number} [i]
15
+ */
16
+ const getLineChartAxis = (options, axisType, state, currentScales, i = 0) => {
17
+ const axisData = currentScales || options.axes[axisType][0];
18
+ const stateAxis = state.axes.filter((axis) => axis.id.startsWith(axisType))[
19
+ i
20
+ ];
21
+
22
+ const { additionalAxesOptions, chartStyling } = options;
23
+
24
+ const getTicks = () => {
25
+ const truncateAxisNumbersToDigitsCallback = Number.isInteger(
26
+ additionalAxesOptions.truncateAxisNumbersToDigitsCallback,
27
+ )
28
+ ? {
29
+ callback: (tick) =>
30
+ truncateDecimals(
31
+ tick,
32
+ additionalAxesOptions.truncateAxisNumbersToDigitsCallback,
33
+ ),
34
+ }
35
+ : {};
36
+
37
+ const ticks =
38
+ additionalAxesOptions.chartScaleType === ScaleType.Logarithmic
39
+ ? {
40
+ callback: (tick) => {
41
+ return LOGARITHMIC_STEPS.includes(tick)
42
+ ? tick.toLocaleString()
43
+ : '';
44
+ },
45
+ }
46
+ : {
47
+ stepSize:
48
+ axisData.stepSize ||
49
+ (axisType === AxisType.Y ? additionalAxesOptions.stepSize : null),
50
+ ...truncateAxisNumbersToDigitsCallback,
51
+ };
52
+ return {
53
+ ...ticks,
54
+ includeBounds: false, //OW-10088 disable irregular axis ticks
55
+ };
56
+ };
57
+
58
+ return {
59
+ type: additionalAxesOptions.chartScaleType,
60
+ position: axisData.position,
61
+ beginAtZero: additionalAxesOptions.beginAtZero,
62
+ reverse: axisType === AxisType.Y ? additionalAxesOptions.reverse : false,
63
+ suggestedMax: additionalAxesOptions.suggestedMax,
64
+ suggestedMin: additionalAxesOptions.suggestedMin,
65
+ min: stateAxis?.min ?? additionalAxesOptions?.range?.[axisType]?.min,
66
+ max: stateAxis?.max ?? additionalAxesOptions?.range?.[axisType]?.max,
67
+ title: {
68
+ display: axisData.label?.length,
69
+ text: axisData.label,
70
+ padding: 0,
71
+ },
72
+ ticks: getTicks(),
73
+ grid: {
74
+ ...axisData.gridLines,
75
+ },
76
+ };
77
+ };
78
+
79
+ /**
80
+ * @param {import('./line-chart.interface').ILineChartOptions} options - line chart options object
81
+ * @param {'x'|'y'} axisType
82
+ * @param {import('../../helpers/chart-interface').IInitialState} state - chart state object controlled by useReducer or similar
83
+ */
84
+ const getLineChartAxes = (options, axisType, state) => {
85
+ const axesData = options.axes[axisType];
86
+ const axes = axesData.reduce((acc, curr, i) => {
87
+ const axisData = curr;
88
+ axisData.color = curr.color || COLORS[i] || generateRandomColor(COLORS);
89
+ axisData.position = curr.position || getAxisPosition(axisType, i);
90
+
91
+ const axis = getLineChartAxis(options, axisType, state, axisData, i);
92
+ const axisId = generateAxisId(axisType, i, true);
93
+ return { ...acc, [axisId]: axis };
94
+ }, {});
95
+ return axes;
96
+ };
97
+
98
+ /**
99
+ *
100
+ * @param {import('./line-chart.interface').ILineChartOptions} options - line chart options object
101
+ * @param {import('../../helpers/chart-interface').IInitialState} state - chart state object controlled by useReducer or similar
102
+ */
103
+ const getLineChartScales = (options, state) => {
104
+ const hasMultipleXAxes = options.axes.x?.length > 1;
105
+ const hasMultipleYAxes = options.axes.y?.length > 1;
106
+
107
+ const xAxes = hasMultipleXAxes
108
+ ? getLineChartAxes(options, AxisType.X, state)
109
+ : { x: getLineChartAxis(options, AxisType.X, state) };
110
+ const yAxes = hasMultipleYAxes
111
+ ? getLineChartAxes(options, AxisType.Y, state)
112
+ : { y: getLineChartAxis(options, AxisType.Y, state) };
113
+
114
+ return {
115
+ ...xAxes,
116
+ ...yAxes,
117
+ };
118
+ };
119
+
120
+ export default getLineChartScales;
@@ -0,0 +1,91 @@
1
+ import { ChartHoverMode, Position, TooltipLabel } from '../../helpers/enums';
2
+ import { afterLabelCallback, getTooltipLabel } from '../../helpers/chart-utils';
3
+
4
+ /**
5
+ * @param {import('./line-chart.interface').ILineChartOptions} options - line chart options object
6
+ */
7
+ const getLineChartToolTips = (options) => {
8
+ const getTooltipLabels = (dataset) => {
9
+ const xIndex = dataset.xAxisID?.length > 1 ? dataset.xAxisID[1] - 1 : 0;
10
+ const yIndex = dataset.yAxisID?.length > 1 ? dataset.yAxisID[1] - 1 : 0;
11
+ const xAxis = options.axes.x[xIndex];
12
+ const yAxis = options.axes.y[yIndex];
13
+
14
+ if (options.axes.x[0].position === Position.Top) {
15
+ return {
16
+ titleAxisLabel: yAxis?.label || '',
17
+ valueAxisLabel: xAxis?.label || '',
18
+ titleLabel: TooltipLabel.Y,
19
+ valueLabel: TooltipLabel.X,
20
+ };
21
+ } else {
22
+ return {
23
+ titleAxisLabel: xAxis?.label || '',
24
+ valueAxisLabel: yAxis?.label || '',
25
+ titleLabel: TooltipLabel.X,
26
+ valueLabel: TooltipLabel.Y,
27
+ };
28
+ }
29
+ };
30
+
31
+ const titleCallback = (tooltipItem, data) => {
32
+ const labels = getTooltipLabels(tooltipItem[0].dataset);
33
+ const { titleLabel, titleAxisLabel } = labels;
34
+
35
+ const formattedValue =
36
+ titleLabel === TooltipLabel.Y
37
+ ? tooltipItem[0].parsed.y
38
+ : tooltipItem[0].parsed.x;
39
+ const roundedValue =
40
+ Math.abs(formattedValue) < 1
41
+ ? formattedValue.toPrecision(3)
42
+ : formattedValue.toFixed(2);
43
+
44
+ return `${roundedValue} ${titleAxisLabel}`;
45
+ };
46
+
47
+ const labelCallback = (tooltipItem) => {
48
+ const { showLabelsInTooltips, hideSimulationName } = options.tooltip;
49
+ let label = tooltipItem.dataset.label || '';
50
+ const labels = getTooltipLabels(tooltipItem.dataset);
51
+ const { valueLabel, valueAxisLabel } = labels;
52
+
53
+ const getTooltipItemValue = () => {
54
+ const labelNumber =
55
+ valueLabel === TooltipLabel.X
56
+ ? tooltipItem.parsed.x
57
+ : tooltipItem.parsed.y;
58
+ return Math.abs(labelNumber) < 1
59
+ ? labelNumber.toPrecision(3)
60
+ : labelNumber.toFixed(3);
61
+ };
62
+
63
+ const splitValueAxisLabel = valueAxisLabel.split(' ');
64
+ const newValueAxisLabel = hideSimulationName
65
+ ? splitValueAxisLabel[splitValueAxisLabel.length - 1]
66
+ : valueAxisLabel;
67
+
68
+ const tooltipItemValue = getTooltipItemValue();
69
+ const valAxisLabel =
70
+ label === valueAxisLabel || valueAxisLabel.includes(label)
71
+ ? ''
72
+ : newValueAxisLabel;
73
+ const tooltipLabel = getTooltipLabel(tooltipItem, showLabelsInTooltips);
74
+
75
+ return `${label}: ${tooltipItemValue} ${valAxisLabel}${tooltipLabel}`;
76
+ };
77
+
78
+ return {
79
+ enabled: options.tooltip.tooltips,
80
+ mode: ChartHoverMode.Nearest,
81
+ intersect: true,
82
+ padding: 8,
83
+ callbacks: {
84
+ title: titleCallback,
85
+ label: labelCallback,
86
+ afterLabel: afterLabelCallback,
87
+ },
88
+ };
89
+ };
90
+
91
+ export default getLineChartToolTips;
@@ -0,0 +1,7 @@
1
+ export const DEFAULT_POINT_RADIUS = 2;
2
+ export const DEFAULT_HOVER_RADIUS = 5;
3
+ export const DEFAULT_BORDER_WIDTH = 1;
4
+ export const BORDER_JOIN_STYLE = 'round';
5
+ export const DEFAULT_LINE_POINT_RADIUS = 0;
6
+ export const DEFAULT_BACKGROUND_COLOR = 'transparent';
7
+ export const ZOOM_BOX_BACKGROUND_COLOR = 'rgba(0, 0, 0, 0.1)';
@@ -0,0 +1,212 @@
1
+ import PropTypes from 'prop-types';
2
+
3
+ export const LineChartPropTypes = {
4
+ table: PropTypes.node,
5
+ chart: PropTypes.shape({
6
+ testId: PropTypes.string,
7
+ data: PropTypes.object.isRequired,
8
+ options: PropTypes.shape({
9
+ title: PropTypes.oneOfType([
10
+ PropTypes.string,
11
+ PropTypes.arrayOf(PropTypes.string),
12
+ ]),
13
+ axes: PropTypes.shape({
14
+ x: PropTypes.arrayOf(
15
+ PropTypes.shape({
16
+ label: PropTypes.string,
17
+ position: PropTypes.oneOf(['top', 'bottom']),
18
+ color: PropTypes.string,
19
+ }),
20
+ ),
21
+ y: PropTypes.arrayOf(
22
+ PropTypes.shape({
23
+ label: PropTypes.string,
24
+ position: PropTypes.oneOf(['left', 'right']),
25
+ color: PropTypes.string,
26
+ }),
27
+ ),
28
+ }),
29
+ additionalAxesOptions: PropTypes.shape({
30
+ chartScaleType: PropTypes.oneOf(['linear', 'logarithmic']),
31
+ reverse: PropTypes.bool,
32
+ beginAtZero: PropTypes.bool,
33
+ stepSize: PropTypes.number,
34
+ truncateAxisNumbersToDigitsCallback: PropTypes.number,
35
+ suggestedMin: PropTypes.number,
36
+ suggestedMax: PropTypes.number,
37
+ range: PropTypes.shape({
38
+ x: PropTypes.shape({
39
+ min: PropTypes.number,
40
+ max: PropTypes.number,
41
+ }),
42
+ y: PropTypes.shape({
43
+ min: PropTypes.number,
44
+ max: PropTypes.number,
45
+ }),
46
+ }),
47
+ autoAxisPadding: PropTypes.bool,
48
+ }),
49
+ chartStyling: PropTypes.shape({
50
+ width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
51
+ height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
52
+ maintainAspectRatio: PropTypes.bool,
53
+ staticChartHeight: PropTypes.bool,
54
+ performanceMode: PropTypes.bool,
55
+ squareAspectRatio: PropTypes.bool,
56
+ }),
57
+ tooltip: PropTypes.shape({
58
+ tooltips: PropTypes.bool,
59
+ showLabelsInTooltips: PropTypes.bool,
60
+ hideSimulationName: PropTypes.bool,
61
+ }),
62
+ graph: PropTypes.shape({
63
+ lineTension: PropTypes.number,
64
+ spanGaps: PropTypes.bool,
65
+ showDataLabels: PropTypes.bool,
66
+ showMinorGridlines: PropTypes.bool,
67
+ }),
68
+ annotations: PropTypes.shape({
69
+ labelAnnotation: PropTypes.object,
70
+ showAnnotations: PropTypes.bool,
71
+ controlAnnotation: PropTypes.bool,
72
+ annotationsData: PropTypes.arrayOf(
73
+ PropTypes.shape({
74
+ adjustScaleRange: PropTypes.bool,
75
+ annotationAxis: PropTypes.oneOf(['x', 'y']),
76
+ color: PropTypes.string,
77
+ endValue: PropTypes.number,
78
+ label: PropTypes.string,
79
+ type: PropTypes.string,
80
+ value: PropTypes.number,
81
+ xMin: PropTypes.number,
82
+ xMax: PropTypes.number,
83
+ yMin: PropTypes.number,
84
+ yMax: PropTypes.number,
85
+ }),
86
+ ),
87
+ }),
88
+ legend: PropTypes.shape({
89
+ display: PropTypes.bool,
90
+ position: PropTypes.oneOf(['top', 'bottom', 'right']),
91
+ align: PropTypes.oneOf(['start', 'center', 'end']),
92
+ customLegend: PropTypes.shape({
93
+ customLegendPlugin: PropTypes.object,
94
+ customLegendContainerID: PropTypes.string,
95
+ }),
96
+ }),
97
+ chartOptions: PropTypes.shape({
98
+ showPoints: PropTypes.bool,
99
+ enableZoom: PropTypes.bool,
100
+ enablePan: PropTypes.bool,
101
+ closeOnOutsideClick: PropTypes.bool,
102
+ }),
103
+ interactions: PropTypes.shape({
104
+ onLegendClick: PropTypes.func,
105
+ onPointHover: PropTypes.func,
106
+ onPointUnhover: PropTypes.func,
107
+ onAnimationComplete: PropTypes.func,
108
+ }),
109
+ }),
110
+ }).isRequired,
111
+ };
112
+
113
+ export const getDefaultProps = (props) => {
114
+ // Add missing nested objects
115
+ props.chart.options = props.chart.options || {};
116
+ props.chart.options.axes = props.chart.options.axes || {};
117
+ props.chart.options.additionalAxesOptions =
118
+ props.chart.options.additionalAxesOptions || {};
119
+ props.chart.options.chartStyling = props.chart.options.chartStyling || {};
120
+ props.chart.options.tooltip = props.chart.options.tooltip || {};
121
+ props.chart.options.graph = props.chart.options.graph || {};
122
+ props.chart.options.annotations = props.chart.options.annotations || {};
123
+ props.chart.options.legend = props.chart.options.legend || {};
124
+ props.chart.options.legend.customLegend = props.chart.options.legend
125
+ .customLegend || { customLegendPlugin: null, customLegendContainerID: '' };
126
+ props.chart.options.chartOptions = props.chart.options.chartOptions || {};
127
+ props.chart.options.interactions = props.chart.options.interactions || {};
128
+ // Set defaults for missing properties
129
+ const chart = {
130
+ testId: props.chart.testId ?? null,
131
+ data: props.chart.data,
132
+ options: {
133
+ title: props.chart.options.title || '',
134
+ axes: {
135
+ x: props.chart.options.axes.x || [{}],
136
+ y: props.chart.options.axes.y || [{}],
137
+ },
138
+ additionalAxesOptions: {
139
+ chartScaleType:
140
+ props.chart.options.additionalAxesOptions.chartScaleType || 'linear',
141
+ reverse: props.chart.options.additionalAxesOptions.reverse || false,
142
+ beginAtZero:
143
+ props.chart.options.additionalAxesOptions.beginAtZero || false,
144
+ stepSize: props.chart.options.additionalAxesOptions.stepSize,
145
+ truncateAxisNumbersToDigitsCallback:
146
+ props.chart.options.additionalAxesOptions
147
+ .truncateAxisNumbersToDigitsCallback,
148
+ suggestedMin: props.chart.options.additionalAxesOptions.suggestedMin,
149
+ suggestedMax: props.chart.options.additionalAxesOptions.suggestedMax,
150
+ range: props.chart.options.additionalAxesOptions.range,
151
+ autoAxisPadding:
152
+ props.chart.options.additionalAxesOptions.autoAxisPadding ?? false,
153
+ },
154
+ chartStyling: {
155
+ width: props.chart.options.chartStyling.width,
156
+ height: props.chart.options.chartStyling.height,
157
+ maintainAspectRatio:
158
+ props.chart.options.chartStyling.maintainAspectRatio || false,
159
+ staticChartHeight:
160
+ props.chart.options.chartStyling.staticChartHeight || false,
161
+ performanceMode:
162
+ props.chart.options.chartStyling.performanceMode ?? true,
163
+ squareAspectRatio:
164
+ props.chart.options.chartStyling.squareAspectRatio || false,
165
+ },
166
+ tooltip: {
167
+ tooltips: props.chart.options.tooltip.tooltips ?? true,
168
+ showLabelsInTooltips:
169
+ props.chart.options.tooltip.showLabelsInTooltips || false,
170
+ hideSimulationName:
171
+ props.chart.options.tooltip.hideSimulationName || false,
172
+ },
173
+ graph: {
174
+ lineTension: props.chart.options.graph.lineTension || 0.01,
175
+ spanGaps: props.chart.options.graph.spanGaps || false,
176
+ showDataLabels: props.chart.options.graph.showDataLabels || false,
177
+ showMinorGridlines:
178
+ props.chart.options.graph.showMinorGridlines || false,
179
+ },
180
+ annotations: {
181
+ labelAnnotation: props.chart.options.annotations.labelAnnotation || {},
182
+ showAnnotations:
183
+ props.chart.options.annotations.showAnnotations ?? false,
184
+ controlAnnotation:
185
+ props.chart.options.annotations.controlAnnotation || false,
186
+ annotationsData: props.chart.options.annotations.annotationsData || [],
187
+ },
188
+ legend: {
189
+ display: props.chart.options.legend.display ?? true,
190
+ position: props.chart.options.legend.position || 'bottom',
191
+ align: props.chart.options.legend.align || 'center',
192
+ customLegend: props.chart.options.legend.customLegend,
193
+ },
194
+ chartOptions: {
195
+ showPoints: props.chart.options.chartOptions.showPoints ?? true,
196
+ enableZoom: props.chart.options.chartOptions.enableZoom || false,
197
+ enablePan: props.chart.options.chartOptions.enablePan || false,
198
+ showLine: props.chart.options.chartOptions.showLine ?? true,
199
+ closeOnOutsideClick:
200
+ props.chart.options.chartOptions.closeOnOutsideClick || false,
201
+ },
202
+ interactions: {
203
+ onLegendClick: props.chart.options.interactions.onLegendClick,
204
+ onPointHover: props.chart.options.interactions.onPointHover,
205
+ onPointUnhover: props.chart.options.interactions.onPointUnhover,
206
+ onAnimationComplete:
207
+ props.chart.options.interactions.onAnimationComplete,
208
+ },
209
+ },
210
+ };
211
+ return chart;
212
+ };
@@ -0,0 +1,192 @@
1
+ import Fraction from 'fraction.js';
2
+
3
+ const isNull = (str) => str === null;
4
+ const isUndefined = (str) => str === undefined;
5
+ const isArray = (str) => str && str.constructor === Array;
6
+ const isObject = (str) => str && str.constructor === Object;
7
+ const hasDivisor = (str) =>
8
+ str && typeof str.includes === 'function' && str.includes('/');
9
+ export const isEmptyString = (str) => str === '';
10
+ const isTrailingPeriodSeparator = (str) => str && str[str.length - 1] === '.';
11
+ const isTrailingCommaSeparator = (str) => str && str[str.length - 1] === ',';
12
+ const isOnlyNumbers = (str) => /^-?\d*\.?\d+$/.test(str);
13
+
14
+ export const charCount = (chr, str) => {
15
+ let total = 0,
16
+ last_location = 0,
17
+ single_char = (chr + '')[0];
18
+ while ((last_location = str.indexOf(single_char, last_location) + 1)) {
19
+ total += 1;
20
+ }
21
+ return total;
22
+ };
23
+
24
+ export const cleanNumStr = (str) => {
25
+ str += '';
26
+ let slashCount = charCount('/', str);
27
+ let spaceCount = charCount(' ', str) + charCount(' ', str);
28
+ let dotcount = charCount('.', str);
29
+ let commacount = charCount(',', str);
30
+ if (slashCount === 0 && spaceCount > 0) str = str.replace(/\s/g, '');
31
+ if (commacount > 1) str = str.replace(/,/g, '');
32
+ if (dotcount > 1) str = str.replace(/\./g, '');
33
+ commacount = charCount(',', str);
34
+ dotcount = charCount('.', str);
35
+ if (dotcount === 1 && commacount === 1) {
36
+ // One of each, make the rightmost act as decimal separator
37
+ if (str.indexOf(',') > str.indexOf('.')) {
38
+ str = str.replace('.', '');
39
+ str = str.replace(',', '.');
40
+ } else {
41
+ str = str.replace(',', '');
42
+ }
43
+ if (str.indexOf('.') === 0) {
44
+ str = 0 + str;
45
+ }
46
+ return str;
47
+ }
48
+ if (dotcount === 1 && commacount) str = str.replace(',', '');
49
+ if (!dotcount && commacount) str = str.replace(',', '.');
50
+ if (str.indexOf('.') === 0) {
51
+ str = 0 + str;
52
+ }
53
+ return str;
54
+ };
55
+
56
+ export const numFraction = (str) => {
57
+ if (str instanceof Array || str === null || str === undefined) {
58
+ return str;
59
+ }
60
+ if (typeof str === 'string') {
61
+ str = str.trim(); //trailing whitespace causes InvalidParameter error in fraction.js
62
+ }
63
+ let result = str;
64
+ try {
65
+ result = Fraction(str);
66
+ } catch (e) {
67
+ //do nothing
68
+ }
69
+ return result.valueOf();
70
+ };
71
+
72
+ export const isValidNum = (input) => {
73
+ let result = false;
74
+ if (isEmptyString(input)) {
75
+ result = true;
76
+ } else {
77
+ if (
78
+ !(
79
+ isNull(input) ||
80
+ isUndefined(input) ||
81
+ isTrailingPeriodSeparator(input) ||
82
+ isTrailingCommaSeparator(input) ||
83
+ isArray(input) ||
84
+ isObject(input) ||
85
+ !isOnlyNumbers(input)
86
+ )
87
+ ) {
88
+ let number;
89
+ const cleaned = cleanNumStr(input);
90
+ if (hasDivisor(cleaned)) {
91
+ //numFraction is slow, so only call it if needed
92
+ number = numFraction(cleaned);
93
+ } else {
94
+ number = parseFloat(cleaned);
95
+ }
96
+ if (!isNaN(number)) {
97
+ result = true;
98
+ }
99
+ }
100
+ }
101
+ return result;
102
+ };
103
+
104
+ export const toNumber = (input, defaultValue, minimum) => {
105
+ let result;
106
+ defaultValue = defaultValue === undefined ? input : defaultValue;
107
+ if (
108
+ isNull(input) ||
109
+ isUndefined(input) ||
110
+ isEmptyString(input) ||
111
+ isTrailingPeriodSeparator(input) ||
112
+ isTrailingCommaSeparator(input) ||
113
+ isArray(input) ||
114
+ isObject(input)
115
+ ) {
116
+ result = defaultValue;
117
+ } else {
118
+ let number;
119
+ const cleaned = cleanNumStr(input);
120
+ if (hasDivisor(cleaned)) {
121
+ //numFraction is slow, so only call it if needed
122
+ number = numFraction(cleaned);
123
+ } else {
124
+ number = parseFloat(cleaned);
125
+ }
126
+ if (isNaN(number)) {
127
+ result = defaultValue;
128
+ } else if (minimum && number < minimum) {
129
+ result = minimum;
130
+ } else {
131
+ result = number;
132
+ }
133
+ }
134
+ return result;
135
+ };
136
+
137
+ export const validNumber = (value) => {
138
+ return isValidNum(value);
139
+ };
140
+
141
+ export const toNum = (value) => {
142
+ const asNumber = toNumber(value);
143
+ return value === '' || isNaN(asNumber) ? '' : asNumber;
144
+ };
145
+
146
+ export const isLessThanMax = (value, max) => {
147
+ return (
148
+ value === undefined || max === undefined || Number(value) < Number(max)
149
+ );
150
+ };
151
+
152
+ export const isGreaterThanMin = (value, min) => {
153
+ return (
154
+ value === undefined || min === undefined || Number(value) > Number(min)
155
+ );
156
+ };
157
+
158
+ /**
159
+ * Truncates a number to the specified decimal digits.
160
+ * Truncate refers to shaving digits off a number without rounding it.
161
+ * @param {Number} number
162
+ * @param {Number} digits
163
+ * @returns {Number}
164
+ */
165
+ export const truncateDecimals = (number, digits) => {
166
+ const multiplier = 10 ** digits;
167
+ const adjustedNum = number * multiplier;
168
+ const truncatedNum = Math[adjustedNum < 0 ? 'ceil' : 'floor'](adjustedNum);
169
+
170
+ return truncatedNum / multiplier;
171
+ };
172
+
173
+ /**
174
+ *
175
+ * @param {'x'|'y'} axisType
176
+ * @param {number} [index] - axis index; optional, 0 by default
177
+ * @param {boolean} [hasMultiAxes] - optional, false by default
178
+ * @return {string} - e.g. x if chart has singular axes; x1, x2 - in case of multiple axes
179
+ */
180
+ export const generateAxisId = (axisType, index = 0, hasMultiAxes = false) => {
181
+ const i = hasMultiAxes ? index + 1 : '';
182
+ return `${axisType}${i}`;
183
+ };
184
+
185
+ /**
186
+ Get axis type from a key string.
187
+ @param {string} string - The key string to extract from.
188
+ @returns {string} e.g. x1 => x
189
+ */
190
+ export const getAxisTypeFromKey = (string) => {
191
+ return string.match(/[^0-9/]+/gi)[0];
192
+ };