Skip to content

Commit 5218a45

Browse files
committed
VueUiQuadrant improved zoom animation
1 parent 1976156 commit 5218a45

File tree

6 files changed

+125
-27
lines changed

6 files changed

+125
-27
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "vue-data-ui",
33
"private": false,
4-
"version": "2.1.13",
4+
"version": "2.1.14",
55
"type": "module",
66
"description": "A user-empowering data visualization Vue components library",
77
"keywords": [

src/App.vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2749,7 +2749,6 @@ const radarConfig = ref({
27492749
const quadrantConfig = ref({
27502750
style: {
27512751
chart: {
2752-
backgroundColor: '#1A1A1A',
27532752
title: {
27542753
text: "Title",
27552754
subtitle: {

src/components/vue-ui-quadrant.vue

Lines changed: 119 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -225,43 +225,129 @@ const mutableSvg = ref({
225225
226226
const selectedSide = ref(null);
227227
228+
const selectedSideLabelCoordinates = computed(() => {
229+
switch (selectedSide.value) {
230+
case 'TL':
231+
return {
232+
x: mutableSvg.value.startX + mutableSvg.value.width / 2,
233+
y: mutableSvg.value.height,
234+
text: quadrantConfig.value.style.chart.layout.labels.quadrantLabels.tl.text || 'Top Left',
235+
fontSize: quadrantConfig.value.style.chart.layout.labels.quadrantLabels.tl.fontSize,
236+
fill: quadrantConfig.value.style.chart.layout.labels.quadrantLabels.tl.color,
237+
bold: quadrantConfig.value.style.chart.layout.labels.quadrantLabels.tl.bold
238+
}
239+
case 'TR':
240+
return {
241+
x: mutableSvg.value.startX + mutableSvg.value.width / 2,
242+
y: mutableSvg.value.height,
243+
text: quadrantConfig.value.style.chart.layout.labels.quadrantLabels.tr.text || 'Top Right',
244+
fontSize: quadrantConfig.value.style.chart.layout.labels.quadrantLabels.tr.fontSize,
245+
fill: quadrantConfig.value.style.chart.layout.labels.quadrantLabels.tr.color,
246+
bold: quadrantConfig.value.style.chart.layout.labels.quadrantLabels.tr.bold
247+
}
248+
case 'BR':
249+
return {
250+
x: mutableSvg.value.startX + mutableSvg.value.width / 2,
251+
y: mutableSvg.value.height * 1.678,
252+
text: quadrantConfig.value.style.chart.layout.labels.quadrantLabels.br.text || 'Bottom Right',
253+
fontSize: quadrantConfig.value.style.chart.layout.labels.quadrantLabels.br.fontSize,
254+
fill: quadrantConfig.value.style.chart.layout.labels.quadrantLabels.br.color,
255+
bold: quadrantConfig.value.style.chart.layout.labels.quadrantLabels.br.bold
256+
}
257+
case 'BL':
258+
return {
259+
x: mutableSvg.value.startX + mutableSvg.value.width / 2,
260+
y: mutableSvg.value.height * 1.678,
261+
text: quadrantConfig.value.style.chart.layout.labels.quadrantLabels.bl.text || 'Bottom Left',
262+
fontSize: quadrantConfig.value.style.chart.layout.labels.quadrantLabels.bl.fontSize,
263+
fill: quadrantConfig.value.style.chart.layout.labels.quadrantLabels.bl.color,
264+
bold: quadrantConfig.value.style.chart.layout.labels.quadrantLabels.bl.bold
265+
}
266+
267+
default:
268+
return {x: 0, y: 0, text: '', fontSize: 0, fill: 'none', bold: false}
269+
}
270+
})
271+
272+
const currentAnimationFrame = ref(null);
273+
const isAnimating = ref(false);
274+
275+
function zoomOnSide({ targetX, targetY, targetW, targetH}) {
276+
const differentials = {
277+
x: targetX - mutableSvg.value.startX,
278+
y: targetY - mutableSvg.value.startY,
279+
w: targetW - mutableSvg.value.width,
280+
h: targetH - mutableSvg.value.height
281+
}
282+
283+
const steps = quadrantConfig.value.zoomAnimationFrames;
284+
let init = 0;
285+
function anim() {
286+
isAnimating.value = true;
287+
mutableSvg.value.startX += (differentials.x / steps);
288+
mutableSvg.value.startY += (differentials.y / steps);
289+
mutableSvg.value.width += (differentials.w / steps);
290+
mutableSvg.value.height += (differentials.h / steps);
291+
init += 1;
292+
if(init < steps) {
293+
currentAnimationFrame.value = requestAnimationFrame(anim)
294+
} else {
295+
isAnimating.value = false;
296+
}
297+
}
298+
anim()
299+
}
300+
228301
function selectQuadrantSide(side) {
302+
if(isAnimating.value) {
303+
return;
304+
}
229305
if(isZoom.value && selectedSide.value === side) {
230-
mutableSvg.value.startX = 0;
231-
mutableSvg.value.startY = 0;
232-
mutableSvg.value.width = svg.value.width;
233-
mutableSvg.value.height = svg.value.height;
306+
zoomOnSide({
307+
targetX: 0,
308+
targetY: 0,
309+
targetW: svg.value.width,
310+
targetH: svg.value.height
311+
})
234312
selectedSide.value = null;
235313
isZoom.value = false;
236314
} else {
237315
selectedSide.value = side;
238316
switch (side) {
239317
case 'TL':
240-
mutableSvg.value.startX = 0;
241-
mutableSvg.value.startY = 0;
242-
mutableSvg.value.width = svg.value.width / 2 + svg.value.left;
243-
mutableSvg.value.height = svg.value.height / 2 + svg.value.top;
318+
zoomOnSide({
319+
targetX: 0,
320+
targetY: 0,
321+
targetW: svg.value.width / 2 + svg.value.left,
322+
targetH: svg.value.height / 2 + svg.value.top
323+
})
244324
break;
245325
246326
case 'TR':
247-
mutableSvg.value.startX = svg.value.width / 2 - svg.value.left;
248-
mutableSvg.value.startY = 0;
249-
mutableSvg.value.width = svg.value.width / 2 + svg.value.left;
250-
mutableSvg.value.height = svg.value.height / 2 + svg.value.top;
327+
zoomOnSide({
328+
targetX: svg.value.width / 2 - svg.value.left,
329+
targetY: 0,
330+
targetW: svg.value.width / 2 + svg.value.left,
331+
targetH: svg.value.height / 2 + svg.value.top
332+
})
251333
break;
252334
253335
case 'BR':
254-
mutableSvg.value.startX = svg.value.width / 2 - svg.value.left;
255-
mutableSvg.value.startY = svg.value.height / 2 - svg.value.top;
256-
mutableSvg.value.width = svg.value.width / 2 + svg.value.left;
257-
mutableSvg.value.height = svg.value.height / 2 + svg.value.top;
336+
zoomOnSide({
337+
targetX: svg.value.width / 2 - svg.value.left,
338+
targetY: svg.value.height / 2 - svg.value.top,
339+
targetW: svg.value.width / 2 + svg.value.left,
340+
targetH: svg.value.height / 2 + svg.value.top
341+
})
258342
break;
259343
260344
case 'BL':
261-
mutableSvg.value.startX = 0;
262-
mutableSvg.value.startY = svg.value.height / 2 - svg.value.top;
263-
mutableSvg.value.width = svg.value.width / 2 + svg.value.left;
264-
mutableSvg.value.height = svg.value.height / 2 + svg.value.top;
345+
zoomOnSide({
346+
targetX: 0,
347+
targetY: svg.value.height / 2 - svg.value.top,
348+
targetW: svg.value.width / 2 + svg.value.left,
349+
targetH: svg.value.height / 2 + svg.value.top
350+
})
265351
break;
266352
267353
default:
@@ -1205,6 +1291,19 @@ defineExpose({
12051291
/>
12061292
</g>
12071293

1294+
<g v-if="selectedSide && !isAnimating">
1295+
<text
1296+
:x="selectedSideLabelCoordinates.x"
1297+
:y="selectedSideLabelCoordinates.y - (selectedSideLabelCoordinates.fontSize / 1.5)"
1298+
:font-size="selectedSideLabelCoordinates.fontSize / 1.5"
1299+
:fill="selectedSideLabelCoordinates.fill"
1300+
text-anchor="middle"
1301+
:font-weight="selectedSideLabelCoordinates.bold ? 'bold' : 'normal'"
1302+
>
1303+
{{ selectedSideLabelCoordinates.text }}
1304+
</text>
1305+
</g>
1306+
12081307
<!-- LEGEND AS G -->
12091308
<foreignObject
12101309
v-if="quadrantConfig.style.chart.legend.show && mutableConfig.inside && !isPrinting"
@@ -1284,7 +1383,6 @@ defineExpose({
12841383
</g>
12851384
<slot name="svg" :svg="svg"/>
12861385
</svg>
1287-
{{ selectedSide }}
12881386

12891387
<Skeleton
12901388
v-if="!isDataset"

src/default_configs.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@
796796
},
797797
"vue_ui_quadrant": {
798798
"useCssAnimation": true,
799+
"zoomAnimationFrames": 20,
799800
"style": {
800801
"fontFamily": "inherit",
801802
"chart": {

types/vue-data-ui.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3173,6 +3173,7 @@ declare module 'vue-data-ui' {
31733173

31743174
export type VueUiQuadrantConfig = {
31753175
useCssAnimation?: boolean;
3176+
zoomAnimationFrames?: number;
31763177
style?: {
31773178
fontFamily?: string;
31783179
chart?: {
@@ -4732,8 +4733,7 @@ declare module 'vue-data-ui' {
47324733
};
47334734

47344735
export type VueUiQuickChartDatasetObjectItem = {
4735-
[key]: string;
4736-
[key]: number | number[]
4736+
[key: string]: string | number[];
47374737
};
47384738

47394739
export type VueUiQuickChartDataset = number[] | VueUiQuickChartDatasetObjectItem | VueUiQuickChartDatasetObjectItem[];

0 commit comments

Comments
 (0)