empower_front/src/views/dashboard/components/DashboardEffectScatter.vue

143 lines
3.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup>
import { useRoute } from "vue-router";
import EffectScatter from "@/components/chart/EffectScatter.vue";
import useSearchParam from "@/hooks/useSearchParam";
import { computed, inject, ref, watch } from "vue";
import { twMerge } from "tailwind-merge";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const route = useRoute();
const { searchParams, changeParams } = useSearchParam();
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
const props = defineProps({
data: {
type: Object,
},
});
const asset_floor_chart = ref(null);
const currentFloorId = ref(null);
const defaultOption = (map, data = []) => {
return {
animation: false,
tooltip: {},
geo: {
tooltip: {
show: true,
confine: true,
formatter: function (params) {
return params.data[2]?.full_name
? `
<div class="p-2 w-auto min-w-24">
<div class="text-lg">${params.data[2].full_name}</div>
<div class="text-sm text-gray-500">${t("operation.status")} : ${
params.data[2].state || ""
}</div>`
: "";
},
},
map,
roam: true, // 允許縮放和平移
layoutSize: window.innerWidth <= 768 ? "110%" : "100%",
layoutCenter: ["50%", "50%"],
scaleLimit: { min: 1, max: 2 },
},
series: [
// 背景圓形
{
type: "scatter",
coordinateSystem: "geo",
geoIndex: 0,
symbolSize: (value) => value[2]?.bgSize || 50,
symbol: "range",
itemStyle: {
color: (params) => params.data[2]?.bgColor || "rgba(0,0,0,0.8)",
},
data,
z: 1,
},
{
type: "scatter",
coordinateSystem: "geo",
geoIndex: 0,
encode: {
tooltip: 2,
},
symbolSize: 30,
itemStyle: {
color: "rgba(225,225,225,0.8)",
},
symbol: (value, params) => {
// 若有 icon 屬性就用 image否則用圓點
return params.data[2]?.icon
? `image://${params.data[2].icon}`
: "roundRect";
},
data,
label: {
show: true,
position: "bottom",
formatter: (params) => params.data[2]?.full_name || "",
color: "#333",
fontSize: 14,
backgroundColor: "rgba(255,255,255)",
padding: [4, 4],
borderRadius: 3,
},
z: 2,
},
],
};
};
const currentIconData = computed(() => {
const data = props.data?.[searchParams.value.floor_id] || [];
return data;
});
watch(
[searchParams, () => asset_floor_chart.value, () => props.data],
([newValue, newChart, newData], [oldValue]) => {
if (newValue.floor_id && newChart && Object.keys(newData || {}).length > 0) {
const isFloorChanged = currentFloorId.value !== newValue.floor_id;
if (isFloorChanged) {
// 樓層切換時才重新載入 SVG
console.log("Floor changed, updating chart with new SVG", newValue.floor_id);
currentFloorId.value = newValue.floor_id;
newChart.updateSvg(
{
full_name: newValue.floor_id,
path: `${FILE_BASEURL}/upload/floor_map/${newValue.floor_id}.svg`,
},
defaultOption(newValue.floor_id, currentIconData.value)
);
} else if (currentFloorId.value === newValue.floor_id && newChart.chart) {
// 只是資料更新時,只更新圖表資料,不重新載入 SVG
console.log("Data updated, refreshing chart data only");
newChart.chart.setOption({
series: defaultOption(newValue.floor_id, currentIconData.value).series
}, false, true);
}
}
},
{
immediate: true,
deep: true,
}
);
</script>
<template>
<EffectScatter
id="system_floor_chart"
ref="asset_floor_chart"
class="bg-slate-300 absolute top-0 left-0 min-h-full z-0"
/>
</template>
<style lang="scss" scoped></style>