@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.
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/index.js +13 -0
- package/package.json +100 -0
- package/release-notes.md +178 -0
- package/src/assets/icons/line-and-point.svg +1 -0
- package/src/assets/icons/line-only.svg +1 -0
- package/src/assets/icons/list-hide.svg +1 -0
- package/src/assets/icons/point-only.svg +1 -0
- package/src/components/bar-chart/bar-chart-prop-types.js +188 -0
- package/src/components/bar-chart/bar-chart.interface.ts +84 -0
- package/src/components/bar-chart/bar-chart.jsx +243 -0
- package/src/components/bar-chart/bar-chart.module.less +61 -0
- package/src/components/bar-chart/get-bar-chart-data-labels.js +42 -0
- package/src/components/bar-chart/get-bar-chart-scales.js +123 -0
- package/src/components/bar-chart/get-bar-chart-tooltips.js +100 -0
- package/src/components/controls/axes-options/axes-options-form-state.js +95 -0
- package/src/components/controls/axes-options/axes-options.jsx +166 -0
- package/src/components/controls/controls.jsx +104 -0
- package/src/components/controls/controls.module.less +12 -0
- package/src/components/controls/drag-options.jsx +77 -0
- package/src/components/controls/legend-options.jsx +25 -0
- package/src/components/controls/line-options.jsx +54 -0
- package/src/components/line-chart/axis-scales/axis-scales.js +165 -0
- package/src/components/line-chart/datalabels-alignment/get-alignment-condition.js +13 -0
- package/src/components/line-chart/datalabels-alignment/get-alignment-data.js +20 -0
- package/src/components/line-chart/datalabels-alignment/get-datalabels-position.js +25 -0
- package/src/components/line-chart/get-axes-ranges-from-chart.js +10 -0
- package/src/components/line-chart/get-line-chart-data-labels.js +21 -0
- package/src/components/line-chart/get-line-chart-scales.js +120 -0
- package/src/components/line-chart/get-line-chart-tooltips.js +91 -0
- package/src/components/line-chart/line-chart-consts.js +7 -0
- package/src/components/line-chart/line-chart-prop-types.js +212 -0
- package/src/components/line-chart/line-chart-utils.js +192 -0
- package/src/components/line-chart/line-chart.interface.ts +107 -0
- package/src/components/line-chart/line-chart.jsx +531 -0
- package/src/components/line-chart/line-chart.minor-gridlines-plugin.js +88 -0
- package/src/components/line-chart/line-chart.module.less +77 -0
- package/src/components/line-chart/state/action-types.js +11 -0
- package/src/components/line-chart/state/initial-state.js +69 -0
- package/src/components/line-chart/state/line-chart-reducer.js +101 -0
- package/src/components/pie-chart/pie-chart-prop-types.js +111 -0
- package/src/components/pie-chart/pie-chart-utils.js +32 -0
- package/src/components/pie-chart/pie-chart.interface.ts +61 -0
- package/src/components/pie-chart/pie-chart.jsx +450 -0
- package/src/components/pie-chart/pie-chart.module.less +61 -0
- package/src/components/scatter-chart/scatter-chart.intefrace.ts +33 -0
- package/src/components/scatter-chart/scatter-chart.jsx +21 -0
- package/src/components/scatter-chart/scatter-chart.module.less +4 -0
- package/src/helpers/chart-border-plugin.js +19 -0
- package/src/helpers/chart-consts.js +62 -0
- package/src/helpers/chart-interface.ts +76 -0
- package/src/helpers/chart-utils.js +183 -0
- package/src/helpers/container.jsx +60 -0
- package/src/helpers/disabled-context.js +8 -0
- package/src/helpers/enums.js +87 -0
- package/src/helpers/get-chart-annotation.js +143 -0
- package/src/helpers/get-custom-legend-plugin-example.js +80 -0
- package/src/helpers/numbers/numbers.js +44 -0
- package/src/helpers/range/estimate-data-series-have-close-values.js +54 -0
- package/src/helpers/range/range.js +95 -0
- package/src/helpers/styles.js +68 -0
- package/src/helpers/text.js +6 -0
- package/src/style/external.less +4 -0
- package/src/style/fonts/lato/Lato-Bold.woff2 +0 -0
- package/src/style/fonts/lato/Lato-BoldItalic.woff2 +0 -0
- package/src/style/fonts/lato/Lato-Italic.woff2 +0 -0
- package/src/style/fonts/lato/Lato-Regular.woff2 +0 -0
- package/src/style/fonts.less +27 -0
- package/src/style/global.less +43 -0
- package/src/style/reset/reset.less +28 -0
- package/src/style/shared.less +24 -0
- package/src/style/variables.less +91 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const MINOR_TICKS_PER_MAJOR = 10;
|
|
2
|
+
|
|
3
|
+
// Return largest gap between ticks
|
|
4
|
+
// (Tick distance may not be consistent if ranges are custom)
|
|
5
|
+
export const getLargestMajorTickWidth = (majorTickPositions) => {
|
|
6
|
+
return majorTickPositions.reduce((acc, curr, index) => {
|
|
7
|
+
if (index === 0) return acc;
|
|
8
|
+
const gap = Math.abs(curr - majorTickPositions[index - 1]);
|
|
9
|
+
return Math.max(gap, acc);
|
|
10
|
+
}, 0);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// Check if position is in visible part of axis scale
|
|
14
|
+
// Check position does not duplicate a major tick
|
|
15
|
+
export const isValidPosition = (
|
|
16
|
+
minorTickPosition,
|
|
17
|
+
majorTickPositions,
|
|
18
|
+
scale,
|
|
19
|
+
) => {
|
|
20
|
+
const { axis, left, top, right, bottom } = scale;
|
|
21
|
+
const isHorizontal = axis === 'x';
|
|
22
|
+
const start = isHorizontal ? left : top;
|
|
23
|
+
const end = isHorizontal ? right : bottom;
|
|
24
|
+
const isAfterStart = minorTickPosition > start;
|
|
25
|
+
const isBeforeEnd = minorTickPosition < end;
|
|
26
|
+
const isDuplicate = majorTickPositions.indexOf(minorTickPosition) !== -1;
|
|
27
|
+
return isAfterStart && isBeforeEnd && !isDuplicate;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Generate minor tick positions for a given axis/scale
|
|
31
|
+
// (Uses second tick as starting point in case first tick is an irregular custom value)
|
|
32
|
+
export const getMinorTickPositions = (majorTickPositions, scale) => {
|
|
33
|
+
const sortedMajorTickPositions = majorTickPositions.sort((a, b) => {
|
|
34
|
+
return a - b;
|
|
35
|
+
});
|
|
36
|
+
const minorTickWidth = getLargestMajorTickWidth(majorTickPositions) / 10;
|
|
37
|
+
const startPosition = majorTickPositions[0];
|
|
38
|
+
const numMinorTicks = (majorTickPositions.length + 1) * MINOR_TICKS_PER_MAJOR;
|
|
39
|
+
const positions = [...Array(numMinorTicks)]
|
|
40
|
+
.map((_, index) => {
|
|
41
|
+
const minorTickPosition =
|
|
42
|
+
startPosition + (index - MINOR_TICKS_PER_MAJOR + 1) * minorTickWidth;
|
|
43
|
+
return parseFloat(minorTickPosition.toFixed(1));
|
|
44
|
+
})
|
|
45
|
+
.filter((position) =>
|
|
46
|
+
isValidPosition(position, sortedMajorTickPositions, scale),
|
|
47
|
+
);
|
|
48
|
+
return positions;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const drawMinorTicksForScale = (scale) => {
|
|
52
|
+
const { chart, ctx } = scale;
|
|
53
|
+
if (!chart.config._config.options.scales[scale.id].grid.drawOnChartArea)
|
|
54
|
+
return;
|
|
55
|
+
if (chart.config._config.options.indexAxis === scale.axis) return;
|
|
56
|
+
const isHorizontal = scale.axis === 'x';
|
|
57
|
+
const majorTickPositions = scale.ticks
|
|
58
|
+
.map((_, index) => scale.getPixelForTick(index))
|
|
59
|
+
.sort((a, b) => a - b);
|
|
60
|
+
const minorTickPositions = getMinorTickPositions(majorTickPositions, scale);
|
|
61
|
+
ctx.save();
|
|
62
|
+
ctx.strokeStyle =
|
|
63
|
+
chart.config._config.options.scales[scale.id].grid.color ||
|
|
64
|
+
'rgba(0,0,0,0.06)';
|
|
65
|
+
ctx.lineWidth = 0.5;
|
|
66
|
+
minorTickPositions.forEach((minorTickPosition) => {
|
|
67
|
+
ctx.beginPath();
|
|
68
|
+
if (isHorizontal) {
|
|
69
|
+
const { top, bottom } = chart.chartArea;
|
|
70
|
+
ctx.moveTo(minorTickPosition, top);
|
|
71
|
+
ctx.lineTo(minorTickPosition, bottom);
|
|
72
|
+
} else {
|
|
73
|
+
const { left, right } = chart.chartArea;
|
|
74
|
+
ctx.moveTo(left, minorTickPosition);
|
|
75
|
+
ctx.lineTo(right, minorTickPosition);
|
|
76
|
+
}
|
|
77
|
+
ctx.stroke();
|
|
78
|
+
});
|
|
79
|
+
ctx.restore();
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const chartMinorGridlinesPlugin = {
|
|
83
|
+
id: 'minorGridlines',
|
|
84
|
+
beforeDatasetsDraw: (chart) => {
|
|
85
|
+
const { scales } = chart;
|
|
86
|
+
Object.keys(scales).forEach((id) => drawMinorTicksForScale(scales[id]));
|
|
87
|
+
},
|
|
88
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
html[data-theme='dark'] .chart canvas {
|
|
2
|
+
// Flip chart colors if dark mode enabled
|
|
3
|
+
filter: invert(1) hue-rotate(180deg);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.chart {
|
|
7
|
+
border: 1px solid rgba(255, 255, 255, 0);
|
|
8
|
+
position: relative;
|
|
9
|
+
display: flex;
|
|
10
|
+
flex-direction: column;
|
|
11
|
+
gap: 8px; // Spacing between each section
|
|
12
|
+
|
|
13
|
+
.canvas {
|
|
14
|
+
flex-grow: 1;
|
|
15
|
+
min-height: 0; // Prevents chart exceeding available space
|
|
16
|
+
canvas {
|
|
17
|
+
width: 100% !important; // Fix for resizing bug
|
|
18
|
+
height: 100% !important; // Remove if stretched when maintainAspectRatio=true
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
&.fixedHeight {
|
|
23
|
+
display: flex;
|
|
24
|
+
align-items: flex-start;
|
|
25
|
+
justify-content: flex-start;
|
|
26
|
+
height: auto;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&.stretchHeight {
|
|
30
|
+
display: flex;
|
|
31
|
+
align-items: stretch;
|
|
32
|
+
justify-content: stretch;
|
|
33
|
+
height: 100%;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
&.squareAspectRatio {
|
|
37
|
+
aspect-ratio: 1;
|
|
38
|
+
min-height: 0;
|
|
39
|
+
min-width: 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&:focus {
|
|
43
|
+
// border: 1px solid #85b7d9;
|
|
44
|
+
outline: none; // Remove dotted outline on FF
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
&::-moz-focus-inner {
|
|
48
|
+
border: 0; // Remove dotted outline on FF
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.zoomForm {
|
|
53
|
+
position: absolute;
|
|
54
|
+
display: flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
justify-content: center;
|
|
57
|
+
top: 0;
|
|
58
|
+
right: 0;
|
|
59
|
+
|
|
60
|
+
.zoomReset {
|
|
61
|
+
margin-left: 10px;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.help {
|
|
65
|
+
margin-left: 5px;
|
|
66
|
+
line-height: 0; // Strip whitespace from icon
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.autoWeight {
|
|
71
|
+
width: auto;
|
|
72
|
+
height: auto;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.table {
|
|
76
|
+
overflow: auto;
|
|
77
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const TOGGLE_ZOOM = 'TOGGLE_ZOOM';
|
|
2
|
+
export const TOGGLE_PAN = 'TOGGLE_PAN';
|
|
3
|
+
export const TOGGLE_POINTS = 'TOGGLE_POINTS';
|
|
4
|
+
export const TOGGLE_LINE = 'TOGGLE_LINE';
|
|
5
|
+
export const TOGGLE_LEGEND = 'TOGGLE_LEGEND';
|
|
6
|
+
export const SET_POINTS_ZOOM_DEFAULTS = 'SET_POINTS_ZOOM_DEFAULTS';
|
|
7
|
+
export const TOGGLE_ANNOTATION = 'TOGGLE_ANNOTATION';
|
|
8
|
+
export const TOGGLE_TABLE = 'TOGGLE_TABLE';
|
|
9
|
+
export const SAVE_INITIAL_AXES_RANGES = 'SAVE_INITIAL_AXES_RANGES';
|
|
10
|
+
export const RESET_AXES_RANGES = 'RESET_AXES_RANGES';
|
|
11
|
+
export const UPDATE_AXES_RANGES = 'UPDATE_AXES_RANGES';
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { AxisType } from '../../../helpers/enums';
|
|
2
|
+
import { setAnnotations } from '../../../helpers/chart-utils';
|
|
3
|
+
import { generateAxisId } from '../line-chart-utils';
|
|
4
|
+
|
|
5
|
+
const initialState = ({
|
|
6
|
+
axes,
|
|
7
|
+
enableZoom,
|
|
8
|
+
enablePan,
|
|
9
|
+
showPoints,
|
|
10
|
+
showLine,
|
|
11
|
+
legendDisplay,
|
|
12
|
+
annotationsData,
|
|
13
|
+
customAxesRange,
|
|
14
|
+
}) => {
|
|
15
|
+
/**
|
|
16
|
+
* getStateAxesByType
|
|
17
|
+
* @param {'x'|'y'} axisType
|
|
18
|
+
* @param {Object} customAxesRange
|
|
19
|
+
* @return {{id: string}[] | []} returns array of objects describing all chart axis or empty array
|
|
20
|
+
*/
|
|
21
|
+
const getStateAxesByType = (axisType, customAxesRange) => {
|
|
22
|
+
if (!axes[axisType]) {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (axes[axisType]?.length > 1) {
|
|
27
|
+
return axes[axisType].map((axisObj, index) => {
|
|
28
|
+
const id = generateAxisId(axisType, index, axes[axisType].length > 1);
|
|
29
|
+
const customMin = customAxesRange?.[id]?.min;
|
|
30
|
+
const customMax = customAxesRange?.[id]?.max;
|
|
31
|
+
return {
|
|
32
|
+
id,
|
|
33
|
+
//only add custom axis ranges if defined:
|
|
34
|
+
...(customMin ? { min: customMin } : {}),
|
|
35
|
+
...(customMax ? { max: customMax } : {}),
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
} else {
|
|
39
|
+
const id = generateAxisId(axisType);
|
|
40
|
+
const customMin = customAxesRange?.[id]?.min;
|
|
41
|
+
const customMax = customAxesRange?.[id]?.max;
|
|
42
|
+
return [
|
|
43
|
+
{
|
|
44
|
+
id,
|
|
45
|
+
//only add custom axis ranges if defined:
|
|
46
|
+
...(customMin ? { min: customMin } : {}),
|
|
47
|
+
...(customMax ? { max: customMax } : {}),
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const xStateAxes = getStateAxesByType(AxisType.X, customAxesRange);
|
|
54
|
+
const yStateAxes = getStateAxesByType(AxisType.Y, customAxesRange);
|
|
55
|
+
const stateAxes = [...xStateAxes, ...yStateAxes];
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
zoomEnabled: enableZoom,
|
|
59
|
+
panEnabled: true, // TODO: work out why this logic doesn't work, workaround wih dispatch is currently used
|
|
60
|
+
pointsEnabled: showPoints,
|
|
61
|
+
lineEnabled: showLine,
|
|
62
|
+
legendEnabled: legendDisplay !== false,
|
|
63
|
+
axes: stateAxes,
|
|
64
|
+
showAnnotationLineIndex: setAnnotations(annotationsData),
|
|
65
|
+
showTable: false,
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export default initialState;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { produce } from 'immer';
|
|
2
|
+
import {
|
|
3
|
+
TOGGLE_PAN,
|
|
4
|
+
TOGGLE_ZOOM,
|
|
5
|
+
TOGGLE_POINTS,
|
|
6
|
+
TOGGLE_LINE,
|
|
7
|
+
TOGGLE_LEGEND,
|
|
8
|
+
SET_POINTS_ZOOM_DEFAULTS,
|
|
9
|
+
TOGGLE_ANNOTATION,
|
|
10
|
+
TOGGLE_TABLE,
|
|
11
|
+
SAVE_INITIAL_AXES_RANGES,
|
|
12
|
+
UPDATE_AXES_RANGES,
|
|
13
|
+
RESET_AXES_RANGES,
|
|
14
|
+
} from './action-types';
|
|
15
|
+
|
|
16
|
+
export const reducer = (state, action) => {
|
|
17
|
+
const newState = { ...state };
|
|
18
|
+
switch (action.type) {
|
|
19
|
+
case TOGGLE_ZOOM: {
|
|
20
|
+
newState.zoomEnabled = !newState.zoomEnabled;
|
|
21
|
+
if (newState.panEnabled) {
|
|
22
|
+
newState.panEnabled = false;
|
|
23
|
+
}
|
|
24
|
+
return newState;
|
|
25
|
+
}
|
|
26
|
+
case TOGGLE_PAN: {
|
|
27
|
+
newState.panEnabled = !newState.panEnabled;
|
|
28
|
+
if (newState.zoomEnabled) {
|
|
29
|
+
newState.zoomEnabled = false;
|
|
30
|
+
}
|
|
31
|
+
return newState;
|
|
32
|
+
}
|
|
33
|
+
case TOGGLE_POINTS: {
|
|
34
|
+
return {
|
|
35
|
+
...newState,
|
|
36
|
+
pointsEnabled: !newState.pointsEnabled,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
case TOGGLE_LINE: {
|
|
40
|
+
return {
|
|
41
|
+
...newState,
|
|
42
|
+
lineEnabled: !newState.lineEnabled,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
case TOGGLE_LEGEND: {
|
|
46
|
+
return {
|
|
47
|
+
...newState,
|
|
48
|
+
legendEnabled: !newState.legendEnabled,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
case TOGGLE_TABLE: {
|
|
52
|
+
return {
|
|
53
|
+
...newState,
|
|
54
|
+
showTable: !newState.showTable,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
case SAVE_INITIAL_AXES_RANGES: {
|
|
58
|
+
return produce(state, (draft) => {
|
|
59
|
+
const { initialAxesRanges } = action.payload;
|
|
60
|
+
draft.initialAxesRanges = initialAxesRanges;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
case UPDATE_AXES_RANGES: {
|
|
64
|
+
return produce(state, (draft) => {
|
|
65
|
+
const { axes } = action.payload;
|
|
66
|
+
draft.axes = axes;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
case RESET_AXES_RANGES: {
|
|
70
|
+
return produce(state, (draft) => {
|
|
71
|
+
const { axes } = state;
|
|
72
|
+
draft.axes = axes.map((axis) => ({
|
|
73
|
+
id: axis.id,
|
|
74
|
+
}));
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
case SET_POINTS_ZOOM_DEFAULTS:
|
|
78
|
+
const { showPoints, enableZoom, enablePan, showLine } = action.payload;
|
|
79
|
+
return {
|
|
80
|
+
...newState,
|
|
81
|
+
zoomEnabled: enableZoom,
|
|
82
|
+
pointsEnabled: showPoints,
|
|
83
|
+
lineEnabled: showLine,
|
|
84
|
+
panEnabled: enablePan,
|
|
85
|
+
};
|
|
86
|
+
case TOGGLE_ANNOTATION:
|
|
87
|
+
const { annotationIndex } = action.payload;
|
|
88
|
+
const updatedIndexes = newState.showAnnotationLineIndex.includes(
|
|
89
|
+
annotationIndex,
|
|
90
|
+
)
|
|
91
|
+
? newState.showAnnotationLineIndex.filter((v) => v !== annotationIndex)
|
|
92
|
+
: [...newState.showAnnotationLineIndex, annotationIndex];
|
|
93
|
+
return {
|
|
94
|
+
...newState,
|
|
95
|
+
showAnnotationLineIndex: updatedIndexes,
|
|
96
|
+
};
|
|
97
|
+
default: {
|
|
98
|
+
return newState;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import PropTypes from 'prop-types';
|
|
2
|
+
|
|
3
|
+
export const PieChartPropTypes = {
|
|
4
|
+
chart: PropTypes.shape({
|
|
5
|
+
testId: PropTypes.string,
|
|
6
|
+
data: PropTypes.shape({
|
|
7
|
+
labels: PropTypes.arrayOf(PropTypes.string),
|
|
8
|
+
datasets: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
9
|
+
}).isRequired,
|
|
10
|
+
options: PropTypes.shape({
|
|
11
|
+
title: PropTypes.oneOfType([
|
|
12
|
+
PropTypes.string,
|
|
13
|
+
PropTypes.arrayOf(PropTypes.string),
|
|
14
|
+
]),
|
|
15
|
+
chartStyling: PropTypes.shape({
|
|
16
|
+
width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
17
|
+
height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
18
|
+
maintainAspectRatio: PropTypes.bool,
|
|
19
|
+
staticChartHeight: PropTypes.bool,
|
|
20
|
+
performanceMode: PropTypes.bool,
|
|
21
|
+
}),
|
|
22
|
+
tooltip: PropTypes.shape({
|
|
23
|
+
tooltips: PropTypes.bool,
|
|
24
|
+
showLabelsInTooltips: PropTypes.bool,
|
|
25
|
+
}),
|
|
26
|
+
graph: PropTypes.shape({
|
|
27
|
+
showDataLabels: PropTypes.bool,
|
|
28
|
+
stacked: PropTypes.bool,
|
|
29
|
+
cutout: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
30
|
+
}),
|
|
31
|
+
legend: PropTypes.shape({
|
|
32
|
+
display: PropTypes.bool,
|
|
33
|
+
position: PropTypes.oneOf(['top', 'bottom', 'right']),
|
|
34
|
+
align: PropTypes.oneOf(['start', 'center', 'end']),
|
|
35
|
+
useDataset: PropTypes.bool,
|
|
36
|
+
}),
|
|
37
|
+
chartOptions: PropTypes.shape({
|
|
38
|
+
enableZoom: PropTypes.bool,
|
|
39
|
+
enablePan: PropTypes.bool,
|
|
40
|
+
}),
|
|
41
|
+
interactions: PropTypes.shape({
|
|
42
|
+
onLegendClick: PropTypes.func,
|
|
43
|
+
onPieHover: PropTypes.func,
|
|
44
|
+
onPieUnhover: PropTypes.func,
|
|
45
|
+
}),
|
|
46
|
+
}),
|
|
47
|
+
}).isRequired,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const getDefaultProps = (props) => {
|
|
51
|
+
// Add missing nested objects
|
|
52
|
+
props.chart.options = props.chart.options || {};
|
|
53
|
+
props.chart.options.chartStyling = props.chart.options.chartStyling || {};
|
|
54
|
+
props.chart.options.tooltip = props.chart.options.tooltip || {};
|
|
55
|
+
props.chart.options.graph = props.chart.options.graph || {};
|
|
56
|
+
props.chart.options.legend = props.chart.options.legend || {};
|
|
57
|
+
props.chart.options.chartOptions = props.chart.options.chartOptions || {};
|
|
58
|
+
props.chart.options.interactions = props.chart.options.interactions || {};
|
|
59
|
+
// Set defaults for missing properties
|
|
60
|
+
const chart = {
|
|
61
|
+
testId: props.chart.testId ?? null,
|
|
62
|
+
data: props.chart.data,
|
|
63
|
+
options: {
|
|
64
|
+
title: props.chart.options.title || '',
|
|
65
|
+
chartStyling: {
|
|
66
|
+
width: props.chart.options.chartStyling.width,
|
|
67
|
+
height: props.chart.options.chartStyling.height,
|
|
68
|
+
maintainAspectRatio:
|
|
69
|
+
props.chart.options.chartStyling.maintainAspectRatio || false,
|
|
70
|
+
staticChartHeight:
|
|
71
|
+
props.chart.options.chartStyling.staticChartHeight || false,
|
|
72
|
+
performanceMode:
|
|
73
|
+
props.chart.options.chartStyling.performanceMode != null
|
|
74
|
+
? props.chart.options.chartStyling.performanceMode
|
|
75
|
+
: true,
|
|
76
|
+
},
|
|
77
|
+
tooltip: {
|
|
78
|
+
tooltips:
|
|
79
|
+
props.chart.options.tooltip.tooltips != null
|
|
80
|
+
? props.chart.options.tooltip.tooltips
|
|
81
|
+
: true,
|
|
82
|
+
showLabelsInTooltips:
|
|
83
|
+
props.chart.options.tooltip.showLabelsInTooltips || false,
|
|
84
|
+
},
|
|
85
|
+
graph: {
|
|
86
|
+
showDataLabels: props.chart.options.graph.showDataLabels || false,
|
|
87
|
+
stacked: props.chart.options.graph.stacked || false,
|
|
88
|
+
cutout: props.chart.options.graph.cutout || 0,
|
|
89
|
+
},
|
|
90
|
+
legend: {
|
|
91
|
+
display:
|
|
92
|
+
props.chart.options.legend.display != null
|
|
93
|
+
? props.chart.options.legend.display
|
|
94
|
+
: true,
|
|
95
|
+
useDataset: props.chart.options.legend.useDataset || false,
|
|
96
|
+
position: props.chart.options.legend.position || 'bottom',
|
|
97
|
+
align: props.chart.options.legend.align || 'center',
|
|
98
|
+
},
|
|
99
|
+
chartOptions: {
|
|
100
|
+
enableZoom: props.chart.options.chartOptions.enableZoom || false,
|
|
101
|
+
enablePan: props.chart.options.chartOptions.enablePan || false,
|
|
102
|
+
},
|
|
103
|
+
interactions: {
|
|
104
|
+
onLegendClick: props.chart.options.interactions.onLegendClick,
|
|
105
|
+
onPieHover: props.chart.options.interactions.onPieHover,
|
|
106
|
+
onPieUnhover: props.chart.options.interactions.onPieUnhover,
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
return chart;
|
|
111
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export const colors = [
|
|
2
|
+
'#3366cc',
|
|
3
|
+
'#dc3912',
|
|
4
|
+
'#ff9900',
|
|
5
|
+
'#109618',
|
|
6
|
+
'#990099',
|
|
7
|
+
'#0099c6',
|
|
8
|
+
'#dd4477',
|
|
9
|
+
'#66aa00',
|
|
10
|
+
'#b82e2e',
|
|
11
|
+
'#316395',
|
|
12
|
+
'#994499',
|
|
13
|
+
'#22aa99',
|
|
14
|
+
'#aaaa11',
|
|
15
|
+
'#6633cc',
|
|
16
|
+
'#e67300',
|
|
17
|
+
'#8b0707',
|
|
18
|
+
'#651067',
|
|
19
|
+
'#329262',
|
|
20
|
+
'#5574a6',
|
|
21
|
+
'#3b3eac',
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
export const generateRandomColor = () => {
|
|
25
|
+
const color = `#${Math.floor(Math.random() * 16777215).toString(16)}`;
|
|
26
|
+
if (colors.includes(color)) {
|
|
27
|
+
return generateRandomColor();
|
|
28
|
+
} else {
|
|
29
|
+
colors.push(color);
|
|
30
|
+
return color;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export interface IChartInteractions {
|
|
2
|
+
onLegendClick: () => any;
|
|
3
|
+
onPointHover: () => any;
|
|
4
|
+
onPointUnhover: () => any;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface IChartOptions {
|
|
8
|
+
enableZoom: boolean;
|
|
9
|
+
enablePan: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface IChartLegend {
|
|
13
|
+
display: boolean;
|
|
14
|
+
position: 'top' | 'bottom' | 'right';
|
|
15
|
+
align: 'start' | 'center' | 'end';
|
|
16
|
+
useDataset: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface IChartGraph {
|
|
20
|
+
showDataLabels: boolean;
|
|
21
|
+
stacked: boolean;
|
|
22
|
+
cutout: number | string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface IChartTooltip {
|
|
26
|
+
tooltips: boolean;
|
|
27
|
+
showLabelsInTooltips: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface IChartStyling {
|
|
31
|
+
width: number | string;
|
|
32
|
+
height: number | string;
|
|
33
|
+
maintainAspectRatio: boolean;
|
|
34
|
+
staticChartHeight: boolean;
|
|
35
|
+
performanceMode: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface IOptions {
|
|
39
|
+
title: string | string[];
|
|
40
|
+
chartStyling: IChartStyling;
|
|
41
|
+
tooltip: IChartTooltip;
|
|
42
|
+
graph: IChartGraph;
|
|
43
|
+
legend: IChartLegend;
|
|
44
|
+
chartOptions: IChartOptions;
|
|
45
|
+
interactions: IChartInteractions;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface IChartData {
|
|
49
|
+
labels: string;
|
|
50
|
+
datasets: any[];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface IChartData {
|
|
54
|
+
testId: string | null;
|
|
55
|
+
data: IChartData;
|
|
56
|
+
options: IOptions;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface IPieChartProps {
|
|
60
|
+
chart: IChartData;
|
|
61
|
+
}
|