Skip to content

Commit c905818

Browse files
committed
Improvement - VueUiQuickChart - Added zoom component for line & bar types
1 parent e86f311 commit c905818

File tree

4 files changed

+77
-18
lines changed

4 files changed

+77
-18
lines changed

src/chartDetector.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const timeType = ['TIME', 'PERIOD', 'MONTH', 'YEAR', 'MONTHS', 'YEARS', '
1212
export function detectChart({dataset, barLineSwitch = 6}) {
1313
let type = null;
1414
let usableDataset = null;
15+
let maxSeriesLength = 0;
1516

1617
const isJustANumber = typeof dataset === 'number';
1718
const isJustAString = typeof dataset === 'string';
@@ -25,6 +26,7 @@ export function detectChart({dataset, barLineSwitch = 6}) {
2526
if (isSimpleArrayOfNumbers(dataset)) {
2627
dataset.length < barLineSwitch ? type = chartType.BAR : type = chartType.LINE;
2728
usableDataset = dataset;
29+
maxSeriesLength = dataset.length;
2830
}
2931

3032
if (isSimpleArrayOfObjects(dataset)) {
@@ -54,6 +56,7 @@ export function detectChart({dataset, barLineSwitch = 6}) {
5456
} else {
5557
type = chartType.BAR
5658
}
59+
maxSeriesLength = maxLengthOfArrayTypesInArrayOfObjects(dataset);
5760
usableDataset = dataset.map(d => {
5861
return {
5962
...d,
@@ -72,7 +75,8 @@ export function detectChart({dataset, barLineSwitch = 6}) {
7275
return {
7376
dataset,
7477
type,
75-
usableDataset
78+
usableDataset,
79+
maxSeriesLength
7680
}
7781
}
7882

src/components/vue-ui-quick-chart.vue

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { useNestedProp } from "../useNestedProp";
2323
import BaseIcon from "../atoms/BaseIcon.vue";
2424
import Tooltip from "../atoms/Tooltip.vue";
2525
import UserOptions from "../atoms/UserOptions.vue";
26+
import Slicer from "../atoms/Slicer.vue";
2627
2728
const props = defineProps({
2829
config: {
@@ -50,6 +51,7 @@ const segregated = ref([]);
5051
const isPrinting = ref(false);
5152
const isImaging = ref(false);
5253
const step = ref(0);
54+
const slicerStep = ref(0);
5355
5456
const quickConfig = computed(() => {
5557
return useNestedProp({
@@ -329,6 +331,19 @@ const donut = computed(() => {
329331
}
330332
});
331333
334+
const slicer = ref({
335+
start: 0,
336+
end: formattedDataset.value.maxSeriesLength
337+
});
338+
339+
function refreshSlicer() {
340+
slicer.value = {
341+
start: 0,
342+
end: formattedDataset.value.maxSeriesLength
343+
};
344+
slicerStep.value += 1;
345+
}
346+
332347
const line = computed(() => {
333348
if(chartType.value !== detector.chartType.LINE) return null;
334349
@@ -351,7 +366,8 @@ const line = computed(() => {
351366
if(detector.isSimpleArrayOfNumbers(formattedDataset.value.dataset)) {
352367
ds = [
353368
{
354-
values: formattedDataset.value.dataset,
369+
values: formattedDataset.value.dataset.slice(slicer.value.start, slicer.value.end),
370+
absoluteIndices: formattedDataset.value.dataset.map((d, i) => i).slice(slicer.value.start, slicer.value.end),
355371
name: quickConfig.value.title,
356372
color: palette[quickConfig.value.paletteStartIndex],
357373
id: `line_0`
@@ -371,8 +387,10 @@ const line = computed(() => {
371387
return {
372388
...d,
373389
color: d.COLOR ? convertColorToHex(d.COLOR) : palette[i + (quickConfig.value.paletteStartIndex)] || palette[(i + quickConfig.value.paletteStartIndex) % palette.length],
390+
values: d.values.slice(slicer.value.start, slicer.value.end),
391+
absoluteIndices: d.values.map((d,i) => i).slice(slicer.value.start, slicer.value.end)
374392
}
375-
});
393+
})
376394
}
377395
const extremes = {
378396
max: Math.max(...ds.filter(d => !segregated.value.includes(d.id)).flatMap(d => d.values)),
@@ -421,7 +439,8 @@ const line = computed(() => {
421439
const mappedSeries = ds.map(d => {
422440
return {
423441
...d,
424-
value: d.values[index]
442+
value: d.values[index],
443+
absoluteIndex: d.absoluteIndices[index]
425444
}
426445
}).filter(d => !segregated.value.includes(d.id))
427446
dataTooltipSlot.value = { datapoint: mappedSeries, seriesIndex: index, config: quickConfig.value, dataset: ds };
@@ -442,8 +461,8 @@ const line = computed(() => {
442461
} else {
443462
let html = '';
444463
445-
if (quickConfig.value.xyPeriods[index]) {
446-
html += `<div style="border-bottom:1px solid #ccc;padding-bottom:6px;margin-bottom:3px;">${quickConfig.value.xyPeriods[index]}</div>`
464+
if (quickConfig.value.xyPeriods[mappedSeries[0].absoluteIndex]) {
465+
html += `<div style="border-bottom:1px solid #ccc;padding-bottom:6px;margin-bottom:3px;">${quickConfig.value.xyPeriods[mappedSeries[0].absoluteIndex]}</div>`
447466
}
448467
449468
mappedSeries.forEach(s => {
@@ -505,7 +524,8 @@ const bar = computed(() => {
505524
if(detector.isSimpleArrayOfNumbers(formattedDataset.value.dataset)) {
506525
ds = [
507526
{
508-
values: formattedDataset.value.dataset,
527+
values: formattedDataset.value.dataset.slice(slicer.value.start, slicer.value.end),
528+
absoluteIndices: formattedDataset.value.dataset.map((_,i) => i).slice(slicer.value.start, slicer.value.end),
509529
name: quickConfig.value.title,
510530
color: palette[quickConfig.value.paletteStartIndex],
511531
id: 'bar_0'
@@ -525,6 +545,8 @@ const bar = computed(() => {
525545
return {
526546
...d,
527547
color: d.COLOR ? convertColorToHex(d.COLOR) : palette[i + (quickConfig.value.paletteStartIndex)] || palette[(i + quickConfig.value.paletteStartIndex) % palette.length],
548+
values: d.values.slice(slicer.value.start, slicer.value.end),
549+
absoluteIndices: d.values.map((_,i) => i).slice(slicer.value.start, slicer.value.end)
528550
}
529551
});
530552
}
@@ -595,7 +617,8 @@ const bar = computed(() => {
595617
const mappedSeries = ds.map(d => {
596618
return {
597619
...d,
598-
value: d.values[index]
620+
value: d.values[index],
621+
absoluteIndex: d.absoluteIndices[index]
599622
}
600623
}).filter(d => !segregated.value.includes(d.id));
601624
@@ -617,8 +640,8 @@ const bar = computed(() => {
617640
} else {
618641
let html = '';
619642
620-
if (quickConfig.value.xyPeriods[index]) {
621-
html += `<div style="border-bottom:1px solid #ccc;padding-bottom:6px;margin-bottom:3px;">${quickConfig.value.xyPeriods[index]}</div>`
643+
if (quickConfig.value.xyPeriods[mappedSeries[0].absoluteIndex]) {
644+
html += `<div style="border-bottom:1px solid #ccc;padding-bottom:6px;margin-bottom:3px;">${quickConfig.value.xyPeriods[mappedSeries[0].absoluteIndex]}</div>`
622645
}
623646
624647
mappedSeries.forEach(s => {
@@ -931,7 +954,7 @@ defineExpose({
931954
</g>
932955
<g class="periodLabels" v-if="quickConfig.xyShowScale && quickConfig.xyPeriods.length">
933956
<line
934-
v-for="(_, i) in line.extremes.maxSeries"
957+
v-for="(_, i) in quickConfig.xyPeriods.slice(slicer.start, slicer.end)"
935958
:x1="line.drawingArea.left + (line.slotSize * (i+1)) - (line.slotSize / 2)"
936959
:x2="line.drawingArea.left + (line.slotSize * (i+1)) - (line.slotSize / 2)"
937960
:y1="line.drawingArea.bottom"
@@ -941,13 +964,13 @@ defineExpose({
941964
stroke-linecap="round"
942965
/>
943966
<text
944-
v-for="(_, i) in line.extremes.maxSeries"
967+
v-for="(period, i) in quickConfig.xyPeriods.slice(slicer.start, slicer.end)"
945968
:font-size="quickConfig.xyLabelsXFontSize"
946969
:text-anchor="quickConfig.xyPeriodLabelsRotation > 0 ? 'start' : quickConfig.xyPeriodLabelsRotation < 0 ? 'end' : 'middle'"
947970
:fill="quickConfig.color"
948971
:transform="`translate(${line.drawingArea.left + (line.slotSize * (i+1)) - (line.slotSize / 2)}, ${line.drawingArea.bottom + quickConfig.xyLabelsXFontSize + 6}), rotate(${quickConfig.xyPeriodLabelsRotation})`"
949972
>
950-
{{ quickConfig.xyPeriods[i] }}
973+
{{ period }}
951974
</text>
952975
</g>
953976
<g class="plots">
@@ -1121,7 +1144,7 @@ defineExpose({
11211144
</g>
11221145
<g class="periodLabels" v-if="quickConfig.xyShowScale && quickConfig.xyPeriods.length">
11231146
<line
1124-
v-for="(_, i) in bar.extremes.maxSeries"
1147+
v-for="(_, i) in quickConfig.xyPeriods.slice(slicer.start, slicer.end)"
11251148
:x1="bar.drawingArea.left + (bar.slotSize * (i+1)) - (bar.slotSize / 2)"
11261149
:x2="bar.drawingArea.left + (bar.slotSize * (i+1)) - (bar.slotSize / 2)"
11271150
:y1="bar.drawingArea.bottom"
@@ -1131,13 +1154,13 @@ defineExpose({
11311154
stroke-linecap="round"
11321155
/>
11331156
<text
1134-
v-for="(_, i) in bar.extremes.maxSeries"
1157+
v-for="(period, i) in quickConfig.xyPeriods.slice(slicer.start, slicer.end)"
11351158
:font-size="quickConfig.xyLabelsXFontSize"
11361159
:text-anchor="quickConfig.xyPeriodLabelsRotation > 0 ? 'start' : quickConfig.xyPeriodLabelsRotation < 0 ? 'end' : 'middle'"
11371160
:transform="`translate(${bar.drawingArea.left + (bar.slotSize * (i+1)) - (bar.slotSize / 2)}, ${bar.drawingArea.bottom + quickConfig.xyLabelsXFontSize + 6}) rotate(${quickConfig.xyPeriodLabelsRotation})`"
11381161
:fill="quickConfig.color"
11391162
>
1140-
{{ quickConfig.xyPeriods[i] }}
1163+
{{ period }}
11411164
</text>
11421165
</g>
11431166
<g class="plots">
@@ -1244,6 +1267,30 @@ defineExpose({
12441267
</g>
12451268
</template>
12461269
</svg>
1270+
1271+
<Slicer
1272+
v-if="[detector.chartType.BAR, detector.chartType.LINE].includes(chartType) && quickConfig.zoomXy && formattedDataset.maxSeriesLength > 1"
1273+
:key="`slicer_${slicerStep}`"
1274+
:background="quickConfig.backgroundColor"
1275+
:fontSize="quickConfig.zoomFontSize"
1276+
:useResetSlot="quickConfig.zoomUseResetSlot"
1277+
:labelLeft="quickConfig.xyPeriods[slicer.start] ? quickConfig.xyPeriods[slicer.start] : ''"
1278+
:labelRight="quickConfig.xyPeriods[slicer.end-1] ? quickConfig.xyPeriods[slicer.end-1] : ''"
1279+
:textColor="quickConfig.color"
1280+
:inputColor="quickConfig.zoomColor"
1281+
:max="formattedDataset.maxSeriesLength"
1282+
:min="0"
1283+
:valueStart="slicer.start"
1284+
:valueEnd="slicer.end"
1285+
v-model:start="slicer.start"
1286+
v-model:end="slicer.end"
1287+
@reset="refreshSlicer"
1288+
>
1289+
<template #reset-action="{ reset }">
1290+
<slot name="reset-action" v-bind="{ reset }"/>
1291+
</template>
1292+
</Slicer>
1293+
12471294
<div
12481295
v-if="quickConfig.showLegend"
12491296
class="vue-ui-quick-chart-legend"
@@ -1325,7 +1372,7 @@ defineExpose({
13251372
</div>
13261373
</template>
13271374
</div>
1328-
1375+
13291376
<Tooltip
13301377
:show="quickConfig.showTooltip && isTooltip"
13311378
:backgroundColor="quickConfig.backgroundColor"

src/default_configs.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3772,7 +3772,11 @@
37723772
"xyShowAxis": true,
37733773
"xyShowGrid": true,
37743774
"xyShowScale": true,
3775-
"yAxisLabel": ""
3775+
"yAxisLabel": "",
3776+
"zoomXy": true,
3777+
"zoomColor": "#CCCCCC",
3778+
"zoomFontSize": 14,
3779+
"zoomUseResetSlot": false
37763780
},
37773781
"vue_ui_cursor": {
37783782
"bubbleEffect": true,

types/vue-data-ui.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4797,6 +4797,10 @@ declare module 'vue-data-ui' {
47974797
xyShowGrid?: boolean;
47984798
xyShowScale?: boolean;
47994799
yAxisLabel?: string;
4800+
zoomXy?: boolean;
4801+
zoomColor?: string;
4802+
zoomFontSize?: number;
4803+
zoomUseResetSlot?: boolean;
48004804
};
48014805

48024806
export type VueUiQuickChartDatasetObjectItem = {

0 commit comments

Comments
 (0)