@mozaic-ds/chart 0.1.0-beta.4 → 0.1.0-beta.40

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 (59) hide show
  1. package/README.md +85 -9
  2. package/dist/mozaic-chart.js +4747 -2614
  3. package/dist/mozaic-chart.umd.cjs +17 -11
  4. package/dist/style.css +1 -1
  5. package/package.json +24 -11
  6. package/src/assets/base.css +1 -1
  7. package/src/assets/img/bubbles.svg +4 -0
  8. package/src/components/bar/BarChart.stories.ts +181 -101
  9. package/src/components/bar/BarChart.vue +370 -139
  10. package/src/components/bar/index.ts +3 -3
  11. package/src/components/bubble/BubbleChart.stories.ts +66 -0
  12. package/src/components/bubble/BubbleChart.vue +432 -0
  13. package/src/components/bubble/index.ts +8 -0
  14. package/src/components/doughnut/DoughnutChart.stories.ts +38 -36
  15. package/src/components/doughnut/DoughnutChart.vue +243 -114
  16. package/src/components/doughnut/index.ts +3 -3
  17. package/src/components/index.ts +4 -4
  18. package/src/components/line/LineChart.stories.ts +52 -27
  19. package/src/components/line/LineChart.vue +381 -255
  20. package/src/components/line/index.ts +3 -3
  21. package/src/components/mixed/MixedBarLineChart.stories.ts +91 -0
  22. package/src/components/mixed/MixedBarLineChart.vue +469 -0
  23. package/src/components/mixed/index.ts +8 -0
  24. package/src/components/radar/RadarChart.stories.ts +102 -102
  25. package/src/components/radar/RadarChart.vue +222 -167
  26. package/src/components/radar/index.ts +3 -3
  27. package/src/main.ts +14 -5
  28. package/src/plugin.ts +9 -7
  29. package/src/services/BarChartFunctions.ts +139 -35
  30. package/src/services/BubbleTooltipService.ts +67 -0
  31. package/src/services/ChartsCommonLegend.ts +315 -139
  32. package/src/services/ColorFunctions.ts +1 -1
  33. package/src/services/DoughnutChartFunctions.ts +132 -55
  34. package/src/services/FormatUtilities.ts +25 -19
  35. package/src/services/GenericTooltipService.ts +141 -66
  36. package/src/services/MixedBarLineFunctions.ts +262 -0
  37. package/src/services/PatternFunctions.ts +25 -18
  38. package/src/services/RadarChartFunctions.ts +39 -12
  39. package/src/services/patterns/ChartDesign.ts +35 -24
  40. package/src/services/patterns/patternCircles.ts +63 -36
  41. package/src/services/patterns/patternDashedDiagonals.ts +64 -57
  42. package/src/services/patterns/patternDiagonals.ts +138 -106
  43. package/src/services/patterns/patternSquares.ts +86 -80
  44. package/src/services/patterns/patternVerticalLines.ts +76 -69
  45. package/src/services/patterns/patternZigzag.ts +92 -85
  46. package/src/stories/Changelog.mdx +6 -0
  47. package/src/stories/Contributing.mdx +101 -0
  48. package/src/stories/GettingStarted.mdx +92 -0
  49. package/src/stories/SupportAndOnboarding.mdx +44 -0
  50. package/src/types/AxisDefinition.ts +4 -0
  51. package/src/types/BarData.ts +1 -0
  52. package/src/types/Chart.ts +9 -7
  53. package/src/types/DoughnutData.ts +8 -0
  54. package/src/types/GenericData.ts +10 -10
  55. package/src/types/LineChart.ts +5 -4
  56. package/src/types/MixedBarLineData.ts +7 -0
  57. package/src/types/RadarData.ts +33 -29
  58. package/src/types/TooltipChartType.ts +7 -6
  59. package/src/vite-env.d.ts +3 -3
@@ -0,0 +1,66 @@
1
+ // BubbleChart.stories.ts
2
+
3
+ import type { Meta, StoryObj } from '@storybook/vue3';
4
+ import BubbleChart from './BubbleChart.vue';
5
+
6
+ const meta = {
7
+ title: 'Charts/Bubble',
8
+ component: BubbleChart
9
+ } satisfies Meta<typeof BubbleChart>;
10
+
11
+ export default meta;
12
+ type Story = StoryObj<typeof meta>;
13
+
14
+ export const Default = {
15
+ args: {
16
+ width: '800px',
17
+ height: '500px',
18
+ labels: ['Serie 1', 'Serie 2', 'Serie 3', 'Serie 4'],
19
+ colours: [0, 4, 1, 2],
20
+ shapes: ['rectRot', 'triangle', 'circle', 'rect'],
21
+ colourSet: 4,
22
+ datasets: [
23
+ [
24
+ {
25
+ x: 20000,
26
+ y: 25,
27
+ r: 5
28
+ },
29
+ {
30
+ x: 10000,
31
+ y: 505,
32
+ r: 15
33
+ }
34
+ ],
35
+ [
36
+ {
37
+ x: 10000,
38
+ y: 30,
39
+ r: 20
40
+ },
41
+ {
42
+ x: 10,
43
+ y: 300,
44
+ r: 200
45
+ }
46
+ ],
47
+ [
48
+ {
49
+ x: 5000,
50
+ y: 320,
51
+ r: 100
52
+ }
53
+ ],
54
+ [
55
+ {
56
+ x: 18000,
57
+ y: 8,
58
+ r: 30
59
+ }
60
+ ]
61
+ ],
62
+ xAxis: { title: 'Data 1', unit: '€' },
63
+ yAxis: { title: 'Data 2', unit: 'D' },
64
+ rAxis: { title: 'Data 3', unit: '%' }
65
+ }
66
+ } satisfies Story;
@@ -0,0 +1,432 @@
1
+ <template>
2
+ <div class="container">
3
+ <div class="main">
4
+ <Bubble
5
+ v-if="chartData"
6
+ ref="bubbleChartRef"
7
+ :id="chartId"
8
+ :data="chartData"
9
+ :options="options"
10
+ :class="cssClasses"
11
+ :style="[{ width, height, cursor: 'pointer' }, styles]"
12
+ />
13
+ </div>
14
+ <div class="chart-legend">
15
+ <img
16
+ src="../../assets/img/bubbles.svg"
17
+ :alt="rAxis.title"
18
+ class="bubble-icon mu-mr-025"
19
+ />
20
+ <div class="size-legend-label">
21
+ {{ rAxis.title }}
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </template>
26
+
27
+ <script setup lang="ts">
28
+ import { computed, PropType } from 'vue';
29
+ import { Bubble } from 'vue-chartjs';
30
+ import ChartDataLabels from 'chartjs-plugin-datalabels';
31
+ import { addAlpha } from '../../services/ColorFunctions';
32
+
33
+ import {
34
+ CategoryScale,
35
+ Chart as ChartJS,
36
+ Legend,
37
+ LinearScale,
38
+ Plugin,
39
+ PointElement,
40
+ Title,
41
+ Tooltip
42
+ } from 'chart.js';
43
+ import ChartDesign from '../../services/patterns/ChartDesign';
44
+ import { Context } from '../../services/GenericTooltipService';
45
+ import { BubbleTooltipService } from '../../services/BubbleTooltipService';
46
+ import { formatDecimalNumber } from '../../services/FormatUtilities';
47
+ import { AxisDefinition } from '../../types/AxisDefinition';
48
+
49
+ const defaultDataLabels = {
50
+ _listened: false,
51
+ _listeners: {},
52
+ _datasets: [],
53
+ _labels: [],
54
+ _actives: []
55
+ };
56
+
57
+ // Create a patched version of ChartDataLabels that handles missing context
58
+ const PatchedChartDataLabels: Plugin = {
59
+ ...ChartDataLabels,
60
+ beforeUpdate(chart: any, args: any, options: any) {
61
+ if (!chart.$datalabels) {
62
+ chart.$datalabels = defaultDataLabels;
63
+ }
64
+ return ChartDataLabels.beforeUpdate?.(chart, args, options);
65
+ },
66
+ beforeEvent(chart: any, args: any, options: any) {
67
+ if (!chart.$datalabels) {
68
+ chart.$datalabels = defaultDataLabels;
69
+ }
70
+ return ChartDataLabels.beforeEvent?.(chart, args, options);
71
+ }
72
+ };
73
+
74
+ ChartJS.register(
75
+ Title,
76
+ Tooltip,
77
+ Legend,
78
+ PointElement,
79
+ CategoryScale,
80
+ LinearScale,
81
+ PatchedChartDataLabels
82
+ );
83
+
84
+ const { colourSets } = ChartDesign();
85
+
86
+ const bubbleDataProps = defineProps({
87
+ /**
88
+ * Value of the id attribute present on the <canvas> tag element the chart
89
+ */
90
+ chartId: {
91
+ type: String,
92
+ default: 'bubble-chart'
93
+ },
94
+ /**
95
+ * Labels used to label the series. See [Data structures documentation](https://www.chartjs.org/docs/latest/general/data-structures.html)
96
+ */
97
+ labels: {
98
+ type: Array as PropType<string[]>,
99
+ default: () => []
100
+ },
101
+ /**
102
+ * Used to choose the colour set of the charts as defined in the Figma prototypes.
103
+ * 7 colour sets are currently defined:
104
+ * - Default 0 corresponds to the current one
105
+ * - 1 to 6 corresponds to the "new" [colour sets](https://www.figma.com/file/Hn6PyvnR385Ta0XN3KqOI9/04.-Dataviz---Documentation-(read-only)?type=design&node-id=1-69316&mode=design&t=sDytQ5BipsryWkuA-0)
106
+ * Note: All the sets are defined in /src/services/patterns/ChartDesign.ts
107
+ */
108
+ colourSet: {
109
+ type: Number,
110
+ default: 0
111
+ },
112
+ /**
113
+ * 6 colors exist in the colourSet (0 to 5)
114
+ * In some use cases, you may need to specify the colours for each dataset
115
+ */
116
+ colours: {
117
+ type: Array as PropType<number[]>,
118
+ default: () => []
119
+ },
120
+ /**
121
+ * In some use cases, you may need to specify the shapes for each dataset
122
+ * Default shape is circle, implementation is done using the Point Styles of chartjs :
123
+ * cf. https://www.chartjs.org/docs/latest/configuration/elements.html#point-styles
124
+ */
125
+ shapes: {
126
+ type: Array as PropType<string[]>,
127
+ default: () => []
128
+ },
129
+ /**
130
+ * Value of the `datasets` key present in the `data` object passed to the Chart config
131
+ */
132
+ datasets: {
133
+ type: Array as PropType<any[]>,
134
+ default: () => []
135
+ },
136
+ /**
137
+ * Value of the `width` css property used to define the width of the <canvas> element
138
+ */
139
+ width: {
140
+ type: String,
141
+ default: '400px'
142
+ },
143
+ /**
144
+ * Value of the `height` css property used to define the height of the <canvas> element
145
+ */
146
+ height: {
147
+ type: String,
148
+ default: '300px'
149
+ },
150
+ /**
151
+ * Add custom CSS classes to the <canvas> element
152
+ */
153
+ cssClasses: {
154
+ type: String,
155
+ default: undefined
156
+ },
157
+ /**
158
+ * Add custom CSS styles to the <canvas> element
159
+ */
160
+ styles: {
161
+ type: Object as PropType<Partial<CSSStyleDeclaration>>,
162
+ default: () => {}
163
+ },
164
+ /**
165
+ * Minimum size for a bubble
166
+ */
167
+ bubbleMin: {
168
+ type: Number,
169
+ default: 10
170
+ },
171
+ /**
172
+ * Maximum size for a bubble
173
+ */
174
+ bubbleMax: {
175
+ type: Number,
176
+ default: 40
177
+ },
178
+ /**
179
+ * Value of the `plugins` key passed to the Chart config
180
+ */
181
+ plugins: {
182
+ type: Array as PropType<Plugin<any>[]>,
183
+ default: () => []
184
+ },
185
+ /**
186
+ * If set to true the label of the dataserie will be shown on top of the bubble
187
+ */
188
+ displayBubbleLabel: {
189
+ type: Boolean,
190
+ default: false
191
+ },
192
+ /**
193
+ * X axis data : title and unit
194
+ */
195
+ xAxis: {
196
+ type: Object as PropType<AxisDefinition>,
197
+ default: null,
198
+ required: true
199
+ },
200
+ /**
201
+ * Y axis data : title and unit
202
+ */
203
+ yAxis: {
204
+ type: Object as PropType<AxisDefinition>,
205
+ default: null,
206
+ required: true
207
+ },
208
+ /**
209
+ * X axis data : title and unit
210
+ */
211
+ rAxis: {
212
+ type: Object as PropType<AxisDefinition>,
213
+ default: null,
214
+ required: true
215
+ },
216
+ /**
217
+ * Show axis labels
218
+ */
219
+ displayAxisLabels: {
220
+ type: Boolean,
221
+ default: true
222
+ },
223
+ /**
224
+ * Value of the minimum number of fraction digits used to format the x values
225
+ */
226
+ xMinimumFractionDigits: {
227
+ type: Number,
228
+ required: false
229
+ },
230
+ /**
231
+ * Value of the maximum number of fraction digits used to format the x values
232
+ */
233
+ xMaximumFractionDigits: {
234
+ type: Number,
235
+ required: false
236
+ },
237
+ /**
238
+ * Value of the minimum number of fraction digits used to format the y values
239
+ */
240
+ yMinimumFractionDigits: {
241
+ type: Number,
242
+ required: false
243
+ },
244
+ /**
245
+ * Value of the maximum number of fraction digits used to format the y values
246
+ */
247
+ yMaximumFractionDigits: {
248
+ type: Number,
249
+ required: false
250
+ },
251
+ /**
252
+ * Value of the minimum number of fraction digits used to format the r values
253
+ */
254
+ rMinimumFractionDigits: {
255
+ type: Number,
256
+ required: false
257
+ },
258
+ /**
259
+ * Value of the maximum number of fraction digits used to format the r values
260
+ */
261
+ rMaximumFractionDigits: {
262
+ type: Number,
263
+ required: false
264
+ }
265
+ });
266
+
267
+ const normalizeDatasets = function (dataSets: Array<Array<any>>) {
268
+ const rValues: Array<number> = [];
269
+ dataSets.forEach((dataSerie: Array<any>) => {
270
+ dataSerie.forEach((item: any) => {
271
+ rValues.push(item.r);
272
+ });
273
+ });
274
+ const max = Math.max(...rValues);
275
+ const min = Math.min(...rValues);
276
+ const rMax = bubbleDataProps.bubbleMax;
277
+ const rMin = bubbleDataProps.bubbleMin;
278
+
279
+ return dataSets.map((dataSerie: Array<any>) => {
280
+ if (max === min) {
281
+ return dataSerie.map((item) => {
282
+ return {
283
+ x: item.x,
284
+ y: item.y,
285
+ r: rMin + (rMax - rMin) / 2
286
+ };
287
+ });
288
+ } else {
289
+ return dataSerie.map((item) => {
290
+ return {
291
+ x: item.x,
292
+ y: item.y,
293
+ r: rMin + ((item.r - min) * (rMax - rMin)) / (max - min)
294
+ };
295
+ });
296
+ }
297
+ });
298
+ };
299
+
300
+ const chartData = computed(() => {
301
+ const chartColourSet = colourSets[bubbleDataProps.colourSet];
302
+ return {
303
+ datasets: normalizeDatasets(bubbleDataProps.datasets).map(
304
+ (data, index) => ({
305
+ data: data,
306
+ pointStyle: bubbleDataProps.shapes[index],
307
+ backgroundColor: addAlpha(
308
+ chartColourSet[bubbleDataProps.colours[index]],
309
+ 0.2
310
+ ),
311
+ borderColor: chartColourSet[bubbleDataProps.colours[index]],
312
+ label: bubbleDataProps.labels[index]
313
+ })
314
+ )
315
+ };
316
+ });
317
+
318
+ const options = computed(() => ({
319
+ responsive: false,
320
+ // eslint-disable-next-line
321
+ scales: {
322
+ x: {
323
+ offset: true,
324
+ title: {
325
+ display: bubbleDataProps.displayAxisLabels,
326
+ text: bubbleDataProps.xAxis.title
327
+ }
328
+ },
329
+ y: {
330
+ offset: true,
331
+ title: {
332
+ display: bubbleDataProps.displayAxisLabels,
333
+ text: bubbleDataProps.yAxis.title
334
+ }
335
+ }
336
+ },
337
+ plugins: {
338
+ legend: {
339
+ display: false
340
+ },
341
+ title: {
342
+ display: false
343
+ },
344
+ datalabels: {
345
+ display: bubbleDataProps.displayBubbleLabel,
346
+ anchor: 'end' as const,
347
+ align: 'end' as const,
348
+ color: 'black',
349
+ formatter: function <T extends { dataset: any }>(
350
+ _value: any,
351
+ context: T
352
+ ) {
353
+ return context.dataset.label;
354
+ },
355
+ padding: 0
356
+ },
357
+ tooltip: {
358
+ enabled: false,
359
+ position: 'nearest' as const,
360
+ external: function (context: Context) {
361
+ const datasetIndex: number =
362
+ context.tooltip?.dataPoints?.[0].datasetIndex || 0;
363
+ const dataIndex: number =
364
+ context.tooltip.dataPoints?.[0].dataIndex || 0;
365
+ const currentBubble: { x: number; y: number; r: number } =
366
+ bubbleDataProps.datasets[datasetIndex][dataIndex];
367
+ new BubbleTooltipService().createBubbleTooltip(
368
+ context,
369
+ getTooltipData(currentBubble),
370
+ bubbleDataProps.labels[datasetIndex]
371
+ );
372
+ }
373
+ }
374
+ }
375
+ }));
376
+
377
+ function getTooltipData(currentBubble: { x: number; y: number; r: number }) {
378
+ return [
379
+ {
380
+ label: bubbleDataProps.xAxis.title,
381
+ value: `${formatDecimalNumber(currentBubble.x, bubbleDataProps.xMinimumFractionDigits, bubbleDataProps.xMaximumFractionDigits)}`,
382
+ unit: bubbleDataProps.xAxis?.unit
383
+ },
384
+ {
385
+ label: bubbleDataProps.yAxis.title,
386
+ value: `${formatDecimalNumber(currentBubble.y, bubbleDataProps.yMinimumFractionDigits, bubbleDataProps.yMaximumFractionDigits)}`,
387
+ unit: bubbleDataProps.yAxis?.unit
388
+ },
389
+ {
390
+ label: bubbleDataProps.rAxis.title,
391
+ value: `${formatDecimalNumber(currentBubble.r, bubbleDataProps.rMinimumFractionDigits, bubbleDataProps.rMaximumFractionDigits)}`,
392
+ unit: bubbleDataProps.rAxis?.unit
393
+ }
394
+ ];
395
+ }
396
+ </script>
397
+
398
+ <style lang="scss">
399
+ @import 'settings-tools/all-settings';
400
+ @import 'components/c.checkbox';
401
+ </style>
402
+
403
+ <style scoped>
404
+ .container {
405
+ -moz-osx-font-smoothing: grayscale;
406
+ -webkit-font-smoothing: antialiased;
407
+ font-weight: 400;
408
+ font-family: 'Roboto', sans-serif;
409
+ }
410
+
411
+ .main {
412
+ display: flex;
413
+ flex-direction: column;
414
+ justify-content: center;
415
+ align-items: center;
416
+ margin-bottom: 20px;
417
+ }
418
+
419
+ .chart-legend {
420
+ display: flex;
421
+ gap: 4px;
422
+ font-size: 14px;
423
+ align-items: center;
424
+ margin: 1.375rem 1.0625rem;
425
+ color: rgb(102, 102, 102);
426
+ }
427
+
428
+ .bubble-icon {
429
+ width: 16px;
430
+ height: 16px;
431
+ }
432
+ </style>
@@ -0,0 +1,8 @@
1
+ import type { App } from 'vue';
2
+ import BubbleChart from './BubbleChart.vue';
3
+
4
+ BubbleChart.install = (app: App) => {
5
+ app.component('BubbleChart', BubbleChart);
6
+ };
7
+
8
+ export { BubbleChart };
@@ -1,11 +1,11 @@
1
1
  // DoughnutChart.stories.ts;
2
2
 
3
- import type { Meta, StoryObj } from "@storybook/vue3";
4
- import DoughnutChart from "./DoughnutChart.vue";
3
+ import type { Meta, StoryObj } from '@storybook/vue3';
4
+ import DoughnutChart from './DoughnutChart.vue';
5
5
 
6
6
  const meta = {
7
- title: "Charts/Doughnut",
8
- component: DoughnutChart,
7
+ title: 'Charts/Doughnut',
8
+ component: DoughnutChart
9
9
  } satisfies Meta<typeof DoughnutChart>;
10
10
 
11
11
  export default meta;
@@ -13,70 +13,72 @@ type Story = StoryObj<typeof meta>;
13
13
 
14
14
  export const Default = {
15
15
  args: {
16
- height: "400px",
17
- width: "400px",
18
- labels: ["Data One", "Data Two"],
16
+ height: '400px',
17
+ width: '400px',
18
+ labels: ['Data One', 'Data Two'],
19
+ enableCenteredLabel: true,
19
20
  disableAccessibility: false,
20
21
  data: [
21
22
  {
22
23
  value: 2771824.19,
23
- unit: "",
24
- rate: 30.186240355262925,
24
+ unit: '',
25
+ rate: 30.186240355262925
25
26
  },
26
27
  {
27
28
  value: 1715453.65,
28
- unit: "",
29
- rate: 18.68195550931139,
30
- },
29
+ unit: '',
30
+ rate: 18.68195550931139
31
+ }
31
32
  ],
32
- },
33
+ maxValues: 2
34
+ }
33
35
  } satisfies Story;
34
36
 
35
37
  export const MultipleData = {
36
38
  args: {
37
- height: "400px",
38
- width: "400px",
39
+ height: '400px',
40
+ width: '400px',
39
41
  labels: [
40
- "Data One",
41
- "Data Two",
42
- "Data Three",
43
- "Data Four",
44
- "Data Five",
45
- "Data Six",
42
+ 'Data One',
43
+ 'Data Two',
44
+ 'Data Three',
45
+ 'Data Four',
46
+ 'Data Five',
47
+ 'Data Six'
46
48
  ],
47
49
  maxValues: 3,
48
50
  disableAccessibility: false,
49
51
  data: [
50
52
  {
51
53
  value: 2771824.19,
52
- unit: "",
53
- rate: 30.186240355262925,
54
+ unit: '',
55
+ rate: 30.186240355262925
54
56
  },
55
57
  {
56
58
  value: 1715453.65,
57
- unit: "",
58
- rate: 18.68195550931139,
59
+ unit: '',
60
+ rate: 18.68195550931139
59
61
  },
60
62
  {
61
63
  value: 1651575.28,
62
- unit: "",
63
- rate: 17.986295287685856,
64
+ unit: '',
65
+ rate: 17.986295287685856
64
66
  },
65
67
  {
66
68
  value: 1168958.3,
67
- unit: "",
68
- rate: 12.730409214402426,
69
+ unit: '',
70
+ rate: 12.730409214402426
69
71
  },
70
72
  {
71
73
  value: 949837.87,
72
- unit: "",
73
- rate: 10.34410275579238,
74
+ unit: '',
75
+ rate: 10.34410275579238
74
76
  },
75
77
  {
76
78
  value: 924760.17,
77
- unit: "",
78
- rate: 10.070996877545035,
79
- },
80
- ],
81
- },
79
+ unit: '',
80
+ rate: 10.070996877545035
81
+ }
82
+ ]
83
+ }
82
84
  } satisfies Story;