Skip to content

Commit 01fc233

Browse files
committed
VueUiTreemap improved zoom functionality & animations
1 parent a41dde1 commit 01fc233

File tree

4 files changed

+45
-67
lines changed

4 files changed

+45
-67
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.0.68",
4+
"version": "2.0.69",
55
"type": "module",
66
"description": "A user-empowering data visualization Vue components library",
77
"keywords": [

src/App.vue

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3139,9 +3139,6 @@ function treemapSelect(data) {
31393139
</template>
31403140
</Box>
31413141

3142-
<TreemapTest :dataset="treemapDataset" :config="treemapConfig" @selectLegend="treemapSelect" @selectDatapoint="treemapSelect">
3143-
</TreemapTest>
3144-
31453142
<Box open @copy="copyConfig(PROD_CONFIG.vue_ui_treemap)">
31463143
<template #title>
31473144
<BaseIcon name="chartTreemap"/>
@@ -3151,6 +3148,7 @@ function treemapSelect(data) {
31513148
</template>
31523149
<template #dev>
31533150
<TreemapTest :dataset="treemapDataset" :config="treemapConfig" @selectLegend="treemapSelect" @selectDatapoint="treemapSelect">
3151+
31543152
</TreemapTest>
31553153
</template>
31563154
<template #prod>

src/components/vue-ui-treemap.vue

Lines changed: 41 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -93,23 +93,37 @@ const svg = computed(() => {
9393
}
9494
});
9595
96-
const immutableDataset = ref(props.dataset.map(ds => {
97-
return {
98-
...ds,
99-
id: createUid()
96+
function addIdsToTree(tree) {
97+
tree.forEach((node, i) => {
98+
node.id = createUid();
99+
node.color = convertColorToHex(node.color) || palette[i] || palette[i % palette.length];
100+
if (node.children) {
101+
node.children.forEach(c => {
102+
c.parentId = node.id,
103+
c.color = node.color
104+
})
105+
addIdsToTree(node.children);
100106
}
101-
}));
107+
});
108+
}
109+
110+
const immutableDataset = ref(props.dataset);
111+
onMounted(() => {
112+
addIdsToTree(immutableDataset.value)
113+
})
114+
115+
const currentSet = ref(immutableDataset.value)
102116
103117
const datasetCopy = computed(() => {
104-
return immutableDataset.value.map((ds, i) => {
118+
return currentSet.value.map((ds, i) => {
105119
return {
106120
...ds,
107121
color: convertColorToHex(ds.color) || palette[i] || palette[i % palette.length],
108122
}
109123
}).filter((ds) => !segregated.value.includes(ds.id))
110124
});
111125
112-
const total = computed(() => datasetCopy.value.map(d => d.value).reduce((a, b) => a + b, 0));
126+
const total = computed(() => immutableDataset.value.filter((ds) => !segregated.value.includes(ds.id)).map(d => d.value || 0).reduce((a, b) => a + b, 0));
113127
114128
const orderedDataset = computed({
115129
get() {
@@ -146,7 +160,6 @@ function mapChildren(children, parentColor, parentName, totalValue) {
146160
color,
147161
proportion,
148162
parentName,
149-
id: createUid(),
150163
children: item.children ? mapChildren(item.children, color, item.name, totalValue) : undefined
151164
};
152165
});
@@ -234,11 +247,29 @@ const viewBox = ref({
234247
})
235248
const isZoom = ref(false);
236249
250+
function findNodeById(id, nodes = immutableDataset.value) {
251+
for (const node of nodes) {
252+
if (node.id === id) {
253+
return node;
254+
}
255+
if (node.children) {
256+
const foundNode = findNodeById(id, node.children);
257+
if (foundNode) {
258+
return foundNode;
259+
}
260+
}
261+
}
262+
return null;
263+
};
264+
265+
237266
function zoom(rect) {
238267
if(isZoom.value) {
239268
emit('selectDatapoint', undefined);
269+
currentSet.value = immutableDataset.value;
240270
} else {
241271
emit('selectDatapoint', rect);
272+
currentSet.value = [findNodeById(rect.parentId)];
242273
}
243274
isZoom.value = !isZoom.value;
244275
}
@@ -487,7 +518,7 @@ defineExpose({
487518
datapoint: rect,
488519
seriesIndex: i,
489520
})"
490-
@mouseleave="!isZoom ? selectedRect = null : ''; isTooltip = false"
521+
@mouseleave="selectedRect = null; isTooltip = false"
491522
:style="`opacity:${selectedRect ? selectedRect.id === rect.id ? 1 : treemapConfig.style.chart.layout.rects.selected.unselectedOpacity : 1}`"
492523
class="vue-ui-treemap-rect"
493524
/>
@@ -498,7 +529,6 @@ defineExpose({
498529
:height="getHeight(rect)"
499530
:width="getWidth(rect)"
500531
class="vue-ui-treemap-cell-foreignObject"
501-
v-if="!isZoom"
502532
>
503533
<div style="width: 100%; height: 100%" class="vue-ui-treemap-cell">
504534
<div
@@ -529,56 +559,6 @@ defineExpose({
529559
</div>
530560
</foreignObject>
531561
</g>
532-
533-
534-
<g v-if="isZoom">
535-
<rect
536-
:x="treemapConfig.style.chart.padding.left * 2"
537-
:y="treemapConfig.style.chart.padding.top * 2"
538-
:width="svg.vbWidth - (treemapConfig.style.chart.padding.left * 2) - (treemapConfig.style.chart.padding.right * 2)"
539-
:height="svg.vbHeight - treemapConfig.style.chart.padding.top - treemapConfig.style.chart.padding.bottom"
540-
:fill="treemapConfig.style.chart.layout.rects.gradient.show ? `url(#tgrad_${selectedRect.id})` : selectedRect.color"
541-
:rx="treemapConfig.style.chart.layout.rects.borderRadius"
542-
:stroke="treemapConfig.style.chart.layout.rects.selected.stroke"
543-
@click="zoom(selectedRect)"
544-
class="vue-ui-treemap-cell-zoom"
545-
/>
546-
<foreignObject
547-
:x="treemapConfig.style.chart.padding.left * 2"
548-
:y="treemapConfig.style.chart.padding.top * 2"
549-
:width="svg.vbWidth - (treemapConfig.style.chart.padding.left * 2) - (treemapConfig.style.chart.padding.right * 2)"
550-
:height="svg.vbHeight - treemapConfig.style.chart.padding.top - treemapConfig.style.chart.padding.bottom"
551-
class="vue-ui-treemap-cell-foreignObject"
552-
>
553-
<div style="width: 100%; height: 100%" class="vue-ui-treemap-cell">
554-
<div
555-
class="vue-ui-treemap-cell-default"
556-
v-if="treemapConfig.style.chart.layout.labels.showDefaultLabels" :style="`width:calc(100% - ${treemapConfig.style.chart.layout.labels.fontSize/ 1.5}px);text-align:left;padding:${treemapConfig.style.chart.layout.labels.fontSize / 3}px; color:${adaptColorToBackground(selectedRect.color)}`"
557-
>
558-
<span :style="`width:100%;`">
559-
{{ selectedRect.name }}
560-
</span><br>
561-
<span :style="`width:100%;`">
562-
{{ dataLabel({
563-
p: treemapConfig.style.chart.layout.labels.prefix,
564-
v: selectedRect.value,
565-
s: treemapConfig.style.chart.layout.labels.suffix,
566-
r: treemapConfig.style.chart.layout.labels.rounding
567-
}) }}
568-
</span>
569-
</div>
570-
<slot
571-
name="rect"
572-
v-bind="{
573-
rect: selectedRect,
574-
shouldShow: selectedRect.proportion > treemapConfig.style.chart.layout.labels.hideUnderProportion || isZoom,
575-
fontSize: calcFontSize(selectedRect),
576-
isZoom,
577-
textColor: adaptColorToBackground(selectedRect.color)
578-
}"/>
579-
</div>
580-
</foreignObject>
581-
</g>
582562
<slot name="svg" v-bind="{ svg, isZoom, rect: selectedRect, config: treemapConfig }"/>
583563
</svg>
584564

@@ -677,7 +657,7 @@ defineExpose({
677657
}
678658
679659
.vue-ui-treemap-rect {
680-
transition: opacity 0.2s ease-in-out;
660+
transition: all 0.2s ease-in-out;
681661
}
682662
683663
.vue-ui-treemap-zoom-info {

0 commit comments

Comments
 (0)