@mozaic-ds/chart 0.1.0-beta.0

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 (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +16 -0
  3. package/dist/mozaic-chart.js +9858 -0
  4. package/dist/mozaic-chart.umd.cjs +22 -0
  5. package/dist/style.css +1 -0
  6. package/dist/vite.svg +1 -0
  7. package/package.json +79 -0
  8. package/src/assets/base.css +2 -0
  9. package/src/components/bar/BarChart.stories.ts +298 -0
  10. package/src/components/bar/BarChart.vue +247 -0
  11. package/src/components/doughnut/DoughnutChart.stories.ts +80 -0
  12. package/src/components/doughnut/DoughnutChart.vue +208 -0
  13. package/src/components/line/LineChart.stories.ts +60 -0
  14. package/src/components/line/LineChart.vue +245 -0
  15. package/src/components/radar/RadarChart.stories.ts +346 -0
  16. package/src/components/radar/RadarChart.vue +265 -0
  17. package/src/main.ts +6 -0
  18. package/src/services/BarChartFunctions.ts +126 -0
  19. package/src/services/ChartsCommonLegend.ts +366 -0
  20. package/src/services/DoughnutChartFunctions.ts +89 -0
  21. package/src/services/FormatUtilities.ts +30 -0
  22. package/src/services/GenericTooltipService.ts +305 -0
  23. package/src/services/PatternFunctions.ts +25 -0
  24. package/src/services/RadarChartFunctions.ts +70 -0
  25. package/src/services/patterns/ChartDesign.ts +27 -0
  26. package/src/services/patterns/patternCircles.ts +82 -0
  27. package/src/services/patterns/patternDashedDiagonals.ts +66 -0
  28. package/src/services/patterns/patternDiagonals.ts +101 -0
  29. package/src/services/patterns/patternSquares.ts +76 -0
  30. package/src/services/patterns/patternVerticalLines.ts +61 -0
  31. package/src/services/patterns/patternZigzag.ts +88 -0
  32. package/src/types/BarData.ts +11 -0
  33. package/src/types/ButtonName.ts +7 -0
  34. package/src/types/Chart.ts +10 -0
  35. package/src/types/DoughnutData.ts +6 -0
  36. package/src/types/GenericData.ts +11 -0
  37. package/src/types/LineChart.ts +5 -0
  38. package/src/types/RadarData.ts +36 -0
  39. package/src/types/TooltipChartType.ts +7 -0
  40. package/src/vite-env.d.ts +7 -0
@@ -0,0 +1,346 @@
1
+ // RadarChart.stories.ts
2
+
3
+ import type { Meta, StoryObj } from "@storybook/vue3";
4
+ import RadarChart from "./RadarChart.vue";
5
+
6
+ const meta = {
7
+ title: "Charts/Radar",
8
+ component: RadarChart,
9
+ } satisfies Meta<typeof RadarChart>;
10
+
11
+ export default meta;
12
+ type Story = StoryObj<typeof meta>;
13
+
14
+ export const Default = {
15
+ args: {
16
+ height: "400px",
17
+ labels: ["Label 1", "Label 2", "Label 3", "Label 4", "Label 5"],
18
+ areas: [
19
+ {
20
+ label: "currentYear",
21
+ areaData: [
22
+ {
23
+ value: 88.524115665,
24
+ position: 60.98,
25
+ unit: "D",
26
+ label: null,
27
+ rate: null,
28
+ color: "red",
29
+ trendValue: null,
30
+ trendUnit: null,
31
+ tooltips: null,
32
+ },
33
+ {
34
+ value: -3.5998021,
35
+ position: 46.4,
36
+ unit: "%",
37
+ label: null,
38
+ rate: null,
39
+ color: "green",
40
+ trendValue: null,
41
+ trendUnit: null,
42
+ tooltips: null,
43
+ },
44
+ {
45
+ value: 3.1604936,
46
+ position: 53.16,
47
+ unit: "%",
48
+ label: null,
49
+ rate: null,
50
+ color: "green",
51
+ trendValue: null,
52
+ trendUnit: null,
53
+ tooltips: null,
54
+ },
55
+ {
56
+ value: 7.787256,
57
+ position: 57.79,
58
+ unit: "%",
59
+ label: null,
60
+ rate: null,
61
+ color: "green",
62
+ trendValue: null,
63
+ trendUnit: null,
64
+ tooltips: null,
65
+ },
66
+ {
67
+ value: 62.2866732,
68
+ position: 79.76,
69
+ unit: "%",
70
+ label: null,
71
+ rate: null,
72
+ color: "red",
73
+ trendValue: null,
74
+ trendUnit: null,
75
+ tooltips: null,
76
+ },
77
+ ],
78
+ },
79
+ {
80
+ label: "previousYear",
81
+ areaData: [
82
+ {
83
+ value: 78.752887008,
84
+ position: 67.5,
85
+ unit: "D",
86
+ label: null,
87
+ rate: null,
88
+ color: null,
89
+ trendValue: null,
90
+ trendUnit: null,
91
+ tooltips: null,
92
+ },
93
+ {
94
+ value: -22.7389942,
95
+ position: 27.26,
96
+ unit: "%",
97
+ label: null,
98
+ rate: null,
99
+ color: null,
100
+ trendValue: null,
101
+ trendUnit: null,
102
+ tooltips: null,
103
+ },
104
+ {
105
+ value: -4.9793614,
106
+ position: 45.02,
107
+ unit: "%",
108
+ label: null,
109
+ rate: null,
110
+ color: null,
111
+ trendValue: null,
112
+ trendUnit: null,
113
+ tooltips: null,
114
+ },
115
+ ],
116
+ },
117
+ ],
118
+ },
119
+ } satisfies Story;
120
+
121
+ export const MultipleData = {
122
+ args: {
123
+ height: "400px",
124
+ labels: [
125
+ "Label 1",
126
+ "Label 2",
127
+ "Label 3",
128
+ "Label 4",
129
+ "Label 5",
130
+ "Label 6",
131
+ "Label 7",
132
+ "Label 8",
133
+ "Label 9",
134
+ ],
135
+ areas: [
136
+ {
137
+ label: "currentYear",
138
+ areaData: [
139
+ {
140
+ value: 88.524115665,
141
+ position: 60.98,
142
+ unit: "D",
143
+ label: null,
144
+ rate: null,
145
+ color: "red",
146
+ trendValue: null,
147
+ trendUnit: null,
148
+ tooltips: null,
149
+ },
150
+ {
151
+ value: -3.5998021,
152
+ position: 46.4,
153
+ unit: "%",
154
+ label: null,
155
+ rate: null,
156
+ color: "green",
157
+ trendValue: null,
158
+ trendUnit: null,
159
+ tooltips: null,
160
+ },
161
+ {
162
+ value: 3.1604936,
163
+ position: 53.16,
164
+ unit: "%",
165
+ label: null,
166
+ rate: null,
167
+ color: "green",
168
+ trendValue: null,
169
+ trendUnit: null,
170
+ tooltips: null,
171
+ },
172
+ {
173
+ value: 7.787256,
174
+ position: 57.79,
175
+ unit: "%",
176
+ label: null,
177
+ rate: null,
178
+ color: "green",
179
+ trendValue: null,
180
+ trendUnit: null,
181
+ tooltips: null,
182
+ },
183
+ {
184
+ value: 62.2866732,
185
+ position: 79.76,
186
+ unit: "%",
187
+ label: null,
188
+ rate: null,
189
+ color: "red",
190
+ trendValue: null,
191
+ trendUnit: null,
192
+ tooltips: null,
193
+ },
194
+ {
195
+ value: 3.8,
196
+ position: 76,
197
+ unit: "*",
198
+ label: null,
199
+ rate: null,
200
+ color: "red",
201
+ trendValue: null,
202
+ trendUnit: null,
203
+ tooltips: null,
204
+ },
205
+ {
206
+ value: 86.8082515,
207
+ position: 89.45,
208
+ unit: "%",
209
+ label: null,
210
+ rate: null,
211
+ color: "green",
212
+ trendValue: null,
213
+ trendUnit: null,
214
+ tooltips: null,
215
+ },
216
+ {
217
+ value: 94.8386888,
218
+ position: 79.35,
219
+ unit: "%",
220
+ label: null,
221
+ rate: null,
222
+ color: "red",
223
+ trendValue: null,
224
+ trendUnit: null,
225
+ tooltips: null,
226
+ },
227
+ {
228
+ value: 72.2144111,
229
+ position: 54.81,
230
+ unit: "%",
231
+ label: null,
232
+ rate: null,
233
+ color: "red",
234
+ trendValue: null,
235
+ trendUnit: null,
236
+ tooltips: null,
237
+ },
238
+ ],
239
+ },
240
+ {
241
+ label: "previousYear",
242
+ areaData: [
243
+ {
244
+ value: 78.752887008,
245
+ position: 67.5,
246
+ unit: "D",
247
+ label: null,
248
+ rate: null,
249
+ color: null,
250
+ trendValue: null,
251
+ trendUnit: null,
252
+ tooltips: null,
253
+ },
254
+ {
255
+ value: -22.7389942,
256
+ position: 27.26,
257
+ unit: "%",
258
+ label: null,
259
+ rate: null,
260
+ color: null,
261
+ trendValue: null,
262
+ trendUnit: null,
263
+ tooltips: null,
264
+ },
265
+ {
266
+ value: -4.9793614,
267
+ position: 45.02,
268
+ unit: "%",
269
+ label: null,
270
+ rate: null,
271
+ color: null,
272
+ trendValue: null,
273
+ trendUnit: null,
274
+ tooltips: null,
275
+ },
276
+ {
277
+ value: -22.8576595,
278
+ position: 27.14,
279
+ unit: "%",
280
+ label: null,
281
+ rate: null,
282
+ color: null,
283
+ trendValue: null,
284
+ trendUnit: null,
285
+ tooltips: null,
286
+ },
287
+ {
288
+ value: 65.1835015,
289
+ position: 83.07,
290
+ unit: "%",
291
+ label: null,
292
+ rate: null,
293
+ color: null,
294
+ trendValue: null,
295
+ trendUnit: null,
296
+ tooltips: null,
297
+ },
298
+ {
299
+ value: 4.181034483,
300
+ position: 83.62,
301
+ unit: "*",
302
+ label: null,
303
+ rate: null,
304
+ color: null,
305
+ trendValue: null,
306
+ trendUnit: null,
307
+ tooltips: null,
308
+ },
309
+ {
310
+ value: 86.8082515,
311
+ position: 89.45,
312
+ unit: "%",
313
+ label: null,
314
+ rate: null,
315
+ color: null,
316
+ trendValue: null,
317
+ trendUnit: null,
318
+ tooltips: null,
319
+ },
320
+ {
321
+ value: 98.120897,
322
+ position: 92.48,
323
+ unit: "%",
324
+ label: null,
325
+ rate: null,
326
+ color: null,
327
+ trendValue: null,
328
+ trendUnit: null,
329
+ tooltips: null,
330
+ },
331
+ {
332
+ value: 97.2715978,
333
+ position: 94.54,
334
+ unit: "%",
335
+ label: null,
336
+ rate: null,
337
+ color: null,
338
+ trendValue: null,
339
+ trendUnit: null,
340
+ tooltips: null,
341
+ },
342
+ ],
343
+ },
344
+ ],
345
+ },
346
+ } satisfies Story;
@@ -0,0 +1,265 @@
1
+ <template>
2
+ <div class="container">
3
+ <div class='main'>
4
+ <Radar
5
+ v-if="radarData"
6
+ :data='radarData'
7
+ :options='chartOptions'
8
+ :plugins="radarPlugins"
9
+ :chart-id='chartId'
10
+ :cssClasses:='cssClasses'
11
+ :styles='styles'
12
+ :style='{ height, cursor:"pointer",}'
13
+ />
14
+ </div>
15
+ <div ref='legendContainer' class='legendContainer' />
16
+ </div>
17
+ </template>
18
+
19
+ <script setup lang='ts'>
20
+ import { PropType, ref, computed } from 'vue';
21
+ import type { Area } from '../../types/RadarData';
22
+ import { Radar } from 'vue-chartjs';
23
+ import type { ActiveElement, ChartData } from 'chart.js';
24
+ import {Context, GenericTooltipService} from '../../services/GenericTooltipService';
25
+ import { formatWithThousandsSeprators } from '../../services/FormatUtilities';
26
+ import { TooltipChartType } from '../../types/TooltipChartType';
27
+ import { drawLabels } from '../../services/RadarChartFunctions';
28
+ import type { Chart, ChartItem } from '../../services/ChartsCommonLegend';
29
+ import {
30
+ Chart as ChartJS,
31
+ Filler,
32
+ Legend,
33
+ LineElement,
34
+ PointElement,
35
+ RadialLinearScale,
36
+ Title,
37
+ Tooltip,
38
+ Plugin
39
+ } from 'chart.js';
40
+
41
+ import {
42
+ createHtmlLegendItemText,
43
+ createHtmlLegendListElement,
44
+ createLegendCheckbox,
45
+ createLegendElementWithSquareArea,
46
+ getOrCreateLegendList,
47
+ hideAllButThis,
48
+ switchItemVisibility
49
+ } from '../../services/ChartsCommonLegend';
50
+
51
+ ChartJS.register(
52
+ Title,
53
+ Tooltip,
54
+ Legend,
55
+ RadialLinearScale,
56
+ LineElement,
57
+ PointElement,
58
+ Filler,
59
+ );
60
+ const radarComponentChartProps = defineProps({
61
+ chartId: {
62
+ type: String,
63
+ default: 'radar-chart',
64
+ },
65
+ height: {
66
+ type: String,
67
+ default: '400px',
68
+ },
69
+ labels: {
70
+ type: Array as PropType<string[]>,
71
+ default: () => []
72
+ },
73
+ areas: {
74
+ type: Array as PropType<Area[]>,
75
+ default: () => []
76
+ },
77
+ cssClasses: {
78
+ default: '',
79
+ type: String,
80
+ },
81
+ styles: {
82
+ type: Object as PropType<Partial<CSSStyleDeclaration>>,
83
+ default: () => {},
84
+ },
85
+ plugins: {
86
+ type: Array as PropType<Plugin<'radar'>[]>,
87
+ default: () => [],
88
+ },
89
+ })
90
+ const radarData = computed<ChartData<'radar'>>(() => ({
91
+ labels: getRadarLabels(),
92
+ datasets: [
93
+ {
94
+ label: 'Data One',
95
+ backgroundColor: '#BFE3E760',
96
+ borderColor: '#0192A0',
97
+ pointBackgroundColor: '#0192A000',
98
+ pointBorderColor: '#0192A0',
99
+ pointBorderWidth: 2,
100
+ borderWidth: 2,
101
+ pointHitRadius: 55,
102
+ pointRadius: 5,
103
+ pointHoverBackgroundColor: '#0192A0',
104
+ pointHoverBorderColor: '#0192A0',
105
+ data: radarComponentChartProps.areas[0].areaData.map((x: { position: number }) => x.position)
106
+ },
107
+ {
108
+ label: 'Data Two',
109
+ backgroundColor: 'rgba(231, 231, 240, .6)',
110
+ borderColor: '#605F9D',
111
+ pointBackgroundColor: 'rgba(231, 231, 240, .6)',
112
+ pointBorderColor: '#605F9D',
113
+ pointBorderWidth: 2,
114
+ borderWidth: 2,
115
+ pointHitRadius: 55,
116
+ pointRadius: 5,
117
+ pointStyle: 'rectRot',
118
+ pointHoverBackgroundColor: '#605F9D',
119
+ pointHoverBorderColor: '#605F9D',
120
+ data: radarComponentChartProps.areas[1].areaData.map((x: { position: number }) => x.position)
121
+ }
122
+ ]
123
+ }));
124
+
125
+ const chartOptions: any = {
126
+ onClick: (_ingnore: unknown, clickedElements: ActiveElement[], chart: Chart) => {
127
+ if (clickedElements[0]) {
128
+ hideAllButThis(chart, clickedElements[0].datasetIndex, selectMode);
129
+ }
130
+ },
131
+ plugins: {
132
+ htmlLegend: {
133
+ containerID: 'legend-container'
134
+ },
135
+ legend: {
136
+ display: false
137
+ },
138
+ title: {
139
+ display: false
140
+ },
141
+ tooltip: {
142
+ enabled: false,
143
+ position: 'nearest' as const,
144
+ external: function (context: Context) {
145
+ new GenericTooltipService().createTooltip(
146
+ context,
147
+ getTooltipData,
148
+ { chartType: TooltipChartType.RADAR }
149
+ );
150
+ }
151
+ }
152
+ },
153
+ layout: {
154
+ padding: 65
155
+ },
156
+ scales: {
157
+ r: {
158
+ min: 0,
159
+ max: 100,
160
+ pointLabels: {
161
+ display: false,
162
+ font: {
163
+ size: 16
164
+ }
165
+ },
166
+ ticks: {
167
+ display: false,
168
+ stepSize: 25
169
+ }
170
+ }
171
+ }
172
+ };
173
+ const legendContainer = ref(null);
174
+ const selectMode = ref(false);
175
+ function splitLabelIfTooLong (axisLabel: string, buildValue: string) {
176
+ const radarLimitLabelLength = 15;
177
+ if (axisLabel.length > radarLimitLabelLength && axisLabel.includes(' ', radarLimitLabelLength)) {
178
+ const indexOfFirstSpaceAfterLimit: number = axisLabel.indexOf(' ', radarLimitLabelLength);
179
+ return [
180
+ axisLabel.substring(0, indexOfFirstSpaceAfterLimit),
181
+ axisLabel.substring(indexOfFirstSpaceAfterLimit),
182
+ buildValue
183
+ ];
184
+ }
185
+ return [
186
+ axisLabel,
187
+ buildValue
188
+ ];
189
+ }
190
+ const getRadarLabels = () => {
191
+ return radarComponentChartProps.labels.map((label: string, index: number) => {
192
+ const buildValue = radarComponentChartProps.areas[0].areaData[index].value
193
+ ? `${formatNumber(radarComponentChartProps.areas[0].areaData[index].value + '')} ${radarComponentChartProps.areas[0].areaData[index].unit}`
194
+ : 'No Data';
195
+ return splitLabelIfTooLong(label, buildValue);
196
+ });
197
+ }
198
+ const formatNumber = (numberFromJson: string) => {
199
+ return formatWithThousandsSeprators(parseFloat(numberFromJson));
200
+ };
201
+ function createLegendElementWithCheckbox (chart: any, item: ChartItem) {
202
+ const liContent = createLegendCheckbox(chart, item);
203
+ liContent.onclick = (e: Event) => {
204
+ switchItemVisibility(chart, item.datasetIndex, selectMode);
205
+ e.stopPropagation();
206
+ };
207
+ return liContent;
208
+ }
209
+
210
+ const radarPlugins = [{
211
+ id: 'htmlLegend',
212
+ afterUpdate (chart: any) {
213
+ const ul = getOrCreateLegendList(legendContainer, 'row');
214
+ while (ul.firstChild) {
215
+ ul.firstChild.remove();
216
+ }
217
+ const items = chart.options.plugins.legend.labels.generateLabels(chart).reverse();
218
+ items.forEach((item: ChartItem) => {
219
+ const li = createHtmlLegendListElement(chart, selectMode, item.datasetIndex);
220
+ let liContent;
221
+ li.style.marginRight = '0.625rem';
222
+ if (!selectMode.value) {
223
+ liContent = createLegendElementWithSquareArea(item);
224
+ } else {
225
+ liContent = createLegendElementWithCheckbox(chart, item);
226
+ }
227
+ li.appendChild(liContent);
228
+ li.appendChild(createHtmlLegendItemText(item));
229
+ ul.appendChild(li);
230
+ });
231
+ }
232
+ },{
233
+ id: 'radarLabelPlugin',
234
+ beforeDraw (chart: any) {
235
+ drawLabels(chart, radarComponentChartProps);
236
+ },
237
+ }];
238
+
239
+ const getTooltipData = (context: Context): string => {
240
+ const datasetIndex: number | undefined = context.tooltip.dataPoints[0].datasetIndex;
241
+ const dataIndex: number | undefined = context.tooltip.dataPoints[0].dataIndex;
242
+ if (datasetIndex && dataIndex) {
243
+ const data = radarComponentChartProps.areas[datasetIndex];
244
+ return data.areaData[dataIndex].value.toFixed(2) + ' ' +
245
+ data.areaData[dataIndex].unit;
246
+ }
247
+ return '';
248
+ };
249
+ </script>
250
+
251
+ <style scoped>
252
+ .container {
253
+ -moz-osx-font-smoothing: grayscale;
254
+ -webkit-font-smoothing: antialiased;
255
+ font-weight: 400;
256
+ font-family: 'Roboto', sans-serif;
257
+ }
258
+ .main {
259
+ height: 600px;
260
+ display: flex;
261
+ flex-direction: column;
262
+ justify-content: center;
263
+ align-items: center;
264
+ }
265
+ </style>
package/src/main.ts ADDED
@@ -0,0 +1,6 @@
1
+ import BarChart from "./components/bar/BarChart.vue";
2
+ import DoughnutChart from "./components/doughnut/DoughnutChart.vue";
3
+ import LineChart from "./components/line/LineChart.vue";
4
+ import RadarChart from "./components/radar/RadarChart.vue";
5
+
6
+ export { BarChart, DoughnutChart, LineChart, RadarChart };