@mozaic-ds/chart 0.1.0-beta.3 → 0.1.0-beta.5
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 +1674 -1492
- package/dist/mozaic-chart.umd.cjs +5 -5
- package/dist/style.css +1 -1
- package/package.json +16 -9
- package/src/components/bar/BarChart.stories.ts +7 -10
- package/src/components/bar/BarChart.vue +197 -128
- package/src/components/doughnut/DoughnutChart.stories.ts +1 -0
- package/src/components/doughnut/DoughnutChart.vue +155 -99
- package/src/components/line/LineChart.vue +293 -257
- package/src/components/radar/RadarChart.stories.ts +2 -2
- package/src/components/radar/RadarChart.vue +204 -146
- package/src/main.ts +5 -4
- package/src/plugin.ts +1 -1
- package/src/services/DoughnutChartFunctions.ts +97 -56
- package/src/services/RadarChartFunctions.ts +13 -11
- 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/App.vue +0 -80
|
@@ -1,32 +1,37 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="container">
|
|
3
|
-
<div class=
|
|
3
|
+
<div class="main">
|
|
4
4
|
<Radar
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
:style='{ height, cursor:"pointer",}'
|
|
5
|
+
v-if="radarData"
|
|
6
|
+
:id="chartId"
|
|
7
|
+
:data="radarData"
|
|
8
|
+
:options="chartOptions"
|
|
9
|
+
:plugins="radarPlugins"
|
|
10
|
+
:class="cssClasses"
|
|
11
|
+
:style="[{ height, cursor: 'pointer' }, styles]"
|
|
13
12
|
/>
|
|
14
13
|
</div>
|
|
15
|
-
<div ref=
|
|
14
|
+
<div ref="legendContainer" class="legendContainer" />
|
|
16
15
|
</div>
|
|
17
16
|
</template>
|
|
18
17
|
|
|
19
|
-
<script setup lang=
|
|
18
|
+
<script setup lang="ts">
|
|
20
19
|
import { PropType, ref, computed } from 'vue';
|
|
21
20
|
import type { Area } from '../../types/RadarData';
|
|
22
21
|
import { Radar } from 'vue-chartjs';
|
|
23
22
|
import type { ActiveElement, ChartData } from 'chart.js';
|
|
24
|
-
import {
|
|
25
|
-
|
|
23
|
+
import {
|
|
24
|
+
Context,
|
|
25
|
+
GenericTooltipService,
|
|
26
|
+
} from '../../services/GenericTooltipService';
|
|
27
|
+
import {
|
|
28
|
+
formatWithThousandsSeprators,
|
|
29
|
+
numberWithThousandSeparators,
|
|
30
|
+
} from '../../services/FormatUtilities';
|
|
26
31
|
import { TooltipChartType } from '../../types/TooltipChartType';
|
|
27
32
|
import { drawLabels } from '../../services/RadarChartFunctions';
|
|
28
33
|
import type { Chart, ChartItem } from '../../services/ChartsCommonLegend';
|
|
29
|
-
import { addAlpha } from '../../services/ColorFunctions'
|
|
34
|
+
import { addAlpha } from '../../services/ColorFunctions';
|
|
30
35
|
import {
|
|
31
36
|
Chart as ChartJS,
|
|
32
37
|
Filler,
|
|
@@ -36,7 +41,7 @@ import {
|
|
|
36
41
|
RadialLinearScale,
|
|
37
42
|
Title,
|
|
38
43
|
Tooltip,
|
|
39
|
-
Plugin
|
|
44
|
+
Plugin,
|
|
40
45
|
} from 'chart.js';
|
|
41
46
|
|
|
42
47
|
import {
|
|
@@ -46,7 +51,7 @@ import {
|
|
|
46
51
|
createLegendElementWithSquareArea,
|
|
47
52
|
getOrCreateLegendList,
|
|
48
53
|
hideAllButThis,
|
|
49
|
-
switchItemVisibility
|
|
54
|
+
switchItemVisibility,
|
|
50
55
|
} from '../../services/ChartsCommonLegend';
|
|
51
56
|
|
|
52
57
|
import ChartDesign from '../../services/patterns/ChartDesign';
|
|
@@ -58,75 +63,105 @@ ChartJS.register(
|
|
|
58
63
|
RadialLinearScale,
|
|
59
64
|
LineElement,
|
|
60
65
|
PointElement,
|
|
61
|
-
Filler
|
|
66
|
+
Filler
|
|
62
67
|
);
|
|
63
68
|
|
|
64
|
-
const {
|
|
65
|
-
colourSets,
|
|
66
|
-
patternsStandardList
|
|
67
|
-
} = ChartDesign();
|
|
69
|
+
const { colourSets, patternsStandardList } = ChartDesign();
|
|
68
70
|
|
|
69
71
|
const radarComponentChartProps = defineProps({
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Value of the id attribute present on the <canvas> tag element the chart
|
|
74
|
+
*/
|
|
75
|
+
chartId: {
|
|
76
|
+
type: String,
|
|
77
|
+
default: 'radar-chart',
|
|
78
|
+
},
|
|
79
|
+
/**
|
|
80
|
+
* Value of the `height` css property used to define the height of the <canvas> element
|
|
81
|
+
*/
|
|
82
|
+
height: {
|
|
83
|
+
type: String,
|
|
84
|
+
default: '400px',
|
|
85
|
+
},
|
|
86
|
+
/**
|
|
87
|
+
* Labels used to label the index axis (default x axes). See [Data structures documentation](https://www.chartjs.org/docs/latest/general/data-structures.html)
|
|
88
|
+
*/
|
|
89
|
+
labels: {
|
|
79
90
|
type: Array as PropType<string[]>,
|
|
80
|
-
default: () => []
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
91
|
+
default: () => [],
|
|
92
|
+
},
|
|
93
|
+
/**
|
|
94
|
+
* Disable accessibility patterns
|
|
95
|
+
*/
|
|
96
|
+
disableAccessibility: {
|
|
97
|
+
type: Boolean,
|
|
98
|
+
default: false,
|
|
99
|
+
},
|
|
100
|
+
/**
|
|
101
|
+
* Used to choose the colour set of the charts as defined in the Figma prototypes.
|
|
102
|
+
* 7 colour sets are currently defined:
|
|
103
|
+
* - Default 0 corresponds to the current one
|
|
104
|
+
* - 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)
|
|
105
|
+
* Note: All the sets are defined in /src/services/patterns/ChartDesign.ts
|
|
106
|
+
*/
|
|
107
|
+
colourSet: {
|
|
108
|
+
type: Number,
|
|
109
|
+
default: 0,
|
|
110
|
+
},
|
|
111
|
+
/**
|
|
112
|
+
* 6 patterns exist and are not randomly given but follow the order defined in [patternsStandardList](/src/services/patterns/ChartDesign.ts)
|
|
113
|
+
* Additionally, a pattern has only one possible colour per colour set as defined in the Figma prototype.
|
|
114
|
+
* In some use cases, the chart may need to show a different orders of these patterns, this can be changed using the props newPatternsOrder
|
|
115
|
+
*/
|
|
116
|
+
newPatternsOrder: {
|
|
117
|
+
type: Array as PropType<number[]>,
|
|
118
|
+
default: () => [0, 1, 2, 3, 4, 5],
|
|
119
|
+
},
|
|
120
|
+
/**
|
|
121
|
+
* Value of the `datasets` key present in the `data` object passed to the Chart config
|
|
122
|
+
*/
|
|
123
|
+
datasets: {
|
|
124
|
+
type: Array as PropType<Area[]>,
|
|
125
|
+
default: () => [],
|
|
126
|
+
},
|
|
127
|
+
/**
|
|
128
|
+
* Add custom CSS classes to the <canvas> element
|
|
129
|
+
*/
|
|
130
|
+
cssClasses: {
|
|
131
|
+
default: '',
|
|
132
|
+
type: String,
|
|
133
|
+
},
|
|
134
|
+
/**
|
|
135
|
+
* Add custom CSS styles to the <canvas> element
|
|
136
|
+
*/
|
|
137
|
+
styles: {
|
|
138
|
+
type: Object as PropType<Partial<CSSStyleDeclaration>>,
|
|
139
|
+
default: () => {},
|
|
140
|
+
},
|
|
141
|
+
/**
|
|
142
|
+
* Value of the `plugins` key passed to the Chart config
|
|
143
|
+
*/
|
|
144
|
+
plugins: {
|
|
145
|
+
type: Array as PropType<Plugin<'radar'>[]>,
|
|
146
|
+
default: () => [],
|
|
147
|
+
},
|
|
148
|
+
});
|
|
120
149
|
|
|
121
|
-
const patternsColors = computed(() =>
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
)
|
|
150
|
+
const patternsColors = computed(() =>
|
|
151
|
+
radarComponentChartProps.newPatternsOrder.length !== 6
|
|
152
|
+
? colourSets[radarComponentChartProps.colourSet]
|
|
153
|
+
: radarComponentChartProps.newPatternsOrder.map((id) => {
|
|
154
|
+
return colourSets[radarComponentChartProps.colourSet][id];
|
|
155
|
+
})
|
|
156
|
+
);
|
|
125
157
|
|
|
126
|
-
const patternsOrderedList = computed(() =>
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
)
|
|
158
|
+
const patternsOrderedList = computed(() =>
|
|
159
|
+
radarComponentChartProps.newPatternsOrder.length !== 6
|
|
160
|
+
? patternsStandardList
|
|
161
|
+
: radarComponentChartProps.newPatternsOrder.map((id) => {
|
|
162
|
+
return patternsStandardList[id];
|
|
163
|
+
})
|
|
164
|
+
);
|
|
130
165
|
|
|
131
166
|
const radarData = computed<ChartData<'radar'>>(() => ({
|
|
132
167
|
labels: getRadarLabels(),
|
|
@@ -135,7 +170,7 @@ const radarData = computed<ChartData<'radar'>>(() => ({
|
|
|
135
170
|
label: 'Data One',
|
|
136
171
|
backgroundColor: addAlpha(patternsColors.value[0], 0.1),
|
|
137
172
|
borderColor: patternsColors.value[0],
|
|
138
|
-
pointBackgroundColor:
|
|
173
|
+
pointBackgroundColor: '#FFFFFF',
|
|
139
174
|
pointBorderColor: patternsColors.value[0],
|
|
140
175
|
pointBorderWidth: 2,
|
|
141
176
|
borderWidth: 2,
|
|
@@ -143,7 +178,9 @@ const radarData = computed<ChartData<'radar'>>(() => ({
|
|
|
143
178
|
pointRadius: 5,
|
|
144
179
|
pointHoverBackgroundColor: patternsColors.value[0],
|
|
145
180
|
pointHoverBorderColor: patternsColors.value[0],
|
|
146
|
-
data: radarComponentChartProps.
|
|
181
|
+
data: radarComponentChartProps.datasets[0].areaData.map(
|
|
182
|
+
(x: { position: number }) => x.position
|
|
183
|
+
),
|
|
147
184
|
},
|
|
148
185
|
{
|
|
149
186
|
label: 'Data Two',
|
|
@@ -158,26 +195,32 @@ const radarData = computed<ChartData<'radar'>>(() => ({
|
|
|
158
195
|
pointStyle: 'rectRot',
|
|
159
196
|
pointHoverBackgroundColor: patternsColors.value[1],
|
|
160
197
|
pointHoverBorderColor: patternsColors.value[1],
|
|
161
|
-
data: radarComponentChartProps.
|
|
162
|
-
|
|
163
|
-
|
|
198
|
+
data: radarComponentChartProps.datasets[1].areaData.map(
|
|
199
|
+
(x: { position: number }) => x.position
|
|
200
|
+
),
|
|
201
|
+
},
|
|
202
|
+
],
|
|
164
203
|
}));
|
|
165
204
|
|
|
166
205
|
const chartOptions: any = {
|
|
167
|
-
|
|
206
|
+
onClick: (
|
|
207
|
+
_ingnore: unknown,
|
|
208
|
+
clickedElements: ActiveElement[],
|
|
209
|
+
chart: Chart
|
|
210
|
+
) => {
|
|
168
211
|
if (clickedElements[0]) {
|
|
169
212
|
hideAllButThis(chart, clickedElements[0].datasetIndex, selectMode);
|
|
170
213
|
}
|
|
171
214
|
},
|
|
172
215
|
plugins: {
|
|
173
216
|
htmlLegend: {
|
|
174
|
-
containerID: 'legend-container'
|
|
217
|
+
containerID: 'legend-container',
|
|
175
218
|
},
|
|
176
219
|
legend: {
|
|
177
|
-
display: false
|
|
220
|
+
display: false,
|
|
178
221
|
},
|
|
179
222
|
title: {
|
|
180
|
-
display: false
|
|
223
|
+
display: false,
|
|
181
224
|
},
|
|
182
225
|
tooltip: {
|
|
183
226
|
enabled: false,
|
|
@@ -191,58 +234,64 @@ const chartOptions: any = {
|
|
|
191
234
|
patternsOrderedList.value,
|
|
192
235
|
radarComponentChartProps.disableAccessibility
|
|
193
236
|
);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
237
|
+
},
|
|
238
|
+
},
|
|
196
239
|
},
|
|
197
240
|
layout: {
|
|
198
|
-
padding: 65
|
|
241
|
+
padding: 65,
|
|
199
242
|
},
|
|
200
243
|
scales: {
|
|
201
244
|
r: {
|
|
202
245
|
min: 0,
|
|
203
246
|
max: 100,
|
|
204
247
|
pointLabels: {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
248
|
+
display: false,
|
|
249
|
+
font: {
|
|
250
|
+
size: 16,
|
|
251
|
+
},
|
|
209
252
|
},
|
|
210
253
|
ticks: {
|
|
211
254
|
display: false,
|
|
212
|
-
stepSize: 25
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
255
|
+
stepSize: 25,
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
};
|
|
217
260
|
const legendContainer = ref(null);
|
|
218
261
|
const selectMode = ref(false);
|
|
219
|
-
function splitLabelIfTooLong
|
|
262
|
+
function splitLabelIfTooLong(axisLabel: string, buildValue: string) {
|
|
220
263
|
const radarLimitLabelLength = 15;
|
|
221
|
-
if (
|
|
222
|
-
|
|
264
|
+
if (
|
|
265
|
+
axisLabel.length > radarLimitLabelLength &&
|
|
266
|
+
axisLabel.includes(' ', radarLimitLabelLength)
|
|
267
|
+
) {
|
|
268
|
+
const indexOfFirstSpaceAfterLimit: number = axisLabel.indexOf(
|
|
269
|
+
' ',
|
|
270
|
+
radarLimitLabelLength
|
|
271
|
+
);
|
|
223
272
|
return [
|
|
224
273
|
axisLabel.substring(0, indexOfFirstSpaceAfterLimit),
|
|
225
274
|
axisLabel.substring(indexOfFirstSpaceAfterLimit),
|
|
226
|
-
buildValue
|
|
275
|
+
buildValue,
|
|
227
276
|
];
|
|
228
277
|
}
|
|
229
|
-
return [
|
|
230
|
-
axisLabel,
|
|
231
|
-
buildValue
|
|
232
|
-
];
|
|
278
|
+
return [axisLabel, buildValue];
|
|
233
279
|
}
|
|
234
280
|
const getRadarLabels = () => {
|
|
235
281
|
return radarComponentChartProps.labels.map((label: string, index: number) => {
|
|
236
|
-
const buildValue = radarComponentChartProps.
|
|
237
|
-
|
|
282
|
+
const buildValue = radarComponentChartProps.datasets[0].areaData[index]
|
|
283
|
+
.value
|
|
284
|
+
? `${formatNumber(
|
|
285
|
+
radarComponentChartProps.datasets[0].areaData[index].value + ''
|
|
286
|
+
)} ${radarComponentChartProps.datasets[0].areaData[index].unit}`
|
|
238
287
|
: 'No Data';
|
|
239
288
|
return splitLabelIfTooLong(label, buildValue);
|
|
240
289
|
});
|
|
241
|
-
}
|
|
290
|
+
};
|
|
242
291
|
const formatNumber = (numberFromJson: string) => {
|
|
243
292
|
return formatWithThousandsSeprators(parseFloat(numberFromJson));
|
|
244
293
|
};
|
|
245
|
-
function createLegendElementWithCheckbox
|
|
294
|
+
function createLegendElementWithCheckbox(chart: any, item: ChartItem) {
|
|
246
295
|
const liContent = createLegendCheckbox(chart, item);
|
|
247
296
|
liContent.onclick = (e: Event) => {
|
|
248
297
|
switchItemVisibility(chart, item.datasetIndex, selectMode);
|
|
@@ -251,44 +300,53 @@ function createLegendElementWithCheckbox (chart: any, item: ChartItem) {
|
|
|
251
300
|
return liContent;
|
|
252
301
|
}
|
|
253
302
|
|
|
254
|
-
const radarPlugins = [
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
ul.firstChild
|
|
260
|
-
|
|
261
|
-
const items = chart.options.plugins.legend.labels.generateLabels(chart).reverse();
|
|
262
|
-
items.forEach((item: ChartItem) => {
|
|
263
|
-
const li = createHtmlLegendListElement(chart, selectMode, item.datasetIndex);
|
|
264
|
-
let liContent;
|
|
265
|
-
li.style.marginRight = '0.625rem';
|
|
266
|
-
if (!selectMode.value) {
|
|
267
|
-
liContent = createLegendElementWithSquareArea(item, true);
|
|
268
|
-
} else {
|
|
269
|
-
liContent = createLegendElementWithCheckbox(chart, item);
|
|
303
|
+
const radarPlugins = [
|
|
304
|
+
{
|
|
305
|
+
id: 'htmlLegend',
|
|
306
|
+
afterUpdate(chart: any) {
|
|
307
|
+
const ul = getOrCreateLegendList(legendContainer, 'row');
|
|
308
|
+
while (ul.firstChild) {
|
|
309
|
+
ul.firstChild.remove();
|
|
270
310
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
311
|
+
const items = chart.options.plugins.legend.labels
|
|
312
|
+
.generateLabels(chart)
|
|
313
|
+
.reverse();
|
|
314
|
+
items.forEach((item: ChartItem) => {
|
|
315
|
+
const li = createHtmlLegendListElement(
|
|
316
|
+
chart,
|
|
317
|
+
selectMode,
|
|
318
|
+
item.datasetIndex
|
|
319
|
+
);
|
|
320
|
+
let liContent;
|
|
321
|
+
li.style.marginRight = '0.625rem';
|
|
322
|
+
if (!selectMode.value) {
|
|
323
|
+
liContent = createLegendElementWithSquareArea(item, true);
|
|
324
|
+
} else {
|
|
325
|
+
liContent = createLegendElementWithCheckbox(chart, item);
|
|
326
|
+
}
|
|
327
|
+
li.appendChild(liContent);
|
|
328
|
+
li.appendChild(createHtmlLegendItemText(item));
|
|
329
|
+
ul.appendChild(li);
|
|
330
|
+
});
|
|
331
|
+
},
|
|
280
332
|
},
|
|
281
|
-
|
|
333
|
+
{
|
|
334
|
+
id: 'radarLabelPlugin',
|
|
335
|
+
beforeDraw(chart: any) {
|
|
336
|
+
drawLabels(chart, radarComponentChartProps);
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
];
|
|
282
340
|
|
|
283
341
|
const getTooltipData = (context: Context): string => {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
342
|
+
const datasetIndex = context.tooltip.dataPoints[0].datasetIndex as number;
|
|
343
|
+
const dataIndex = context.tooltip.dataPoints[0].dataIndex as number;
|
|
344
|
+
const data = radarComponentChartProps.datasets[datasetIndex];
|
|
345
|
+
return (
|
|
346
|
+
data.areaData[dataIndex].value.toFixed(2) +
|
|
347
|
+
' ' +
|
|
348
|
+
data.areaData[dataIndex].unit
|
|
349
|
+
);
|
|
292
350
|
};
|
|
293
351
|
</script>
|
|
294
352
|
|
|
@@ -306,4 +364,4 @@ const getTooltipData = (context: Context): string => {
|
|
|
306
364
|
justify-content: center;
|
|
307
365
|
align-items: center;
|
|
308
366
|
}
|
|
309
|
-
</style>
|
|
367
|
+
</style>
|
package/src/main.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
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";
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
export { BarChart, DoughnutChart, LineChart, RadarChart };
|
package/src/plugin.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { App } from "vue";
|
|
|
2
2
|
import * as Components from "./components";
|
|
3
3
|
|
|
4
4
|
const MozaicChart = {
|
|
5
|
-
install: (app: App) => {
|
|
5
|
+
install: (app: App, options: {}) => {
|
|
6
6
|
Object.keys(Components).forEach((name) => {
|
|
7
7
|
// @ts-ignore
|
|
8
8
|
app.component(name, Components[name]);
|