@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.
Files changed (37) hide show
  1. package/dist/mozaic-chart.js +4111 -2476
  2. package/dist/mozaic-chart.umd.cjs +17 -11
  3. package/dist/style.css +1 -1
  4. package/package.json +23 -10
  5. package/src/assets/img/bubbles.svg +4 -0
  6. package/src/components/bar/BarChart.stories.ts +12 -10
  7. package/src/components/bar/BarChart.vue +248 -141
  8. package/src/components/bubble/BubbleChart.stories.ts +66 -0
  9. package/src/components/bubble/BubbleChart.vue +336 -0
  10. package/src/components/bubble/index.ts +8 -0
  11. package/src/components/doughnut/DoughnutChart.stories.ts +1 -0
  12. package/src/components/doughnut/DoughnutChart.vue +182 -101
  13. package/src/components/line/LineChart.stories.ts +2 -1
  14. package/src/components/line/LineChart.vue +331 -258
  15. package/src/components/mixed/MixedBarLineChart.stories.ts +91 -0
  16. package/src/components/mixed/MixedBarLineChart.vue +411 -0
  17. package/src/components/mixed/index.ts +8 -0
  18. package/src/components/radar/RadarChart.stories.ts +2 -2
  19. package/src/components/radar/RadarChart.vue +203 -157
  20. package/src/main.ts +3 -1
  21. package/src/plugin.ts +2 -0
  22. package/src/services/BarChartFunctions.ts +10 -7
  23. package/src/services/BubbleTooltipService.ts +65 -0
  24. package/src/services/ChartsCommonLegend.ts +86 -58
  25. package/src/services/DoughnutChartFunctions.ts +107 -59
  26. package/src/services/FormatUtilities.ts +1 -1
  27. package/src/services/GenericTooltipService.ts +25 -10
  28. package/src/services/MixedBarLineFunctions.ts +258 -0
  29. package/src/services/RadarChartFunctions.ts +33 -12
  30. package/src/stories/Changelog.mdx +6 -0
  31. package/src/stories/Contributing.mdx +101 -0
  32. package/src/stories/GettingStarted.mdx +92 -0
  33. package/src/stories/SupportAndOnboarding.mdx +44 -0
  34. package/src/types/AxisDefinition.ts +6 -0
  35. package/src/types/BarData.ts +1 -0
  36. package/src/types/MixedBarLineData.ts +7 -0
  37. package/src/types/TooltipChartType.ts +1 -0
@@ -1,16 +1,17 @@
1
- import type { Ref } from 'vue';
2
- import type { HTMLLegendPlugin } from "../types/Chart";
3
- import type { ChartOptions } from 'chart.js';
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 { formatValueAndRate } from './FormatUtilities';
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 = 18;
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 = '12px'
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, disableAccessibility.value);
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 = '2px';
166
-
167
- boxSpan.onmouseover = ():void => {
168
- isDoughnut ? onHoverIndex.value = index : onHoverIndex.dataSetIndex = index;
169
- };
170
- boxSpan.onmouseleave = (): void => {
171
- isDoughnut ? onHoverIndex.value = null : onHoverIndex.dataSetIndex = null;
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, disableAccessibility: boolean): HTMLElement {
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, disableAccessibility);
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
- if (allCheckBoxesVisible) {
185
- if (isDoughnut) {
186
- onHoverIndex.value = -1;
187
- selectMode.value = false;
188
- } else {
189
- onHoverIndex.dataSetIndex = -1;
192
+ if (allCheckBoxesVisible) {
193
+ if (isDoughnut) {
194
+ selectMode.value = false;
195
+ onHoverIndex.value = -1;
196
+ }
197
+ return checkbox;
190
198
  }
191
- return checkbox;
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 = item.fillStyle;
227
+ boxSpan.style.background = 'rgba(0, 0, 0, 0.1)';
218
228
  boxSpan.style.borderColor = item.strokeStyle;
219
- boxSpan.style.borderWidth = item.lineWidth + 'px';
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 + 'px';
236
+ boxSpan.style.width = LEGEND_BOX_SIZE;
227
237
  boxSpan.style.marginRight = LEGEND_LABEL_LEFT_MARGIN;
228
- boxSpan.style.height = LEGEND_BOX_SIZE + 'px';
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 = item.lineWidth + 'px';
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, disableAccessibility: boolean) {
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
- backgroundColor = disableAccessibility? item.fillStyle : item.strokeStyle;
267
- borderColor = item.strokeStyle;
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 + 4 + 'px'};
273
- height: ${LEGEND_BOX_SIZE + 4 + 'px'};
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, disableAccessibility: boolean = false) {
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 = isDoughnut ? chart.getDataVisibility(index) : chart.isDatasetVisible(index);
285
- addCheckboxStyle(isDataSetVisible, item, checkbox, disableAccessibility);
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.isDatasetVisible(dataIndex);
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
- if (index === 0) {
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 'vue';
2
- import type { Ref } from 'vue';
3
- import {
4
- getHtmlLegendPlugin
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 ChartDesign from './patterns/ChartDesign';
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(legendContainer: Ref, selectMode: Ref<boolean>, disableAccessibility: Ref<boolean>, patternsColors: Ref<string[]>, patternsList: Ref<((hover: boolean, color: string, disableAccessibility: boolean) => CanvasPattern)[]>, maxValueToDisplay: number, doughnutData: any) {
17
- return getHtmlLegendPlugin(legendContainer, selectMode, onHoverIndex, disableAccessibility, patternsColors, patternsList, maxValueToDisplay, doughnutData);
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
- function getBackgroundColor(patternsColors: string[], patternsList: ((hover: boolean, color: string, disableAccessibility: boolean) => CanvasPattern)[], disableAccessibility: boolean) {
22
- if (onHoverIndex.value !== null) {
23
- return patternsList
24
- .map((pattern, index) => onHoverIndex.value === index ? pattern(false, patternsColors[index], disableAccessibility) : pattern(true, patternsColors[index], disableAccessibility));
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
- .map((pattern, index) => pattern(false, patternsColors[index], disableAccessibility),);
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) => onHoverIndex.value === index ? color : addAlpha(color, 0.2));
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
- function getOnHoverOptions () {
41
- return (_ignore: unknown, activeElements: Array<any>): void => {
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(labels: string[], data: any[], maxValues: number) {
55
- let truncatedLabels = labels.slice(0);
56
- let truncatedData = data.slice(0);
57
- if (labels.length > maxValues){
58
- truncatedData = groupDataAfterNthValue(data, maxValues);
59
- truncatedLabels = truncatedLabels.slice(0, maxValues - 1);
60
- truncatedLabels.push('others');
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 (data: any, maxValues: number): any[] {
66
- if (maxValues < 1) {
67
- return data;
68
- }
69
- let truncatedData = data.slice(0);
70
- if (data.length > maxValues) {
71
- truncatedData = truncatedData.slice(0, maxValues);
72
- truncatedData[maxValues - 1] = data.slice(maxValues).reduce((result: any, current: any) => {
73
- result.rate += current.rate;
74
- result.value += current.value;
75
- return result;
76
- }, {
77
- rate: data[maxValues - 1].rate,
78
- value: data[maxValues - 1].value
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 | null): 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
- private handleTooltipPosition
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
- private createNewTooltipElement () {
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();