@oliasoft-open-source/charts-library 2.17.6 → 2.18.0-beta-2
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/dist/index.js +40398 -0
- package/dist/style.css +177 -0
- package/package.json +26 -34
- package/index.js +0 -14
- package/release-notes.md +0 -310
- package/src/assets/icons/line-and-point.svg +0 -1
- package/src/assets/icons/line-only.svg +0 -1
- package/src/assets/icons/list-hide.svg +0 -1
- package/src/assets/icons/point-only.svg +0 -1
- package/src/components/bar-chart/bar-chart-prop-types.js +0 -209
- package/src/components/bar-chart/bar-chart.interface.ts +0 -91
- package/src/components/bar-chart/bar-chart.jsx +0 -247
- package/src/components/bar-chart/bar-chart.module.less +0 -61
- package/src/components/bar-chart/get-bar-chart-data-labels.js +0 -42
- package/src/components/bar-chart/get-bar-chart-scales.js +0 -123
- package/src/components/bar-chart/get-bar-chart-tooltips.js +0 -102
- package/src/components/controls/axes-options/axes-options.jsx +0 -270
- package/src/components/line-chart/constants/default-translations.js +0 -24
- package/src/components/line-chart/constants/line-chart-consts.js +0 -12
- package/src/components/line-chart/controls/axes-options/action-types.js +0 -5
- package/src/components/line-chart/controls/axes-options/axes-options-form-state.js +0 -97
- package/src/components/line-chart/controls/controls.jsx +0 -174
- package/src/components/line-chart/controls/controls.module.less +0 -12
- package/src/components/line-chart/controls/drag-options.jsx +0 -112
- package/src/components/line-chart/controls/legend-options.jsx +0 -36
- package/src/components/line-chart/controls/line-options.jsx +0 -64
- package/src/components/line-chart/hooks/use-chart-functions.js +0 -257
- package/src/components/line-chart/hooks/use-chart-options.js +0 -181
- package/src/components/line-chart/hooks/use-chart-plugins.js +0 -35
- package/src/components/line-chart/hooks/use-toggle-handler.js +0 -33
- package/src/components/line-chart/initialize/config.js +0 -23
- package/src/components/line-chart/initialize/initialize-line-chart.js +0 -25
- package/src/components/line-chart/line-chart-prop-types.js +0 -292
- package/src/components/line-chart/line-chart.interface.ts +0 -121
- package/src/components/line-chart/line-chart.jsx +0 -161
- package/src/components/line-chart/line-chart.module.less +0 -77
- package/src/components/line-chart/plugins/chart-area-text-plugin.js +0 -246
- package/src/components/line-chart/plugins/line-chart.minor-gridlines-plugin.js +0 -88
- package/src/components/line-chart/plugins/plugin-constants.js +0 -11
- package/src/components/line-chart/state/action-types.js +0 -12
- package/src/components/line-chart/state/initial-state.js +0 -89
- package/src/components/line-chart/state/line-chart-reducer.js +0 -100
- package/src/components/line-chart/state/manage-state-in-local-storage.js +0 -86
- package/src/components/line-chart/state/use-chart-state.js +0 -141
- package/src/components/line-chart/utils/axis-scales/axis-scales.js +0 -165
- package/src/components/line-chart/utils/datalabels-alignment/get-alignment-condition.js +0 -13
- package/src/components/line-chart/utils/datalabels-alignment/get-alignment-data.js +0 -20
- package/src/components/line-chart/utils/datalabels-alignment/get-datalabels-position.js +0 -25
- package/src/components/line-chart/utils/generate-line-chart-datasets.js +0 -114
- package/src/components/line-chart/utils/get-axes-ranges-from-chart.js +0 -13
- package/src/components/line-chart/utils/get-line-chart-data-labels.js +0 -21
- package/src/components/line-chart/utils/get-line-chart-scales.js +0 -120
- package/src/components/line-chart/utils/get-line-chart-tooltips.js +0 -94
- package/src/components/line-chart/utils/line-chart-utils.js +0 -77
- package/src/components/line-chart/utils/translations/get-translations.js +0 -17
- package/src/components/pie-chart/pie-chart-prop-types.js +0 -111
- package/src/components/pie-chart/pie-chart-utils.js +0 -32
- package/src/components/pie-chart/pie-chart.interface.ts +0 -61
- package/src/components/pie-chart/pie-chart.jsx +0 -450
- package/src/components/pie-chart/pie-chart.module.less +0 -61
- package/src/components/scatter-chart/scatter-chart.intefrace.ts +0 -33
- package/src/components/scatter-chart/scatter-chart.jsx +0 -21
- package/src/components/scatter-chart/scatter-chart.module.less +0 -4
- package/src/helpers/chart-border-plugin.js +0 -19
- package/src/helpers/chart-consts.js +0 -64
- package/src/helpers/chart-interface.ts +0 -94
- package/src/helpers/chart-utils.js +0 -182
- package/src/helpers/container.jsx +0 -60
- package/src/helpers/disabled-context.js +0 -8
- package/src/helpers/enums.js +0 -96
- package/src/helpers/get-chart-annotation.js +0 -106
- package/src/helpers/get-custom-legend-plugin-example.js +0 -80
- package/src/helpers/get-draggableData.js +0 -32
- package/src/helpers/range/estimate-data-series-have-close-values.js +0 -54
- package/src/helpers/range/range.js +0 -100
- package/src/helpers/text.js +0 -6
- package/src/style/external.less +0 -4
- 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 +0 -27
- package/src/style/global.less +0 -43
- package/src/style/reset/reset.less +0 -28
- package/src/style/shared.less +0 -11
- package/src/style/variables.less +0 -91
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
IChartAnnotations, IChartDraggableData,
|
|
3
|
-
IChartInteractions,
|
|
4
|
-
IChartLegend,
|
|
5
|
-
IChartStyling,
|
|
6
|
-
} from "../../helpers/chart-interface";
|
|
7
|
-
|
|
8
|
-
export interface IChartOptions {
|
|
9
|
-
showPoints: boolean;
|
|
10
|
-
enableZoom: boolean;
|
|
11
|
-
enablePan: boolean;
|
|
12
|
-
closeOnOutsideClick: boolean;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface ILineChartGraph {
|
|
16
|
-
lineTension: number;
|
|
17
|
-
spanGaps: boolean;
|
|
18
|
-
showDataLabels: boolean;
|
|
19
|
-
showMinorGridlines: boolean;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface ILineChartTooltip {
|
|
23
|
-
tooltips: boolean;
|
|
24
|
-
showLabelsInTooltips: boolean;
|
|
25
|
-
hideSimulationName: boolean;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
export interface IChartRange {
|
|
30
|
-
min: number;
|
|
31
|
-
max: number;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface ILineChartAdditionalAxesOptions {
|
|
35
|
-
chartScaleType: 'linear' | 'logarithmic';
|
|
36
|
-
reverse: boolean;
|
|
37
|
-
beginAtZero: boolean;
|
|
38
|
-
stepSize: number;
|
|
39
|
-
truncateAxisNumbersToDigitsCallback: number;
|
|
40
|
-
suggestedMin: number;
|
|
41
|
-
suggestedMax:number;
|
|
42
|
-
range: {
|
|
43
|
-
x: IChartRange;
|
|
44
|
-
y: IChartRange;
|
|
45
|
-
};
|
|
46
|
-
autoAxisPadding: boolean;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface IUnitOptions {
|
|
50
|
-
options: string[],
|
|
51
|
-
selectedUnit: string,
|
|
52
|
-
setSelectedUnit: () => void,
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export interface ILineChartAxis<PositionType> {
|
|
56
|
-
label: string;
|
|
57
|
-
position: PositionType;
|
|
58
|
-
color: string;
|
|
59
|
-
unit: IUnitOptions
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface ILineChartAxes {
|
|
63
|
-
x: ILineChartAxis<'top' | 'bottom'>[];
|
|
64
|
-
y: ILineChartAxis<'left' | 'right'>[];
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export interface IDepthType {
|
|
68
|
-
options: string[],
|
|
69
|
-
selectedUnit: string,
|
|
70
|
-
setSelectedUnit: () => void,
|
|
71
|
-
}
|
|
72
|
-
export interface ILineChartOptions {
|
|
73
|
-
title: string | string[];
|
|
74
|
-
axes: ILineChartAxes;
|
|
75
|
-
additionalAxesOptions: ILineChartAdditionalAxesOptions;
|
|
76
|
-
chartStyling: IChartStyling;
|
|
77
|
-
tooltip: ILineChartTooltip;
|
|
78
|
-
graph: ILineChartGraph;
|
|
79
|
-
annotations: IChartAnnotations;
|
|
80
|
-
legend: IChartLegend;
|
|
81
|
-
chartOptions: IChartOptions;
|
|
82
|
-
interactions: IChartInteractions;
|
|
83
|
-
depthType: IDepthType
|
|
84
|
-
draggableData :IChartDraggableData;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export interface IDataPoint {
|
|
88
|
-
x: number,
|
|
89
|
-
y: number,
|
|
90
|
-
label?: string[]
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export interface ILineChartDataset {
|
|
94
|
-
label?: string,
|
|
95
|
-
lineTension?: number,
|
|
96
|
-
borderColor?: string,
|
|
97
|
-
pointBackgroundColor?: string,
|
|
98
|
-
backgroundColor?: string,
|
|
99
|
-
pointRadius?: number,
|
|
100
|
-
pointHoverRadius?: number,
|
|
101
|
-
pointHitRadius?: number,
|
|
102
|
-
borderWidth?: number,
|
|
103
|
-
fill?: boolean,
|
|
104
|
-
yAxisID?: string,
|
|
105
|
-
formation?: boolean,
|
|
106
|
-
data: IDataPoint[],
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export interface ILineChartData {
|
|
110
|
-
//TODO: revisit data interface definition after project is more stable
|
|
111
|
-
testId: string | null;
|
|
112
|
-
data: {
|
|
113
|
-
labels?: string[],
|
|
114
|
-
datasets: ILineChartDataset[]
|
|
115
|
-
} | any;
|
|
116
|
-
options: ILineChartOptions;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export interface ILineChartProps {
|
|
120
|
-
chart: ILineChartData;
|
|
121
|
-
}
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import React, { useMemo, useReducer, useRef } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
CategoryScale,
|
|
4
|
-
Chart as ChartJS,
|
|
5
|
-
Filler,
|
|
6
|
-
Legend,
|
|
7
|
-
LinearScale,
|
|
8
|
-
LineElement,
|
|
9
|
-
LogarithmicScale,
|
|
10
|
-
PointElement,
|
|
11
|
-
Title,
|
|
12
|
-
Tooltip,
|
|
13
|
-
} from 'chart.js';
|
|
14
|
-
import { Line } from 'react-chartjs-2';
|
|
15
|
-
import zoomPlugin from 'chartjs-plugin-zoom';
|
|
16
|
-
import dataLabelsPlugin from 'chartjs-plugin-datalabels';
|
|
17
|
-
import annotationPlugin from 'chartjs-plugin-annotation';
|
|
18
|
-
import dragDataPlugin from 'chartjs-plugin-dragdata';
|
|
19
|
-
import styles from './line-chart.module.less';
|
|
20
|
-
import { reducer } from './state/line-chart-reducer';
|
|
21
|
-
import initialState from './state/initial-state';
|
|
22
|
-
import Controls from './controls/controls';
|
|
23
|
-
import { getDefaultProps, LineChartPropTypes } from './line-chart-prop-types';
|
|
24
|
-
import { getClassName, setDefaultTheme } from '../../helpers/chart-utils';
|
|
25
|
-
import { AUTO } from '../../helpers/chart-consts';
|
|
26
|
-
import { generateLineChartDatasets } from './utils/generate-line-chart-datasets';
|
|
27
|
-
import { useChartFunctions } from './hooks/use-chart-functions';
|
|
28
|
-
import { useChartOptions } from './hooks/use-chart-options';
|
|
29
|
-
import { useChartPlugins } from './hooks/use-chart-plugins';
|
|
30
|
-
import { generateKey } from './utils/line-chart-utils';
|
|
31
|
-
import { useChartState } from './state/use-chart-state';
|
|
32
|
-
import { chartAreaTextPlugin } from './plugins/chart-area-text-plugin';
|
|
33
|
-
import { getConfig } from './initialize/config';
|
|
34
|
-
|
|
35
|
-
ChartJS.register(
|
|
36
|
-
LinearScale,
|
|
37
|
-
PointElement,
|
|
38
|
-
LineElement,
|
|
39
|
-
CategoryScale,
|
|
40
|
-
LogarithmicScale,
|
|
41
|
-
Legend,
|
|
42
|
-
Tooltip,
|
|
43
|
-
Title,
|
|
44
|
-
Filler,
|
|
45
|
-
zoomPlugin,
|
|
46
|
-
dataLabelsPlugin,
|
|
47
|
-
annotationPlugin,
|
|
48
|
-
dragDataPlugin,
|
|
49
|
-
chartAreaTextPlugin,
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* this is a line chart component
|
|
54
|
-
* @param {import('./line-chart.interface').ILineChartProps} props
|
|
55
|
-
*/
|
|
56
|
-
const LineChart = (props) => {
|
|
57
|
-
setDefaultTheme();
|
|
58
|
-
const chartRef = useRef(null);
|
|
59
|
-
const { table } = props;
|
|
60
|
-
const { translations, languageKey } = getConfig();
|
|
61
|
-
const chart = getDefaultProps(props);
|
|
62
|
-
const {
|
|
63
|
-
data: { datasets },
|
|
64
|
-
options,
|
|
65
|
-
testId,
|
|
66
|
-
persistenceId,
|
|
67
|
-
} = chart;
|
|
68
|
-
const { annotations, axes, chartStyling, graph } = options;
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* @type {[object, import('react').Dispatch<{type: String, payload: any}>]} useReducer
|
|
72
|
-
*/
|
|
73
|
-
const [state, dispatch] = useReducer(
|
|
74
|
-
reducer,
|
|
75
|
-
{
|
|
76
|
-
options,
|
|
77
|
-
persistenceId,
|
|
78
|
-
},
|
|
79
|
-
initialState,
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
const generatedDatasets = useMemo(() => {
|
|
83
|
-
return generateLineChartDatasets(datasets, state, options, translations);
|
|
84
|
-
}, [state.lineEnabled, state.pointsEnabled, axes, annotations, graph]);
|
|
85
|
-
|
|
86
|
-
// Call the custom hooks.
|
|
87
|
-
useChartState({
|
|
88
|
-
chartRef,
|
|
89
|
-
options,
|
|
90
|
-
state,
|
|
91
|
-
generatedDatasets,
|
|
92
|
-
dispatch,
|
|
93
|
-
persistenceId,
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
const { resetZoom, handleKeyDown, handleKeyUp } = useChartFunctions({
|
|
97
|
-
chartRef,
|
|
98
|
-
state,
|
|
99
|
-
options,
|
|
100
|
-
dispatch,
|
|
101
|
-
generatedDatasets,
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
const useOptions = useChartOptions({
|
|
105
|
-
chartRef,
|
|
106
|
-
state,
|
|
107
|
-
options,
|
|
108
|
-
dispatch,
|
|
109
|
-
generatedDatasets,
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
const usePlugins = useChartPlugins({ options, resetZoom });
|
|
113
|
-
|
|
114
|
-
return (
|
|
115
|
-
<div
|
|
116
|
-
key={generateKey([
|
|
117
|
-
state.enableDragPoints,
|
|
118
|
-
state.zoomEnabled,
|
|
119
|
-
state.panEnabled,
|
|
120
|
-
languageKey,
|
|
121
|
-
])}
|
|
122
|
-
className={getClassName(chartStyling, styles)}
|
|
123
|
-
style={{
|
|
124
|
-
width: chartStyling.width || AUTO,
|
|
125
|
-
height: chartStyling.height || AUTO,
|
|
126
|
-
}}
|
|
127
|
-
tabIndex={0} //eslint-disable-line jsx-a11y/no-noninteractive-tabindex
|
|
128
|
-
onKeyDown={handleKeyDown}
|
|
129
|
-
onKeyUp={handleKeyUp}
|
|
130
|
-
data-testid={testId}
|
|
131
|
-
>
|
|
132
|
-
<Controls
|
|
133
|
-
props={props}
|
|
134
|
-
chartRef={chartRef}
|
|
135
|
-
state={state}
|
|
136
|
-
options={options}
|
|
137
|
-
dispatch={dispatch}
|
|
138
|
-
generatedDatasets={generatedDatasets}
|
|
139
|
-
translations={translations}
|
|
140
|
-
/>
|
|
141
|
-
{table && state.showTable ? (
|
|
142
|
-
<div className={styles.table}>{table}</div>
|
|
143
|
-
) : (
|
|
144
|
-
<div className={styles.canvas}>
|
|
145
|
-
<Line
|
|
146
|
-
ref={chartRef}
|
|
147
|
-
data={{
|
|
148
|
-
datasets: generatedDatasets,
|
|
149
|
-
}}
|
|
150
|
-
options={useOptions}
|
|
151
|
-
plugins={usePlugins}
|
|
152
|
-
/>
|
|
153
|
-
</div>
|
|
154
|
-
)}
|
|
155
|
-
</div>
|
|
156
|
-
);
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
LineChart.propTypes = LineChartPropTypes;
|
|
160
|
-
|
|
161
|
-
export { LineChart };
|
|
@@ -1,77 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
import { TextLabelPosition } from './plugin-constants';
|
|
2
|
-
import { AlignOptions } from '../../../helpers/enums';
|
|
3
|
-
|
|
4
|
-
const WORD_SEPARATOR = ' ';
|
|
5
|
-
const SEMI_TRANSPARENT = 'rgba(0, 0, 0, 0.5)';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Splits the input text into words based on the predefined WORD_SEPARATOR.
|
|
9
|
-
* If the input is an array, it first joins the array and then splits it.
|
|
10
|
-
*
|
|
11
|
-
* @param {string | string[]} text - The text to split into words.
|
|
12
|
-
* @returns {string[]} An array of words.
|
|
13
|
-
*/
|
|
14
|
-
const getWords = (text) => {
|
|
15
|
-
return (Array.isArray(text) ? text.join(WORD_SEPARATOR) : text).split(
|
|
16
|
-
WORD_SEPARATOR,
|
|
17
|
-
);
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Renders the lines of text on the canvas context.
|
|
22
|
-
* It iterates over the array of lines and renders each line with the provided styling.
|
|
23
|
-
*
|
|
24
|
-
* @param {CanvasRenderingContext2D} ctx - The canvas rendering context to draw on.
|
|
25
|
-
* @param {string[]} lines - The array of lines to be rendered.
|
|
26
|
-
* @param {number} lineHeight - The height of each line.
|
|
27
|
-
* @param {number} x - The x-coordinate of the starting position.
|
|
28
|
-
* @param {number} y - The y-coordinate of the starting position.
|
|
29
|
-
* @param {string} position - The position for the text (one of the values from the TextLabelPosition enum).
|
|
30
|
-
*/
|
|
31
|
-
const drawText = (ctx, lines, lineHeight, x, y, position) => {
|
|
32
|
-
lines.forEach((line, index) => {
|
|
33
|
-
const lineY = position.includes('top')
|
|
34
|
-
? y + lineHeight * (index + 1) - 5
|
|
35
|
-
: y - (lines.length - 1 - index) * lineHeight;
|
|
36
|
-
ctx.fillText(line, x, lineY);
|
|
37
|
-
});
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Calculates the maximum width for the text based on the initial maximum width
|
|
42
|
-
* and the chart area width.
|
|
43
|
-
* @param {number} initialMaxWidth - The initial maximum width.
|
|
44
|
-
* @param {number} chartAreaWidth - The width of the chart area.
|
|
45
|
-
* @returns {number} The updated maximum width.
|
|
46
|
-
*/
|
|
47
|
-
const calculateMaxWidth = (initialMaxWidth, chartAreaWidth) => {
|
|
48
|
-
const factorMiddle = 0.5;
|
|
49
|
-
const factorSmall = 0.7;
|
|
50
|
-
const maxWidthFactor =
|
|
51
|
-
chartAreaWidth < 500
|
|
52
|
-
? factorMiddle
|
|
53
|
-
: chartAreaWidth < 700
|
|
54
|
-
? factorSmall
|
|
55
|
-
: 1;
|
|
56
|
-
return initialMaxWidth * maxWidthFactor;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Determines the legend dimensions (width and height) based on its position.
|
|
61
|
-
*
|
|
62
|
-
* @param {object} chart - The Chart.js chart object.
|
|
63
|
-
* @returns {object} An object containing the legend width and height.
|
|
64
|
-
*/
|
|
65
|
-
const getLegendDimensions = (chart) => {
|
|
66
|
-
const { legend } = chart;
|
|
67
|
-
|
|
68
|
-
const legendWidth =
|
|
69
|
-
legend && legend.display && legend.options.position === 'left'
|
|
70
|
-
? legend.width + legend.options.labels.padding * 2
|
|
71
|
-
: 0;
|
|
72
|
-
|
|
73
|
-
const legendHeight =
|
|
74
|
-
legend &&
|
|
75
|
-
legend.display &&
|
|
76
|
-
(legend.options.position === 'top' || legend.options.position === 'bottom')
|
|
77
|
-
? legend.height + legend.options.labels.padding * 2
|
|
78
|
-
: 0;
|
|
79
|
-
|
|
80
|
-
return { legendWidth, legendHeight };
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Determines the X and Y coordinates for the provided position.
|
|
85
|
-
*
|
|
86
|
-
* @param {string} position - The position for the text (one of the values from the TextLabelPosition enum).
|
|
87
|
-
* @param {object} chart - The Chart.js chart object.
|
|
88
|
-
* @param {number} xOffset - The horizontal offset from the specified position.
|
|
89
|
-
* @param {number} yOffset - The vertical offset from the specified position.
|
|
90
|
-
* @returns {number[]} An array with the X and Y coordinates.
|
|
91
|
-
*/
|
|
92
|
-
const getPositionCoordinates = (position, chart, xOffset, yOffset) => {
|
|
93
|
-
const { chartArea, width } = chart;
|
|
94
|
-
const temporaryChartAreaRight = width - 8;
|
|
95
|
-
|
|
96
|
-
const { legendWidth, legendHeight } = getLegendDimensions(chart);
|
|
97
|
-
|
|
98
|
-
switch (position) {
|
|
99
|
-
case TextLabelPosition.TOP_LEFT:
|
|
100
|
-
return [
|
|
101
|
-
chartArea.left + xOffset + legendWidth,
|
|
102
|
-
chartArea.top + yOffset + legendHeight,
|
|
103
|
-
];
|
|
104
|
-
case TextLabelPosition.TOP_CENTER:
|
|
105
|
-
return [
|
|
106
|
-
chartArea.left + chartArea.width / 2,
|
|
107
|
-
chartArea.top + yOffset + legendHeight,
|
|
108
|
-
];
|
|
109
|
-
case TextLabelPosition.TOP_RIGHT:
|
|
110
|
-
return [
|
|
111
|
-
temporaryChartAreaRight - xOffset, //replace within chartArea.right when resize bug will be fixed
|
|
112
|
-
chartArea.top + yOffset + legendHeight,
|
|
113
|
-
];
|
|
114
|
-
case TextLabelPosition.MIDDLE_LEFT:
|
|
115
|
-
return [
|
|
116
|
-
chartArea.left + xOffset + legendWidth,
|
|
117
|
-
chartArea.top + chartArea.height / 2,
|
|
118
|
-
];
|
|
119
|
-
case TextLabelPosition.MIDDLE_CENTER:
|
|
120
|
-
return [
|
|
121
|
-
chartArea.left + chartArea.width / 2,
|
|
122
|
-
chartArea.top + chartArea.height / 2,
|
|
123
|
-
];
|
|
124
|
-
case TextLabelPosition.MIDDLE_RIGHT:
|
|
125
|
-
return [
|
|
126
|
-
temporaryChartAreaRight - xOffset - legendWidth, //replace within chartArea.right when resize bug will be fixed
|
|
127
|
-
chartArea.top + chartArea.height / 2,
|
|
128
|
-
];
|
|
129
|
-
case TextLabelPosition.BOTTOM_LEFT:
|
|
130
|
-
return [
|
|
131
|
-
chartArea.left + xOffset + legendWidth,
|
|
132
|
-
chartArea.bottom - yOffset - legendHeight,
|
|
133
|
-
];
|
|
134
|
-
case TextLabelPosition.BOTTOM_CENTER:
|
|
135
|
-
return [
|
|
136
|
-
chartArea.left + chartArea.width / 2,
|
|
137
|
-
chartArea.bottom - yOffset - legendHeight,
|
|
138
|
-
];
|
|
139
|
-
case TextLabelPosition.BOTTOM_RIGHT:
|
|
140
|
-
default:
|
|
141
|
-
return [
|
|
142
|
-
temporaryChartAreaRight - xOffset - legendWidth, //replace within chartArea.right when resize bug will be fixed
|
|
143
|
-
chartArea.bottom - yOffset - legendHeight,
|
|
144
|
-
];
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Determines the appropriate text alignment based on the position provided.
|
|
150
|
-
*
|
|
151
|
-
* @param {string} position - The position for the text (one of the values from the TextLabelPosition enum).
|
|
152
|
-
* @returns {string} The text alignment ('left', 'center', or 'right').
|
|
153
|
-
*/
|
|
154
|
-
const getTextAlign = (position) => {
|
|
155
|
-
if (position.includes(AlignOptions.Center)) {
|
|
156
|
-
return AlignOptions.Center;
|
|
157
|
-
} else if (position.includes(AlignOptions.Left)) {
|
|
158
|
-
return AlignOptions.Left;
|
|
159
|
-
} else {
|
|
160
|
-
return AlignOptions.Right;
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Wraps the text into lines based on the maxWidth provided.
|
|
166
|
-
*
|
|
167
|
-
* @param {string[]} words - The array of words to be processed.
|
|
168
|
-
* @param {number} maxWidth - The maximum width allowed for the text.
|
|
169
|
-
* @param {CanvasRenderingContext2D} ctx - The canvas rendering context to measure the text width.
|
|
170
|
-
* @returns {string[]} An array of wrapped lines.
|
|
171
|
-
*/
|
|
172
|
-
const wrapText = (words, maxWidth, ctx) => {
|
|
173
|
-
let line = '';
|
|
174
|
-
let lines = [];
|
|
175
|
-
for (let i = 0; i < words.length; i++) {
|
|
176
|
-
const testLine = `${line}${words[i]}${WORD_SEPARATOR}`;
|
|
177
|
-
const { width: testWidth } = ctx.measureText(testLine);
|
|
178
|
-
if (testWidth > maxWidth) {
|
|
179
|
-
lines.push(line.trim());
|
|
180
|
-
line = `${words[i]}${WORD_SEPARATOR}`;
|
|
181
|
-
} else {
|
|
182
|
-
line = testLine;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
lines.push(line.trim()); // Add the last line
|
|
186
|
-
return lines;
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Renders the wrapped text on the canvas context.
|
|
191
|
-
*
|
|
192
|
-
* @param {CanvasRenderingContext2D} ctx - The canvas rendering context to draw on.
|
|
193
|
-
* @param {object} options - The options object containing text, maxWidth, fontSize, lineHeight, position, and coordinates (x, y).
|
|
194
|
-
*/
|
|
195
|
-
const renderWrappedText = (ctx, options) => {
|
|
196
|
-
const { text, maxWidth, fontSize, lineHeight, x, y, position } = options;
|
|
197
|
-
|
|
198
|
-
const words = getWords(text);
|
|
199
|
-
const wrappedLines = wrapText(words, maxWidth, ctx);
|
|
200
|
-
|
|
201
|
-
ctx.save();
|
|
202
|
-
ctx.font = `${fontSize}px Arial`;
|
|
203
|
-
ctx.fillStyle = SEMI_TRANSPARENT;
|
|
204
|
-
ctx.textAlign = getTextAlign(position);
|
|
205
|
-
|
|
206
|
-
drawText(ctx, wrappedLines, lineHeight, x, y, position);
|
|
207
|
-
|
|
208
|
-
ctx.restore();
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
export const chartAreaTextPlugin = {
|
|
212
|
-
id: 'chartAreaText',
|
|
213
|
-
|
|
214
|
-
beforeDraw: (chart, args, options) => {
|
|
215
|
-
const {
|
|
216
|
-
showLabel,
|
|
217
|
-
text,
|
|
218
|
-
fontSize,
|
|
219
|
-
xOffset,
|
|
220
|
-
yOffset,
|
|
221
|
-
lineHeight,
|
|
222
|
-
maxWidth: initialMaxWidth,
|
|
223
|
-
position,
|
|
224
|
-
} = options;
|
|
225
|
-
const { ctx, chartArea } = chart;
|
|
226
|
-
|
|
227
|
-
if (!showLabel || !text) return;
|
|
228
|
-
|
|
229
|
-
// Determine the maxWidth based on chartArea width
|
|
230
|
-
const maxWidth = calculateMaxWidth(initialMaxWidth, chartArea.width);
|
|
231
|
-
|
|
232
|
-
// Get the position coordinates
|
|
233
|
-
const [x, y] = getPositionCoordinates(position, chart, xOffset, yOffset);
|
|
234
|
-
|
|
235
|
-
// Render the wrapped text
|
|
236
|
-
renderWrappedText(ctx, {
|
|
237
|
-
text,
|
|
238
|
-
maxWidth,
|
|
239
|
-
fontSize,
|
|
240
|
-
lineHeight,
|
|
241
|
-
x,
|
|
242
|
-
y,
|
|
243
|
-
position,
|
|
244
|
-
});
|
|
245
|
-
},
|
|
246
|
-
};
|
|
@@ -1,88 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export const TextLabelPosition = {
|
|
2
|
-
TOP_LEFT: 'top-left',
|
|
3
|
-
TOP_CENTER: 'top-center',
|
|
4
|
-
TOP_RIGHT: 'top-right',
|
|
5
|
-
MIDDLE_LEFT: 'middle-left',
|
|
6
|
-
MIDDLE_CENTER: 'middle-center',
|
|
7
|
-
MIDDLE_RIGHT: 'middle-right',
|
|
8
|
-
BOTTOM_LEFT: 'bottom-left',
|
|
9
|
-
BOTTOM_CENTER: 'bottom-center',
|
|
10
|
-
BOTTOM_RIGHT: 'bottom-right',
|
|
11
|
-
};
|