Skip to content

Commit 0bd7146

Browse files
committed
Improvement - Sanitize datasets to process charts with unprocessable values
1 parent 4f4df10 commit 0bd7146

25 files changed

+249
-136
lines changed

src/components/vue-ui-age-pyramid.vue

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { ref, computed, nextTick, onMounted } from "vue";
33
import {
44
applyDataLabel,
5+
checkNaN,
56
createCsvContent,
67
createUid,
78
dataLabel,
@@ -186,7 +187,7 @@ function closestDecimal(number) {
186187
187188
const max = computed(() => {
188189
return Math.max(...props.dataset.flatMap(ds => {
189-
return ds.slice(-2);
190+
return ds.slice(-2).map(v => checkNaN(v));
190191
}));
191192
});
192193
@@ -220,16 +221,16 @@ const drawableDataset = computed(() => {
220221
...ds.left,
221222
y,
222223
color: FINAL_CONFIG.value.style.layout.bars.left.color,
223-
x: drawingArea.value.leftChart.right - (ds.left.proportionToMax * drawingArea.value.leftChart.width),
224-
width: ds.left.proportionToMax * drawingArea.value.leftChart.width,
224+
x: (drawingArea.value.leftChart.right - (ds.left.proportionToMax * drawingArea.value.leftChart.width)),
225+
width: checkNaN(ds.left.proportionToMax * drawingArea.value.leftChart.width),
225226
height
226227
},
227228
right: {
228229
...ds.right,
229230
y,
230231
color: FINAL_CONFIG.value.style.layout.bars.right.color,
231232
x: drawingArea.value.rightChart.left,
232-
width: ds.right.proportionToMax * drawingArea.value.rightChart.width,
233+
width: checkNaN(ds.right.proportionToMax * drawingArea.value.rightChart.width),
233234
height
234235
}
235236
}
@@ -279,29 +280,29 @@ function useTooltip(index, datapoint) {
279280
html += `<div><b>${selectedSet.segment}</b></div>`;
280281
html += `<div>${FINAL_CONFIG.value.translations.age}: ${applyDataLabel(
281282
FINAL_CONFIG.value.style.layout.dataLabels.yAxis.formatter,
282-
selectedSet.age,
283-
dataLabel({ v: selectedSet.age }),
283+
checkNaN(selectedSet.age),
284+
dataLabel({ v: checkNaN(selectedSet.age) }),
284285
{ datapoint, seriesIndex: index}
285286
)}</div>`
286287
html += `<div style="margin-top:6px;padding-top:6px;border-top:1px solid ${FINAL_CONFIG.value.style.tooltip.borderColor}">`;
287288
html += `<div style="display:flex; flex-direction:row;gap:12px">`;
288289
html += `<div style="display:flex;flex-direction:column;align-items:center;justify-content:center"><svg viewBox="0 0 12 12" height="12" width="12"><rect stroke="none" x="0" y="0" height="12" width="12" rx="2" fill="${FINAL_CONFIG.value.style.layout.bars.gradient.underlayer}"/><rect stroke="none" x="0" y="0" height="12" width="12" rx="2" fill="${FINAL_CONFIG.value.style.layout.bars.gradient.show ? `url(#age_pyramid_left_${uid.value})` : FINAL_CONFIG.value.style.layout.bars.left.color}"/></svg><div>${FINAL_CONFIG.value.translations.female}</div><div><b>${applyDataLabel(
289290
FINAL_CONFIG.value.style.layout.dataLabels.xAxis.formatter,
290-
selectedSet.left.value,
291-
dataLabel({ v: selectedSet.left.value }),
291+
checkNaN(selectedSet.left.value),
292+
dataLabel({ v: checkNaN(selectedSet.left.value) }),
292293
{ datapoint, seriesIndex: index }
293294
)}</b></div></div>`;
294295
html += `<div style="display:flex;flex-direction:column;align-items:center;justify-content:center"><svg viewBox="0 0 12 12" height="12" width="12"><rect stroke="none" x="0" y="0" height="12" width="12" rx="2" fill="${FINAL_CONFIG.value.style.layout.bars.gradient.underlayer}"/><rect stroke="none" x="0" y="0" height="12" width="12" rx="2" fill="${FINAL_CONFIG.value.style.layout.bars.gradient.show ? `url(#age_pyramid_right_${uid.value})` : FINAL_CONFIG.value.style.layout.bars.right.color}"/></svg><div>${FINAL_CONFIG.value.translations.male}</div><div><b>${applyDataLabel(
295296
FINAL_CONFIG.value.style.layout.dataLabels.xAxis.formatter,
296-
selectedSet.right.value,
297-
dataLabel({ v: selectedSet.right.value }),
297+
checkNaN(selectedSet.right.value),
298+
dataLabel({ v: checkNaN(selectedSet.right.value) }),
298299
{ datapoint, seriesIndex: index }
299300
)}</b></div></div>`;
300301
html += `</div>`;
301302
html += `<div style="margin-top:6px;padding-top:6px;border-top:1px solid ${FINAL_CONFIG.value.style.tooltip.borderColor}"><div>${FINAL_CONFIG.value.translations.total}</div><div><b>${applyDataLabel(
302303
FINAL_CONFIG.value.style.layout.dataLabels.xAxis.formatter,
303-
selectedSet.right.value + selectedSet.left.value,
304-
dataLabel({ v: selectedSet.right.value + selectedSet.left.value }),
304+
checkNaN(selectedSet.right.value) + checkNaN(selectedSet.left.value),
305+
dataLabel({ v: checkNaN(selectedSet.right.value) + checkNaN(selectedSet.left.value) }),
305306
{ datapoint, seriesIndex: index }
306307
)}</b></div></div>`
307308
html += `</div>`;
@@ -490,7 +491,7 @@ defineExpose({
490491
<rect
491492
:x="segment.left.x"
492493
:y="segment.left.y"
493-
:width="segment.left.width <= 0 ? 0.0001 : segment.left.width"
494+
:width="checkNaN(segment.left.width <= 0 ? 0.0001 : segment.left.width)"
494495
:height="segment.left.height <= 0 ? 0.0001 : segment.left.height"
495496
:fill="FINAL_CONFIG.style.layout.bars.gradient.underlayer"
496497
:rx="FINAL_CONFIG.style.layout.bars.borderRadius"

src/components/vue-ui-candlestick.vue

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { ref, computed, onMounted, nextTick, onBeforeUnmount } from "vue";
33
import {
44
calculateNiceScale,
55
canShowValue,
6+
checkNaN,
67
createCsvContent,
78
createUid,
89
downloadCsv,
@@ -247,9 +248,9 @@ const niceScale = computed(() => {
247248
function convertToPlot(item, index) {
248249
return {
249250
...item,
250-
x: drawingArea.value.left + (index * slot.value) + (slot.value / 2),
251-
y: drawingArea.value.top + (1 - (item / niceScale.value.max)) * drawingArea.value.height,
252-
value: item
251+
x: checkNaN(drawingArea.value.left + (index * slot.value) + (slot.value / 2)),
252+
y: checkNaN(drawingArea.value.top + (1 - (item / niceScale.value.max)) * drawingArea.value.height),
253+
value: checkNaN(item)
253254
}
254255
}
255256
@@ -273,14 +274,14 @@ const drawableDataset = computed(() => {
273274
});
274275
275276
function ratioToMax(value) {
276-
return value / niceScale.value.max;
277+
return checkNaN(value / niceScale.value.max);
277278
}
278279
279280
const yLabels = computed(() => {
280281
return niceScale.value.ticks.map(t => {
281282
return {
282283
y: drawingArea.value.bottom - (drawingArea.value.height * ratioToMax(t)),
283-
value: t
284+
value: checkNaN(t)
284285
}
285286
})
286287
});

src/components/vue-ui-chestnut.vue

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ const treeTotal = computed(() => {
124124
if(!isDataset.value) {
125125
return 0
126126
}
127-
return props.dataset.flatMap(root => root.branches.map(branch => branch.value)).reduce((a,b) => a + b);
127+
return props.dataset.flatMap(root => (root.branches || []).map(branch => (branch.value || 0))).reduce((a,b) => a + b, 0);
128128
})
129129
130130
const mutableDataset = computed(() => {
@@ -176,15 +176,15 @@ const mutableDataset = computed(() => {
176176
});
177177
178178
return props.dataset.map((root, i) => {
179-
const rootTotal = root.branches.map(branch => branch.value).reduce((a, b) => a + b);
179+
const rootTotal = (root.branches || []).map(branch => (branch.value || 0)).reduce((a, b) => a + b, 0);
180180
return {
181181
...root,
182182
color: convertColorToHex(root.color) || customPalette.value[i] || palette[i] || palette[i % palette.length],
183183
id: root.id || `root_${i}_${uid.value}`,
184184
type: "root",
185185
total: rootTotal,
186186
rootIndex: i,
187-
branches: root.branches.map((branch, j) => {
187+
branches: (root.branches || []).map((branch, j) => {
188188
return {
189189
...branch,
190190
rootName: root.name,
@@ -194,7 +194,7 @@ const mutableDataset = computed(() => {
194194
id: branch.id || `branch_${i}_${j}_${uid.value}`,
195195
proportionToRoot: branch.value / rootTotal,
196196
type: "branch",
197-
breakdown: branch.breakdown.map((nut, k) => {
197+
breakdown: (branch.breakdown || []).map((nut, k) => {
198198
return {
199199
table: {
200200
rootName: root.name,
@@ -394,7 +394,9 @@ function observeTable() {
394394
isResponsive.value = entry.contentRect.width < breakpoint.value;
395395
})
396396
})
397-
observer.observe(tableContainer.value)
397+
if (tableContainer.value) {
398+
observer.observe(tableContainer.value)
399+
}
398400
}
399401
400402
onMounted(() => {

src/components/vue-ui-donut-evolution.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ import {
1818
makeDonut,
1919
objectIsEmpty,
2020
opacity,
21-
palette,
21+
palette,
22+
sanitizeArray,
2223
sumByAttribute,
2324
themePalettes,
2425
XMLNS
@@ -184,7 +185,7 @@ const convertedDataset = computed(() => {
184185
return props.dataset.map((ds, i) => {
185186
return {
186187
...ds,
187-
values: ds.values || [],
188+
values: sanitizeArray(ds.values),
188189
color: convertColorToHex(ds.color) || customPalette.value[i] || palette[i] || palette[i % palette.length],
189190
length: (ds.values || []).length,
190191
uid: createUid(),

src/components/vue-ui-dumbbell.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
getMissingDatasetAttributes,
1313
lightenHexColor,
1414
objectIsEmpty,
15+
sanitizeArray,
1516
XMLNS,
1617
} from "../lib";
1718
import { throttle } from "../canvas-lib";
@@ -134,7 +135,7 @@ const mutableConfig = ref({
134135
});
135136
136137
const immutableDataset = computed(() => {
137-
return props.dataset.map((ds, i) => {
138+
return sanitizeArray(props.dataset, ['start', 'end']).map((ds, i) => {
138139
return {
139140
...ds,
140141
id: createUid()

src/components/vue-ui-flow.vue

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import {
55
abbreviate,
66
adaptColorToBackground,
77
applyDataLabel,
8-
convertCustomPalette,
8+
checkNaN,
9+
convertCustomPalette,
910
createCsvContent,
1011
createUid,
1112
dataLabel,
@@ -108,6 +109,17 @@ const unitWidth = computed(() => {
108109
return FINAL_CONFIG.value.style.chart.links.width;
109110
});
110111
112+
const sanitizedDataset = computed(() => {
113+
if(!props.dataset || !props.dataset.length) return [];
114+
return props.dataset.map(dp => {
115+
return [
116+
dp[0],
117+
dp[1],
118+
checkNaN(dp[2])
119+
]
120+
})
121+
})
122+
111123
const max = computed(() => {
112124
const nodes = {};
113125
@@ -117,7 +129,7 @@ const max = computed(() => {
117129
}
118130
}
119131
120-
props.dataset.forEach(([source, target, value]) => {
132+
sanitizedDataset.value.forEach(([source, target, value]) => {
121133
addNode(source);
122134
addNode(target);
123135
@@ -214,16 +226,16 @@ function computeSankeyCoordinates(ds) {
214226
const sourceCoord = nodeCoordinates[node];
215227
const targetCoord = nodeCoordinates[target];
216228
217-
const sourceLinkY1 = sourceY;
218-
const sourceLinkY2 = sourceY + (value / nodes[node].outflow) * sourceCoord.height;
219-
const targetLinkY1 = targetY;
220-
const targetLinkY2 = targetY + (value / nodes[target].inflow) * targetCoord.height;
229+
const sourceLinkY1 = checkNaN(sourceY);
230+
const sourceLinkY2 = checkNaN(sourceY + (value / nodes[node].outflow) * sourceCoord.height);
231+
const targetLinkY1 = checkNaN(targetY);
232+
const targetLinkY2 = checkNaN(targetY + (value / nodes[target].inflow) * targetCoord.height);
221233
222234
const link = {
223235
id: createUid(),
224236
source: node,
225237
target: target,
226-
path: `M ${sourceCoord.x + nodeWidth.value} ${sourceLinkY1} L ${sourceCoord.x + nodeWidth.value} ${sourceLinkY2} L ${targetCoord.x} ${targetLinkY2} L ${targetCoord.x} ${targetLinkY1} Z`,
238+
path: `M ${checkNaN(sourceCoord.x) + checkNaN(nodeWidth.value)} ${sourceLinkY1} L ${checkNaN(sourceCoord.x) + checkNaN(nodeWidth.value)} ${sourceLinkY2} L ${checkNaN(targetCoord.x)} ${targetLinkY2} L ${checkNaN(targetCoord.x)} ${targetLinkY1} Z`,
227239
value: value,
228240
sourceColor: nodes[node].color,
229241
targetColor: nodes[target].color
@@ -274,7 +286,7 @@ function computeTotalHeight(nodeCoordinates) {
274286
275287
const drawingArea = computed(() => {
276288
const { top: p_top, right: p_right, left: p_left, bottom: p_bottom } = FINAL_CONFIG.value.style.chart.padding;
277-
const width = props.dataset.length * unitWidth.value;
289+
const width = sanitizedDataset.value.length * unitWidth.value;
278290
return {
279291
height: totalHeight.value + p_top + p_bottom,
280292
width: p_right + Math.max(...mutableDataset.value.nodes.map(n => n.x)) + nodeWidth.value,
@@ -291,7 +303,7 @@ function findConnectedNodes(startNode) {
291303
const reverseNodes = {};
292304
const result = new Set();
293305
294-
props.dataset.forEach(([source, target, value]) => {
306+
sanitizedDataset.value.forEach(([source, target, value]) => {
295307
if (!nodes[source]) {
296308
nodes[source] = [];
297309
}
@@ -534,8 +546,8 @@ defineExpose({
534546
v-for="(node, i) in mutableDataset.nodes"
535547
class="vue-ui-flow-node"
536548
:x="node.x"
537-
:y="node.absoluteY"
538-
:height="node.height"
549+
:y="checkNaN(node.absoluteY)"
550+
:height="checkNaN(node.height)"
539551
:width="nodeWidth"
540552
:fill="node.color"
541553
:stroke="FINAL_CONFIG.style.chart.nodes.stroke"
@@ -548,7 +560,7 @@ defineExpose({
548560
<text
549561
v-for="(node, i) in mutableDataset.nodes"
550562
:x="node.x + nodeWidth / 2"
551-
:y="node.absoluteY + node.height / 2 - (FINAL_CONFIG.style.chart.nodes.labels.fontSize / 4)"
563+
:y="checkNaN(node.absoluteY + node.height / 2 - (FINAL_CONFIG.style.chart.nodes.labels.fontSize / 4))"
552564
:font-size="FINAL_CONFIG.style.chart.nodes.labels.fontSize"
553565
:fill="adaptColorToBackground(node.color)"
554566
text-anchor="middle"
@@ -559,7 +571,7 @@ defineExpose({
559571
<text
560572
v-for="(node, i) in mutableDataset.nodes"
561573
:x="node.x + nodeWidth / 2"
562-
:y="node.absoluteY + node.height / 2 + (FINAL_CONFIG.style.chart.nodes.labels.fontSize)"
574+
:y="checkNaN(node.absoluteY + node.height / 2 + (FINAL_CONFIG.style.chart.nodes.labels.fontSize))"
563575
:font-size="FINAL_CONFIG.style.chart.nodes.labels.fontSize"
564576
:fill="adaptColorToBackground(node.color)"
565577
text-anchor="middle"

src/components/vue-ui-galaxy.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
isFunction,
1616
objectIsEmpty,
1717
palette,
18+
sanitizeArray,
1819
themePalettes,
1920
XMLNS
2021
} from "../lib";
@@ -147,8 +148,8 @@ const immutableSet = computed(() => {
147148
return {
148149
name: serie.name,
149150
color: convertColorToHex(serie.color) || customPalette.value[i] || palette[i] || palette[i % palette.length],
150-
value: serie.values ? serie.values.reduce((a,b) => a + b, 0) : 0,
151-
absoluteValues: serie.values || [0],
151+
value: serie.values ? sanitizeArray(serie.values).reduce((a,b) => a + b, 0) : 0,
152+
absoluteValues: sanitizeArray(serie.values),
152153
id: createUid(),
153154
seriesIndex: i
154155
}

src/components/vue-ui-gauge.vue

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
makeDonut,
1616
translateSize,
1717
offsetFromCenterPoint,
18-
XMLNS
18+
XMLNS,
1919
} from "../lib.js";
2020
import { throttle } from "../canvas-lib";
2121
import themes from "../themes.json";
@@ -45,7 +45,7 @@ const props = defineProps({
4545
});
4646
4747
const isDataset = computed(() => {
48-
return !!props.dataset && Object.keys(props.dataset).length;
48+
return !!props.dataset && Object.keys(props.dataset).length > 0 && props.dataset.series && props.dataset.series.length;
4949
});
5050
5151
const uid = ref(createUid());
@@ -90,13 +90,14 @@ const mutableDataset = computed(() => {
9090
series: [
9191
{
9292
from: 0,
93-
to: 1
93+
to: 0
9494
}
9595
]
9696
}
9797
}
9898
9999
const arr = [];
100+
100101
(props.dataset.series || []).forEach(serie => {
101102
arr.push(serie.from || 0);
102103
arr.push(serie.to || 0);
@@ -320,7 +321,7 @@ const arcs = computed(() => {
320321
109.9495,
321322
40 * svg.value.trackSize
322323
);
323-
return donut
324+
return donut;
324325
})
325326
326327
const gradientArcs = computed(() => {

0 commit comments

Comments
 (0)