@mozaic-ds/chart 0.1.0-beta.2 → 0.1.0-beta.23
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/mozaic-chart.js +4111 -2476
- package/dist/mozaic-chart.umd.cjs +17 -11
- package/dist/style.css +1 -1
- package/package.json +23 -10
- package/src/assets/img/bubbles.svg +4 -0
- package/src/components/bar/BarChart.stories.ts +12 -10
- package/src/components/bar/BarChart.vue +248 -141
- package/src/components/bubble/BubbleChart.stories.ts +66 -0
- package/src/components/bubble/BubbleChart.vue +336 -0
- package/src/components/bubble/index.ts +8 -0
- package/src/components/doughnut/DoughnutChart.stories.ts +1 -0
- package/src/components/doughnut/DoughnutChart.vue +182 -101
- package/src/components/line/LineChart.stories.ts +2 -1
- package/src/components/line/LineChart.vue +331 -258
- package/src/components/mixed/MixedBarLineChart.stories.ts +91 -0
- package/src/components/mixed/MixedBarLineChart.vue +411 -0
- package/src/components/mixed/index.ts +8 -0
- package/src/components/radar/RadarChart.stories.ts +2 -2
- package/src/components/radar/RadarChart.vue +203 -157
- package/src/main.ts +3 -1
- package/src/plugin.ts +2 -0
- package/src/services/BarChartFunctions.ts +10 -7
- package/src/services/BubbleTooltipService.ts +65 -0
- package/src/services/ChartsCommonLegend.ts +86 -58
- package/src/services/DoughnutChartFunctions.ts +107 -59
- package/src/services/FormatUtilities.ts +1 -1
- package/src/services/GenericTooltipService.ts +25 -10
- package/src/services/MixedBarLineFunctions.ts +258 -0
- package/src/services/RadarChartFunctions.ts +33 -12
- package/src/stories/Changelog.mdx +6 -0
- package/src/stories/Contributing.mdx +101 -0
- package/src/stories/GettingStarted.mdx +92 -0
- package/src/stories/SupportAndOnboarding.mdx +44 -0
- package/src/types/AxisDefinition.ts +6 -0
- package/src/types/BarData.ts +1 -0
- package/src/types/MixedBarLineData.ts +7 -0
- package/src/types/TooltipChartType.ts +1 -0
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
1
|
+
import type {Ref} from 'vue';
|
|
2
|
+
import type {HTMLLegendPlugin} from "../types/Chart";
|
|
3
|
+
import type {ChartOptions} from 'chart.js';
|
|
4
4
|
import PatternFunctions from './PatternFunctions';
|
|
5
|
-
import {
|
|
5
|
+
import {formatValueAndRate} from './FormatUtilities';
|
|
6
6
|
import QuestionMarkSvg from '@mozaic-ds/icons/svg/Navigation_Notification_Question_24px.svg';
|
|
7
7
|
|
|
8
8
|
const { getPatternCanvas } = PatternFunctions();
|
|
9
9
|
|
|
10
10
|
export const LEGEND_FONT_SIZE = 14;
|
|
11
11
|
export const LEGEND_LABEL_LEFT_MARGIN = '6px';
|
|
12
|
-
export const LEGEND_BOX_SIZE =
|
|
12
|
+
export const LEGEND_BOX_SIZE = '22px';
|
|
13
13
|
export const LEGEND_BOX_POINT_SIZE = 6;
|
|
14
|
+
export const LEGEND_BOX_BORDER = '2px';
|
|
14
15
|
|
|
15
16
|
export interface Chart {
|
|
16
17
|
update (): void;
|
|
@@ -31,17 +32,18 @@ export interface Chart {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
export interface ChartItem {
|
|
34
|
-
fontColor: string
|
|
35
|
-
hidden: boolean
|
|
36
|
-
text: string
|
|
37
|
-
fillStyle: string
|
|
38
|
-
strokeStyle: string
|
|
39
|
-
lineWidth: number
|
|
40
|
-
datasetIndex: number
|
|
41
|
-
index: number
|
|
35
|
+
fontColor: string;
|
|
36
|
+
hidden: boolean;
|
|
37
|
+
text: string;
|
|
38
|
+
fillStyle: string;
|
|
39
|
+
strokeStyle: string;
|
|
40
|
+
lineWidth: number;
|
|
41
|
+
datasetIndex: number;
|
|
42
|
+
index: number;
|
|
43
|
+
lineCap?: string;
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
export function getHtmlLegendPlugin(legendContainer: Ref, selectMode: Ref<boolean>, onHoverIndex: any, disableAccessibility: Ref<boolean>, patternsColors: Ref<string[]>, patternsList: Ref<((hover: boolean, color: string, disableAccessibility: boolean) => CanvasPattern)[]>, maxValueToDisplay?: number, chartData?: any): HTMLLegendPlugin[] {
|
|
46
|
+
export function getHtmlLegendPlugin(legendContainer: Ref, selectMode: Ref<boolean>, onHoverIndex: any, disableAccessibility: Ref<boolean>, patternsColors: Ref<string[]>, patternsList: Ref<((hover: boolean, color: string, disableAccessibility: boolean) => CanvasPattern)[]>, enableHoverFeature: Ref<boolean>, maxValueToDisplay?: number, chartData?: any): HTMLLegendPlugin[] {
|
|
45
47
|
return [{
|
|
46
48
|
id: 'htmlLegend',
|
|
47
49
|
afterUpdate (chart: any) {
|
|
@@ -64,16 +66,17 @@ export function getHtmlLegendPlugin(legendContainer: Ref, selectMode: Ref<boolea
|
|
|
64
66
|
li.style.position = 'relative';
|
|
65
67
|
}
|
|
66
68
|
} else {
|
|
67
|
-
li.style.marginRight = '
|
|
69
|
+
li.style.marginRight = '10px'
|
|
68
70
|
}
|
|
69
71
|
li.style.width = 'max-content';
|
|
70
72
|
li.style.cursor = 'pointer';
|
|
71
73
|
let liContent: HTMLElement;
|
|
72
74
|
if (!selectMode.value) {
|
|
73
|
-
liContent = createLegendElementWithPatterns(item, chart, onHoverIndex, disableAccessibility.value, patternsColors.value, patternsList.value);
|
|
75
|
+
liContent = createLegendElementWithPatterns(item, chart, onHoverIndex, disableAccessibility.value, patternsColors.value, patternsList.value, enableHoverFeature.value);
|
|
74
76
|
} else {
|
|
75
|
-
liContent = createLegendElementWithCheckbox(chart, item, selectMode, onHoverIndex,
|
|
77
|
+
liContent = createLegendElementWithCheckbox(chart, item, selectMode, onHoverIndex, patternsColors.value, enableHoverFeature.value);
|
|
76
78
|
}
|
|
79
|
+
liContent.style.boxSizing = 'border-box';
|
|
77
80
|
li.appendChild(liContent);
|
|
78
81
|
li.appendChild(createHtmlLegendItemText(item));
|
|
79
82
|
if (isDoughnut && maxValueToDisplay && hasOthersTooltipToDisplay(chartData, maxValueToDisplay, index)) {
|
|
@@ -105,6 +108,9 @@ export function createTooltipAndItsIcon (doughnutData: any, maxValueToDisplay: n
|
|
|
105
108
|
icon.onmouseover = () => {
|
|
106
109
|
(iconWrapper.firstElementChild as HTMLElement).style.visibility = 'visible';
|
|
107
110
|
};
|
|
111
|
+
icon.onmouseleave = () => {
|
|
112
|
+
(iconWrapper.firstElementChild as HTMLElement).style.visibility = 'hidden';
|
|
113
|
+
};
|
|
108
114
|
iconTopWrapper.appendChild(iconWrapper);
|
|
109
115
|
iconWrapper.appendChild(tooltip);
|
|
110
116
|
iconWrapper.appendChild(icon);
|
|
@@ -150,7 +156,7 @@ doughnutData.data.slice(startIndex).forEach((_ignore: any, index: number) => {
|
|
|
150
156
|
}
|
|
151
157
|
|
|
152
158
|
export function createLegendElementWithPatterns
|
|
153
|
-
(item: ChartItem, chart: Chart, onHoverIndex: any | null, disableAccessibility: boolean, patternsColors: string[], patternsList: ((hover: boolean, color: string, disableAccessibility: boolean) => CanvasPattern)[])
|
|
159
|
+
(item: ChartItem, chart: Chart, onHoverIndex: any | null, disableAccessibility: boolean, patternsColors: string[], patternsList: ((hover: boolean, color: string, disableAccessibility: boolean) => CanvasPattern)[], enableHoverFeature: boolean)
|
|
154
160
|
: HTMLElement {
|
|
155
161
|
const isDoughnut: boolean = chart.config.type === 'doughnut';
|
|
156
162
|
const index: number = isDoughnut ? item.index : item.datasetIndex;
|
|
@@ -162,40 +168,44 @@ export function createLegendElementWithPatterns
|
|
|
162
168
|
boxSpan.style.background = `url(${img.src})`;
|
|
163
169
|
boxSpan.style.backgroundSize = 'cover';
|
|
164
170
|
boxSpan.style.borderColor = patternsColors[index];
|
|
165
|
-
boxSpan.style.borderWidth =
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
boxSpan.style.borderWidth = LEGEND_BOX_BORDER;
|
|
172
|
+
|
|
173
|
+
if (enableHoverFeature) {
|
|
174
|
+
boxSpan.onmouseover = ():void => {
|
|
175
|
+
isDoughnut ? onHoverIndex.value = index : onHoverIndex.dataSetIndex = index;
|
|
176
|
+
};
|
|
177
|
+
boxSpan.onmouseleave = (): void => {
|
|
178
|
+
isDoughnut ? onHoverIndex.value = null : onHoverIndex.dataSetIndex = -1;
|
|
179
|
+
};
|
|
180
|
+
}
|
|
173
181
|
return boxSpan;
|
|
174
182
|
}
|
|
175
183
|
|
|
176
184
|
export function createLegendElementWithCheckbox
|
|
177
|
-
(chart: Chart, item: ChartItem, selectMode: Ref<boolean>, onHoverIndex: any | null,
|
|
185
|
+
(chart: Chart, item: ChartItem, selectMode: Ref<boolean>, onHoverIndex: any | null, patternsColors: string[], enableHoverFeature: boolean): HTMLElement {
|
|
178
186
|
const isDoughnut: boolean = chart.config.type === 'doughnut';
|
|
179
187
|
const index: number = isDoughnut ? item.index : item.datasetIndex;
|
|
180
|
-
const checkbox: HTMLElement = createLegendCheckbox(chart, item,
|
|
188
|
+
const checkbox: HTMLElement = createLegendCheckbox(chart, item, patternsColors);
|
|
181
189
|
const labels = chart.config.data.labels;
|
|
182
190
|
const allCheckBoxesVisible: boolean =
|
|
183
191
|
labels.every((label: string, index: number) => chart.getDataVisibility(index));
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
192
|
+
if (allCheckBoxesVisible) {
|
|
193
|
+
if (isDoughnut) {
|
|
194
|
+
selectMode.value = false;
|
|
195
|
+
onHoverIndex.value = -1;
|
|
196
|
+
}
|
|
197
|
+
return checkbox;
|
|
190
198
|
}
|
|
191
|
-
|
|
199
|
+
if (enableHoverFeature) {
|
|
200
|
+
checkbox.onmouseover = ():void => {
|
|
201
|
+
isDoughnut ? onHoverIndex.value = index : onHoverIndex.dataSetIndex = index;
|
|
202
|
+
chart.update();
|
|
203
|
+
};
|
|
204
|
+
checkbox.onmouseleave = (): void => {
|
|
205
|
+
isDoughnut ? onHoverIndex.value = null : onHoverIndex.dataSetIndex = -1;
|
|
206
|
+
chart.update();
|
|
207
|
+
};
|
|
192
208
|
}
|
|
193
|
-
checkbox.onmouseover = ():void => {
|
|
194
|
-
isDoughnut ? onHoverIndex.value = index : onHoverIndex.dataSetIndex = index;
|
|
195
|
-
};
|
|
196
|
-
checkbox.onmouseleave = (): void => {
|
|
197
|
-
isDoughnut ? onHoverIndex.value = null : onHoverIndex.dataSetIndex = null;
|
|
198
|
-
};
|
|
199
209
|
return checkbox;
|
|
200
210
|
}
|
|
201
211
|
|
|
@@ -214,18 +224,18 @@ export function createHtmlLegendItemText (item: ChartItem) {
|
|
|
214
224
|
export function createHtmlLegendLine (item: ChartItem, type: string | undefined) {
|
|
215
225
|
const boxSpan = document.createElement('div');
|
|
216
226
|
if (type !== 'doughnut') {
|
|
217
|
-
boxSpan.style.background =
|
|
227
|
+
boxSpan.style.background = 'rgba(0, 0, 0, 0.1)';
|
|
218
228
|
boxSpan.style.borderColor = item.strokeStyle;
|
|
219
|
-
boxSpan.style.borderWidth =
|
|
229
|
+
boxSpan.style.borderWidth = LEGEND_BOX_BORDER;
|
|
220
230
|
}
|
|
221
231
|
boxSpan.style.borderRadius = '5px';
|
|
222
232
|
boxSpan.style.borderStyle = 'solid';
|
|
223
233
|
boxSpan.style.display = 'flex';
|
|
224
234
|
boxSpan.style.justifyContent = 'center';
|
|
225
235
|
boxSpan.style.alignItems = 'center';
|
|
226
|
-
boxSpan.style.width = LEGEND_BOX_SIZE
|
|
236
|
+
boxSpan.style.width = LEGEND_BOX_SIZE;
|
|
227
237
|
boxSpan.style.marginRight = LEGEND_LABEL_LEFT_MARGIN;
|
|
228
|
-
boxSpan.style.height = LEGEND_BOX_SIZE
|
|
238
|
+
boxSpan.style.height = LEGEND_BOX_SIZE;
|
|
229
239
|
return boxSpan;
|
|
230
240
|
}
|
|
231
241
|
|
|
@@ -236,7 +246,7 @@ export function createHtmlLegendDatasetSquare (item: ChartItem) {
|
|
|
236
246
|
divPoint.style.background = 'white';
|
|
237
247
|
divPoint.style.borderStyle = 'solid';
|
|
238
248
|
divPoint.style.borderColor = item.strokeStyle;
|
|
239
|
-
divPoint.style.borderWidth =
|
|
249
|
+
divPoint.style.borderWidth = LEGEND_BOX_BORDER;
|
|
240
250
|
return divPoint;
|
|
241
251
|
}
|
|
242
252
|
|
|
@@ -259,30 +269,32 @@ export function createHtmlLegendListElement
|
|
|
259
269
|
return li;
|
|
260
270
|
}
|
|
261
271
|
|
|
262
|
-
export function addCheckboxStyle (isDataSetVisible: boolean, item: ChartItem, checkbox: Element,
|
|
272
|
+
export function addCheckboxStyle (isDataSetVisible: boolean, item: ChartItem, checkbox: Element, patternColor: string) {
|
|
263
273
|
let backgroundColor = '#fff';
|
|
264
274
|
let borderColor = '#666';
|
|
265
275
|
if (isDataSetVisible) {
|
|
266
|
-
|
|
267
|
-
|
|
276
|
+
//Default white for patterns chart
|
|
277
|
+
backgroundColor = isDefaultWhiteColor(item.strokeStyle)? patternColor: item.strokeStyle;
|
|
278
|
+
borderColor = isDefaultWhiteColor(item.strokeStyle)? patternColor: item.strokeStyle;
|
|
279
|
+
checkbox.setAttribute('checked', '' + isDataSetVisible);
|
|
268
280
|
}
|
|
269
|
-
checkbox.setAttribute('checked', '' + isDataSetVisible);
|
|
270
281
|
checkbox.setAttribute('class', 'mc-checkbox__input');
|
|
271
282
|
checkbox.setAttribute('style', `background-color: ${backgroundColor};
|
|
272
|
-
width: ${LEGEND_BOX_SIZE
|
|
273
|
-
height: ${LEGEND_BOX_SIZE
|
|
283
|
+
width: ${LEGEND_BOX_SIZE};
|
|
284
|
+
height: ${LEGEND_BOX_SIZE};
|
|
274
285
|
margin-right: ${LEGEND_LABEL_LEFT_MARGIN};
|
|
275
286
|
border-color: ${borderColor};`);
|
|
276
287
|
}
|
|
277
288
|
|
|
278
|
-
export function createLegendCheckbox (chart: Chart, item: ChartItem,
|
|
289
|
+
export function createLegendCheckbox (chart: Chart, item: ChartItem, patternsColors: string[]) {
|
|
279
290
|
const isDoughnut: boolean = chart.config.type === 'doughnut';
|
|
280
291
|
const index: number = isDoughnut ? item.index : item.datasetIndex;
|
|
281
292
|
const checkbox = document.createElement('input');
|
|
282
293
|
checkbox.setAttribute('type', 'checkbox');
|
|
283
294
|
checkbox.setAttribute('data-test-id', `legend-checkbox-${index}`);
|
|
284
|
-
const isDataSetVisible =
|
|
285
|
-
|
|
295
|
+
const isDataSetVisible = isChartDataVisible(chart, index);
|
|
296
|
+
const patternColor = patternsColors? patternsColors[index]:undefined;
|
|
297
|
+
addCheckboxStyle(isDataSetVisible, item, checkbox, patternColor as string);
|
|
286
298
|
return checkbox;
|
|
287
299
|
}
|
|
288
300
|
|
|
@@ -315,17 +327,26 @@ function allDataVisible (chart: Chart): boolean {
|
|
|
315
327
|
let allVisible = true;
|
|
316
328
|
const chartsData: unknown[] = getChartsData(chart);
|
|
317
329
|
chartsData.forEach((_data, dataIndex) => {
|
|
318
|
-
allVisible = allVisible && chart
|
|
330
|
+
allVisible = allVisible && isChartDataVisible(chart, dataIndex);
|
|
319
331
|
});
|
|
320
332
|
return allVisible;
|
|
321
333
|
}
|
|
322
334
|
|
|
335
|
+
function isChartDataVisible(chart: Chart, dataIndex: number): boolean {
|
|
336
|
+
if (isMonoDataSetChart(chart)) {
|
|
337
|
+
return chart.getDataVisibility(dataIndex);
|
|
338
|
+
} else {
|
|
339
|
+
return chart.isDatasetVisible(dataIndex);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
323
343
|
export function switchItemVisibility (chart: Chart, elementIndex: number, selectMode?: Ref) {
|
|
324
344
|
if (isMonoDataSetChart(chart)) {
|
|
325
345
|
chart.toggleDataVisibility(elementIndex);
|
|
326
346
|
} else {
|
|
327
347
|
chart.setDatasetVisibility(elementIndex, !chart.isDatasetVisible(elementIndex));
|
|
328
348
|
}
|
|
349
|
+
|
|
329
350
|
if (selectMode && allDataVisible(chart)) {
|
|
330
351
|
selectMode.value = false;
|
|
331
352
|
}
|
|
@@ -333,11 +354,14 @@ export function switchItemVisibility (chart: Chart, elementIndex: number, select
|
|
|
333
354
|
}
|
|
334
355
|
|
|
335
356
|
|
|
336
|
-
export function createLegendElementWithSquareArea (item: ChartItem, mainSerieFirstDataset?: boolean) {
|
|
357
|
+
export function createLegendElementWithSquareArea (item: ChartItem, mainSerieFirstDataset?: boolean,) {
|
|
337
358
|
const liContent = createHtmlLegendLine(item, '');
|
|
338
359
|
const divPoint = createHtmlLegendDatasetSquare(item);
|
|
339
360
|
const index = item.index || item.datasetIndex;
|
|
340
|
-
|
|
361
|
+
|
|
362
|
+
divPoint.style.width = '10px';
|
|
363
|
+
divPoint.style.height = '10px';
|
|
364
|
+
if (index % 2 === 0) {
|
|
341
365
|
mainSerieFirstDataset ? divPoint.style.borderRadius = '25px' : divPoint.style.transform = 'rotate(45deg)';
|
|
342
366
|
} else {
|
|
343
367
|
mainSerieFirstDataset ? divPoint.style.transform = 'rotate(45deg)' : divPoint.style.borderRadius = '25px';
|
|
@@ -359,3 +383,7 @@ export function getOrCreateLegendList (legendContainer: Ref, flexDirection: stri
|
|
|
359
383
|
}
|
|
360
384
|
return listContainer;
|
|
361
385
|
}
|
|
386
|
+
|
|
387
|
+
function isDefaultWhiteColor(color: string){
|
|
388
|
+
return color === '#00000000';
|
|
389
|
+
}
|
|
@@ -1,85 +1,133 @@
|
|
|
1
|
-
import { ref } from
|
|
2
|
-
import type { Ref } from
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
} from '../services/ChartsCommonLegend';
|
|
6
|
-
import { formatWithThousandsSeprators } from '../services/FormatUtilities';
|
|
1
|
+
import { ref } from "vue";
|
|
2
|
+
import type { Ref } from "vue";
|
|
3
|
+
import { getHtmlLegendPlugin } from "../services/ChartsCommonLegend";
|
|
4
|
+
import { formatWithThousandsSeprators } from "../services/FormatUtilities";
|
|
7
5
|
|
|
8
|
-
import
|
|
9
|
-
import {addAlpha} from './ColorFunctions';
|
|
6
|
+
import { addAlpha } from "./ColorFunctions";
|
|
10
7
|
|
|
11
8
|
export default function () {
|
|
12
9
|
const doughnutRef: Ref = ref(null);
|
|
13
10
|
const onHoverIndex: Ref<number | null> = ref(null);
|
|
14
11
|
const backgroundColor: Ref<CanvasPattern[] | null> = ref(null);
|
|
15
12
|
|
|
16
|
-
function privateGetHtmlLegendPlugin(
|
|
17
|
-
|
|
13
|
+
function privateGetHtmlLegendPlugin(
|
|
14
|
+
legendContainer: Ref,
|
|
15
|
+
selectMode: Ref<boolean>,
|
|
16
|
+
disableAccessibility: Ref<boolean>,
|
|
17
|
+
patternsColors: Ref<string[]>,
|
|
18
|
+
patternsList: Ref<
|
|
19
|
+
((
|
|
20
|
+
hover: boolean,
|
|
21
|
+
color: string,
|
|
22
|
+
disableAccessibility: boolean
|
|
23
|
+
) => CanvasPattern)[]
|
|
24
|
+
>,
|
|
25
|
+
maxValueToDisplay: number,
|
|
26
|
+
doughnutData: any,
|
|
27
|
+
enableHoverFeature: Ref<boolean>
|
|
28
|
+
) {
|
|
29
|
+
return getHtmlLegendPlugin(
|
|
30
|
+
legendContainer,
|
|
31
|
+
selectMode,
|
|
32
|
+
onHoverIndex,
|
|
33
|
+
disableAccessibility,
|
|
34
|
+
patternsColors,
|
|
35
|
+
patternsList,
|
|
36
|
+
enableHoverFeature,
|
|
37
|
+
maxValueToDisplay,
|
|
38
|
+
doughnutData
|
|
39
|
+
);
|
|
18
40
|
}
|
|
19
41
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
42
|
+
function getBackgroundColor(
|
|
43
|
+
patternsColors: string[],
|
|
44
|
+
patternsList: ((
|
|
45
|
+
hover: boolean,
|
|
46
|
+
color: string,
|
|
47
|
+
disableAccessibility: boolean
|
|
48
|
+
) => CanvasPattern)[],
|
|
49
|
+
disableAccessibility: boolean,
|
|
50
|
+
enableHoverFeature: boolean
|
|
51
|
+
) {
|
|
52
|
+
if (onHoverIndex.value !== null && enableHoverFeature) {
|
|
53
|
+
return patternsList.map((pattern, index) =>
|
|
54
|
+
onHoverIndex.value === index
|
|
55
|
+
? pattern(false, patternsColors[index], disableAccessibility)
|
|
56
|
+
: pattern(true, patternsColors[index], disableAccessibility)
|
|
57
|
+
);
|
|
25
58
|
} else {
|
|
26
|
-
return patternsList
|
|
27
|
-
|
|
59
|
+
return patternsList.map((pattern, index) =>
|
|
60
|
+
pattern(false, patternsColors[index], disableAccessibility)
|
|
61
|
+
);
|
|
28
62
|
}
|
|
29
63
|
}
|
|
30
64
|
|
|
31
|
-
function getBorderColor(patternsColors: string[]): string[] {
|
|
32
|
-
if (onHoverIndex.value !== null) {
|
|
33
|
-
return patternsColors.map((color, index) =>
|
|
65
|
+
function getBorderColor(patternsColors: string[], enableHoverFeature: boolean): string[] {
|
|
66
|
+
if (onHoverIndex.value !== null && enableHoverFeature) {
|
|
67
|
+
return patternsColors.map((color, index) =>
|
|
68
|
+
onHoverIndex.value === index ? color : addAlpha(color, 0.2)
|
|
69
|
+
);
|
|
34
70
|
} else {
|
|
35
71
|
return patternsColors;
|
|
36
72
|
}
|
|
37
73
|
}
|
|
38
74
|
|
|
75
|
+
function getOnHoverOptions() {
|
|
76
|
+
return (_ignore: unknown, activeElements: Array<any>): void => {
|
|
77
|
+
if (activeElements[0] !== undefined) {
|
|
78
|
+
onHoverIndex.value = activeElements[0].element.$context.index;
|
|
79
|
+
} else {
|
|
80
|
+
onHoverIndex.value = null;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
39
84
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (activeElements[0] !== undefined) {
|
|
43
|
-
onHoverIndex.value = activeElements[0].element.$context.index;
|
|
44
|
-
} else {
|
|
45
|
-
onHoverIndex.value = null;
|
|
46
|
-
}
|
|
85
|
+
const getFormatedText = (str: string) => {
|
|
86
|
+
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
|
47
87
|
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const getFormatedText = (str: string) => {
|
|
51
|
-
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
|
52
|
-
};
|
|
53
88
|
|
|
54
|
-
function getDoughnutLabels(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
truncatedLabels.
|
|
89
|
+
function getDoughnutLabels(
|
|
90
|
+
labels: string[],
|
|
91
|
+
data: any[],
|
|
92
|
+
maxValues: number,
|
|
93
|
+
othersLabel: string
|
|
94
|
+
) {
|
|
95
|
+
let truncatedLabels = labels.slice(0);
|
|
96
|
+
let truncatedData = data.slice(0);
|
|
97
|
+
if (labels.length > maxValues) {
|
|
98
|
+
truncatedData = groupDataAfterNthValue(data, maxValues);
|
|
99
|
+
truncatedLabels = truncatedLabels.slice(0, maxValues - 1);
|
|
100
|
+
truncatedLabels.push(othersLabel);
|
|
101
|
+
}
|
|
102
|
+
return truncatedLabels.map(
|
|
103
|
+
(label: string, index: number) =>
|
|
104
|
+
`${getFormatedText(label)} (${formatWithThousandsSeprators(
|
|
105
|
+
truncatedData[index].rate as number
|
|
106
|
+
)} %)`
|
|
107
|
+
);
|
|
61
108
|
}
|
|
62
|
-
return truncatedLabels.map((label: string, index: number) => `${getFormatedText(label)} (${formatWithThousandsSeprators(truncatedData[index].rate as number)} %)`);
|
|
63
|
-
}
|
|
64
109
|
|
|
65
|
-
function groupDataAfterNthValue
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
110
|
+
function groupDataAfterNthValue(data: any, maxValues: number): any[] {
|
|
111
|
+
if (maxValues < 1) {
|
|
112
|
+
return data;
|
|
113
|
+
}
|
|
114
|
+
let truncatedData = data.slice(0);
|
|
115
|
+
if (data.length > maxValues) {
|
|
116
|
+
truncatedData = truncatedData.slice(0, maxValues);
|
|
117
|
+
truncatedData[maxValues - 1] = data.slice(maxValues).reduce(
|
|
118
|
+
(result: any, current: any) => {
|
|
119
|
+
result.rate += current.rate;
|
|
120
|
+
result.value += current.value;
|
|
121
|
+
return result;
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
rate: data[maxValues - 1].rate,
|
|
125
|
+
value: data[maxValues - 1].value,
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
return truncatedData;
|
|
80
130
|
}
|
|
81
|
-
return truncatedData;
|
|
82
|
-
}
|
|
83
131
|
|
|
84
132
|
return {
|
|
85
133
|
onHoverIndex,
|
|
@@ -91,6 +139,6 @@ function groupDataAfterNthValue (data: any, maxValues: number): any[] {
|
|
|
91
139
|
getFormatedText,
|
|
92
140
|
getBorderColor,
|
|
93
141
|
backgroundColor,
|
|
94
|
-
doughnutRef
|
|
142
|
+
doughnutRef,
|
|
95
143
|
};
|
|
96
144
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export function formatTicks (val: number, unit?: string
|
|
1
|
+
export function formatTicks (val: number, unit?: string): string {
|
|
2
2
|
const fixedValue = parseInt(val.toFixed());
|
|
3
3
|
return `${new Intl.NumberFormat().format(fixedValue)}${unit ? ' ' + unit : ''}`;
|
|
4
4
|
}
|
|
@@ -39,8 +39,12 @@ export type Context = {
|
|
|
39
39
|
replay?: unknown;
|
|
40
40
|
tooltip: {
|
|
41
41
|
dataPoints: {
|
|
42
|
+
dataset?: {
|
|
43
|
+
type?: string
|
|
44
|
+
},
|
|
42
45
|
dataIndex?: number,
|
|
43
|
-
datasetIndex?: number
|
|
46
|
+
datasetIndex?: number,
|
|
47
|
+
raw: any
|
|
44
48
|
}[];
|
|
45
49
|
opacity : number;
|
|
46
50
|
body: {
|
|
@@ -110,6 +114,7 @@ export class GenericTooltipService {
|
|
|
110
114
|
const body = this.chartType === 'DOUGHNUT' ? [tooltipModel.title[0].split('(')[0].trim()]: bodyLines[0];
|
|
111
115
|
let legendIconStyle = '';
|
|
112
116
|
let legendInnerStyle = '';
|
|
117
|
+
const datasetType = context.tooltip?.dataPoints[0]?.dataset?.type;
|
|
113
118
|
|
|
114
119
|
if (this.chartType === 'RADAR' || this.chartType === 'LINE_CHART') {
|
|
115
120
|
legendIconStyle = this.createLegendStyle(context);
|
|
@@ -118,6 +123,13 @@ export class GenericTooltipService {
|
|
|
118
123
|
this.chartType === 'DETAILS_BAR_CHART' ||
|
|
119
124
|
this.chartType === 'DOUGHNUT') {
|
|
120
125
|
legendIconStyle = this.createPatternLegendStyle(context);
|
|
126
|
+
} else if (this.chartType === 'MIXED_BAR_LINE_CHART') {
|
|
127
|
+
if (datasetType === 'bar') {
|
|
128
|
+
legendIconStyle = this.createPatternLegendStyle(context);
|
|
129
|
+
} else {
|
|
130
|
+
legendIconStyle = this.createLegendStyle(context);
|
|
131
|
+
legendInnerStyle = this.createLegendInnerStyle(context);
|
|
132
|
+
}
|
|
121
133
|
}
|
|
122
134
|
|
|
123
135
|
this.addLegendToDom(
|
|
@@ -129,14 +141,15 @@ export class GenericTooltipService {
|
|
|
129
141
|
tooltipEl,
|
|
130
142
|
patternsColors,
|
|
131
143
|
patternsList,
|
|
132
|
-
disableAccessibility
|
|
144
|
+
disableAccessibility,
|
|
145
|
+
datasetType
|
|
133
146
|
);
|
|
134
147
|
}
|
|
135
148
|
|
|
136
149
|
this.handleTooltipPosition(context, tooltipModel, tooltipEl);
|
|
137
150
|
}
|
|
138
151
|
|
|
139
|
-
|
|
152
|
+
protected handleTooltipPosition
|
|
140
153
|
(context: Context, tooltipModel: { caretX: number, caretY: number }, tooltipEl: HTMLElement) {
|
|
141
154
|
const position = context.chart.canvas.getBoundingClientRect();
|
|
142
155
|
const screenWidth = window.innerWidth;
|
|
@@ -158,7 +171,7 @@ export class GenericTooltipService {
|
|
|
158
171
|
}
|
|
159
172
|
}
|
|
160
173
|
|
|
161
|
-
|
|
174
|
+
protected createNewTooltipElement () {
|
|
162
175
|
const tooltipEl = document.createElement('div');
|
|
163
176
|
tooltipEl.id = 'chartjs-tooltip';
|
|
164
177
|
tooltipEl.style.backgroundColor = 'white';
|
|
@@ -188,7 +201,8 @@ export class GenericTooltipService {
|
|
|
188
201
|
style += ';margin-right: 10px';
|
|
189
202
|
style += ';display: flex';
|
|
190
203
|
style += ';align-items: center';
|
|
191
|
-
style += ';justify-content: center
|
|
204
|
+
style += ';justify-content: center';
|
|
205
|
+
style += ';background: rgba(0, 0, 0, 0.1);';
|
|
192
206
|
return style;
|
|
193
207
|
}
|
|
194
208
|
|
|
@@ -215,7 +229,8 @@ export class GenericTooltipService {
|
|
|
215
229
|
tooltipEl: HTMLElement,
|
|
216
230
|
patternsColors: string[],
|
|
217
231
|
patternsList: ((hover: boolean, color: string, disableAccessibility: boolean) => CanvasPattern)[],
|
|
218
|
-
disableAccessibility: boolean = false
|
|
232
|
+
disableAccessibility: boolean = false,
|
|
233
|
+
datasetType?: string
|
|
219
234
|
) {
|
|
220
235
|
let innerHtml = innerHTMLtext;
|
|
221
236
|
let legendImage = `<div class="legendIcon" style="${legendIconStyle}">`;
|
|
@@ -225,9 +240,9 @@ export class GenericTooltipService {
|
|
|
225
240
|
const innerHtmlToAdd = this.setInnerHtmlToAdd(body, style, legendImage);
|
|
226
241
|
innerHtml += innerHtmlToAdd;
|
|
227
242
|
const tableRoot = tooltipEl?.querySelector('.tooltipCtn') as HTMLElement | null;
|
|
228
|
-
|
|
229
243
|
if (tableRoot?.innerHTML != null) {
|
|
230
|
-
this.setInnerHtmlAndPattern(tableRoot, innerHtml, patternsColors, patternsList, disableAccessibility)
|
|
244
|
+
datasetType ? this.setInnerHtmlAndPattern(tableRoot, innerHtml, patternsColors, patternsList, disableAccessibility, datasetType)
|
|
245
|
+
: this.setInnerHtmlAndPattern(tableRoot, innerHtml, patternsColors, patternsList, disableAccessibility);
|
|
231
246
|
}
|
|
232
247
|
}
|
|
233
248
|
|
|
@@ -285,7 +300,7 @@ export class GenericTooltipService {
|
|
|
285
300
|
}
|
|
286
301
|
|
|
287
302
|
|
|
288
|
-
setInnerHtmlAndPattern(tableRoot: HTMLElement, innerHtml: string, patternsColors: string[], patternsList: ((hover: boolean, color: string, disableAccessibility: boolean) => CanvasPattern)[], disableAccessibility: boolean = false) {
|
|
303
|
+
setInnerHtmlAndPattern(tableRoot: HTMLElement, innerHtml: string, patternsColors: string[], patternsList: ((hover: boolean, color: string, disableAccessibility: boolean) => CanvasPattern)[], disableAccessibility: boolean = false, datasetType?: string) {
|
|
289
304
|
tableRoot.innerHTML = innerHtml;
|
|
290
305
|
const legendIconHtml = document.querySelector('.legendIcon') as HTMLElement;
|
|
291
306
|
const img: HTMLImageElement = new Image();
|
|
@@ -298,7 +313,7 @@ export class GenericTooltipService {
|
|
|
298
313
|
index = this.datasetIndex + 1;
|
|
299
314
|
}
|
|
300
315
|
const patternIndex = getPatternIndexWithShift(index, this.patternShifting);
|
|
301
|
-
if (this.chartType !== 'LINE_CHART' && this.chartType !== 'RADAR') {
|
|
316
|
+
if (this.chartType !== 'LINE_CHART' && this.chartType !== 'RADAR' && datasetType !== 'line') {
|
|
302
317
|
const pattern: CanvasPattern = patternsList[patternIndex - 1](false, patternsColors[patternIndex - 1], disableAccessibility);
|
|
303
318
|
const patternCanvas: HTMLCanvasElement = getPatternCanvas(pattern, 22, 22);
|
|
304
319
|
img.src = patternCanvas.toDataURL();
|