SocialNetworks_duan/src/components/weight/EventHeatmap.vue

252 lines
6.4 KiB
Vue
Raw Normal View History

2025-07-17 10:28:56 +08:00
<template>
<div class="panel-container event-hot">
<!-- 1. 标题行 -->
<div class="header-title">
<img
src="../../assets/images/evenhot.png"
alt=""
style="margin-top: -22px; margin-left: -22px"
/>
</div>
<!-- 2. 控件行 -->
<div class="header-controls">
<div class="chart-tabs">
<button :class="{ active: activeChartTab === 'trend' }" @click="activeChartTab = 'trend'">
时序热度图
</button>
<button
:class="{ active: activeChartTab === 'cumulative' }"
@click="activeChartTab = 'cumulative'"
>
累计热度图
</button>
</div>
<button class="details-btn" @click="showDetails">查看详情</button>
</div>
<!-- 3. ECharts 容器 -->
<div ref="hotspotChart" class="chart-container"></div>
</div>
</template>
<script setup>
import { ref, watch, onMounted, onUnmounted, defineProps } from "vue";
import * as echarts from "echarts";
const props = defineProps({
panelTrendData: {
//时序热度列表
type: Array,
default: () => []
},
panelXAxisLabels: {
//x轴
type: Array,
default: () => []
},
granularTrendData: {
//查看详情数据
type: Array,
default: () => []
},
granularXAxisLabels: {
//查看详情x轴数据
type: Array,
default: () => []
}
});
const emit = defineEmits(["showDetails"]);
// ===================================================================
// 数据定义与处理
// ===================================================================
const activeChartTab = ref("trend");
// --- 完整/详情用数据 (Granular/Details Data) ---
const granularTrendData = props.granularTrendData;
const granularXAxisLabels = props.granularXAxisLabels;
const granularCumulativeData = granularTrendData.reduce((acc, val) => {
acc.push((acc.length > 0 ? acc[acc.length - 1] : 0) + val);
return acc;
}, []);
// --- 面板用数据 (Panel Data - Daily Summary) ---
const panelTrendData = props.panelTrendData; // Figma中的数据
const panelXAxisLabels = props.panelXAxisLabels;
const panelCumulativeData = panelTrendData.reduce((acc, val) => {
acc.push((acc.length > 0 ? acc[acc.length - 1] : 0) + val);
return acc;
}, []);
// --- 整合数据集 ---
const chartDataSets = {
panel: {
trend: { data: panelTrendData, xAxis: panelXAxisLabels, yAxisMax: 60000 },
cumulative: { data: panelCumulativeData, xAxis: panelXAxisLabels, yAxisMax: 120000 }
},
details: {
trend: { data: granularTrendData, xAxis: granularXAxisLabels, yAxisMax: 20000 },
cumulative: { data: granularCumulativeData, xAxis: granularXAxisLabels, yAxisMax: 120000 }
}
};
// ===================================================================
// ECharts 逻辑
// ===================================================================
const hotspotChart = ref(null);
let myChart = null;
const getChartOptions = (xAxisData, seriesData, yMax, rotate = 0) => ({
tooltip: {
trigger: "axis",
backgroundColor: "rgba(0,21,41,0.8)",
borderColor: "#3a95ff",
2025-07-18 17:44:13 +08:00
textStyle: { color: "#cbeaff" },
2025-07-17 10:28:56 +08:00
},
grid: { left: "3%", right: "8%", bottom: "5%", top: "20%", containLabel: true },
xAxis: {
type: "category",
boundaryGap: false,
data: xAxisData,
axisLine: { lineStyle: { color: "rgba(62, 115, 171, 0.5)" } },
axisLabel: { color: "#a7c5d4", fontSize: 10, rotate: rotate, interval: 0 },
axisTick: { show: false }
},
yAxis: {
type: "value",
max: yMax,
axisLabel: { color: "#a7c5d4", fontSize: 12 },
splitLine: { show: true, lineStyle: { color: "rgba(62, 115, 171, 0.2)", type: "dashed" } }
},
series: [
{
name: "热度",
type: "line",
smooth: true,
symbol: "circle",
symbolSize: 8,
data: seriesData,
label: { show: true, position: "top", color: "#cdeeff", fontSize: 12 },
itemStyle: { color: "#00baff", borderColor: "#041421", borderWidth: 2 },
lineStyle: { color: "#00baff", width: 2 },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "rgba(0, 186, 255, 0.4)" },
{ offset: 1, color: "rgba(0, 186, 255, 0)" }
])
}
}
]
});
// 监听标签页切换,更新面板小图
watch(activeChartTab, (newTab) => {
if (myChart) {
const dataSet = chartDataSets.panel[newTab];
myChart.setOption({
xAxis: [{ data: dataSet.xAxis }],
yAxis: { max: dataSet.yAxisMax },
series: [{ data: dataSet.data }]
});
}
});
// 点击“查看详情”时,触发事件并传递完整数据
const showDetails = () => {
const dataSet = chartDataSets.details[activeChartTab.value];
const rotate = dataSet.xAxis.length > 5 ? 15 : 0;
const option = getChartOptions(dataSet.xAxis, dataSet.data, dataSet.yAxisMax, rotate);
emit("showDetails", { option });
};
onMounted(() => {
if (hotspotChart.value) {
myChart = echarts.init(hotspotChart.value);
// 初始化时使用面板数据
const initialDataSet = chartDataSets.panel[activeChartTab.value];
myChart.setOption(
getChartOptions(initialDataSet.xAxis, initialDataSet.data, initialDataSet.yAxisMax)
);
}
});
onUnmounted(() => {
if (myChart) myChart.dispose();
});
</script>
<style scoped>
/* 容器样式,无边框 */
.panel-container {
width: 350px;
height: 276px;
background: rgba(4, 20, 33, 0.4);
border-radius: 2px;
box-shadow: 0 0 18px 0 #0a2e55 inset;
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
padding: 15px 20px;
box-sizing: border-box;
display: flex;
flex-direction: column;
border: 1px solid #1a8bff;
}
/* 标题行 */
.header-title {
width: 100%;
margin-bottom: 5px;
}
.header-title img {
}
/* 控件行 */
.header-controls {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.chart-tabs {
display: flex;
border: 1px solid #1c588f;
border-radius: 3px;
background-color: #031826;
}
.chart-tabs button {
background: none;
border: none;
color: #a7c5d4;
padding: 4px 12px;
font-size: 14px;
cursor: pointer;
transition: all 0.2s;
}
.chart-tabs button.active {
background-color: #236291;
color: white;
border-radius: 2px;
}
.details-btn {
margin-left: auto;
background: none;
border: 1px solid #1c588f;
color: #a7c5d4;
padding: 4px 12px;
font-size: 14px;
border-radius: 3px;
cursor: pointer;
}
.chart-container {
flex-grow: 1;
width: 100%;
margin-left: -10px;
}
</style>