SocialNetworks_duan/src/views/GroupEvolution/component/groupChart.vue

242 lines
6.0 KiB
Vue
Raw Normal View History

<template>
<div class="groupChart-component">
2025-07-23 11:22:19 +08:00
<img :src="title" alt="" class="title" v-if="title" />
<div class="container" id="container"></div>
<div class="slider-container">
<div
class="sliding-block"
:style="{ left: `${sliderLeft}px` }"
@mousedown="onMouseDown"
></div>
</div>
</div>
</template>
<script setup>
import { defineProps, onMounted, onBeforeUnmount, ref } from "vue";
import * as echarts from "echarts";
let chartInstance = null;
const props = defineProps({
title: {
type: String,
default: ""
},
chartData: {
type: Object,
default: ""
}
});
const sliderLeft = ref(25); // 滑块初始left
const sliderWidth = 24; // 滑块宽度
const sliderContainerWidth = ref(0); // 容器宽度
let isDragging = false;
let startX = 0;
let startLeft = 0;
const onMouseDown = (e) => {
isDragging = true;
startX = e.clientX;
startLeft = sliderLeft.value;
document.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseup", onMouseUp);
};
const onMouseMove = (e) => {
if (!isDragging) return;
const deltaX = e.clientX - startX;
let newLeft = startLeft + deltaX;
newLeft = Math.max(0, Math.min(newLeft, sliderContainerWidth.value - sliderWidth));
sliderLeft.value = newLeft;
// 计算当前滑块对应的x轴索引
const percent = newLeft / (sliderContainerWidth.value - sliderWidth);
const xIndex = Math.round(percent * (props.chartData.xAxisData.length - 1));
// 调用ECharts显示tooltip
if (chartInstance) {
chartInstance.dispatchAction({
type: "showTip",
seriesIndex: 0, // 只显示第一个系列的tooltip
dataIndex: xIndex
});
}
};
const onMouseUp = () => {
isDragging = false;
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseup", onMouseUp);
};
const initChart = () => {
chartInstance = echarts.init(document.getElementById("container"));
const legendData = props.chartData.seriesList.map((item) => ({
name: item.name,
icon: "circle"
}));
const option = {
tooltip: {
trigger: "axis"
},
legend: {
data: legendData,
right: 10, // 距离右侧 10px
top: 13,
textStyle: {
color: "#fff"
}
},
tooltip: {
trigger: "axis",
backgroundColor: "rgba(0,0,0,0)", // 透明背景
borderColor: "rgba(0,0,0,0)", // 透明边框
borderWidth: 0,
extraCssText: "box-shadow:none;padding:0;",
formatter: function (params) {
const color = {
头部自媒体: "#33b6fb",
官方媒体: "#00d6da",
普通自媒体: "#fddc33"
};
const listHtml = params
.map(
(item) => `
<div style="
display:flex;
align-items:center;
justify-content:space-between;
width:100%;
height:30px;
border-radius:4px;
background:rgba(204,250,255,0.2);
margin-bottom:6px;
padding:0 8px;
color:#fff;
font-size:12px;
">
<p style="width:10px;height:10px;border-radius:50%;background-color:${color[item.seriesName]}"></p>
<span>${item.seriesName}</span>
<span style="
color: #fff;
text-align: right;
font-family: MiSans;
font-size: 14px;
font-style: normal;
font-weight: 500;
line-height: normal;
">${item.value}</span>
</div>
`
)
.join("");
return `
<div style="
width:150px;
border-radius:6px;
background:linear-gradient(304deg, rgba(28,103,175,0.3) -6.04%, rgba(2,95,137,0.3) 85.2%);
backdrop-filter:blur(4px);
padding:10px;
">
${listHtml}
</div>
`;
}
},
grid: {
left: "3%",
right: "4%",
bottom: "3%",
top: "30%",
containLabel: true
},
xAxis: {
type: "category",
boundaryGap: false,
data: props.chartData.xAxisData,
axisLabel: {
textStyle: {
color: "#94C1EC"
}
}
},
yAxis: {
name: "数量",
max: props.chartData.yAxisRange.max,
min: props.chartData.yAxisRange.min,
interval: props.chartData.yAxisRange.interval,
nameTextStyle: {
color: "#B6D6F7",
fontSize: 13,
align: "left",
padding: [0, 0, 5, -28] // 负值让文字更靠左
},
axisLabel: {
textStyle: {
color: "#94C1EC"
}
},
type: "value",
splitLine: {
show: true, // 是否显示分割线
lineStyle: {
color: ["rgba(57, 69, 106, 0.86)"], // 分割线颜色,可以使用数组实现交替颜色
width: 1, // 分割线宽度
type: "dotted" // 分割线类型
}
}
},
series: props.chartData.seriesList
};
chartInstance.setOption(option);
};
onMounted(() => {
initChart();
// 获取容器宽度
sliderContainerWidth.value = document.querySelector(".slider-container").offsetWidth;
});
onBeforeUnmount(() => {
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseup", onMouseUp);
});
</script>
<style scoped lang="less">
.groupChart-component {
width: 100%;
height: 100%;
padding: 10px 10px;
.title {
margin-top: -18px;
margin-left: -12px;
}
.container {
width: 100%;
height: 180px;
}
.slider-container {
width: 100%;
height: 4px;
border-radius: 20px;
background: linear-gradient(270deg, rgba(0, 82, 125, 0.48) 0%, rgba(0, 200, 255, 0.23) 100%);
backdrop-filter: blur(3px);
margin-top: 10px;
position: relative;
.sliding-block {
width: 24px;
height: 8px;
border-radius: 2px;
background: linear-gradient(270deg, #00527d 0%, #00c8ff 100%);
backdrop-filter: blur(3px);
position: absolute;
top: -2px;
left: 25px;
cursor: pointer;
}
}
}
</style>