|
@@ -1,119 +1,134 @@
|
|
|
<!-- 访客趋势图组件 -->
|
|
|
<template>
|
|
|
- <div class="bubble-chart-container">
|
|
|
- <div ref="chartRef" class="chart"></div>
|
|
|
+ <div class="visitor-trend">
|
|
|
+ <div ref="chartRef" style="width: 100%; height: 300px"></div>
|
|
|
+ <div style="position: absolute; top: 20px; right: 0">
|
|
|
+ <el-select v-model="value" style="width: 84px" @change="initChart">
|
|
|
+ <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts" name="keywordFrequency">
|
|
|
import { ref, onMounted, onUnmounted, watch } from 'vue';
|
|
|
import * as echarts from 'echarts';
|
|
|
-import { markRaw } from 'vue';
|
|
|
|
|
|
-interface ChartDataItem {
|
|
|
- name: string;
|
|
|
- value: number;
|
|
|
- color: string;
|
|
|
-}
|
|
|
+const chartData = ref([
|
|
|
+ { name: '下载', value: 30, color: '#ff6384' },
|
|
|
+ { name: '宅六', value: 10, color: '#4bc0c0' },
|
|
|
+
|
|
|
+ { name: '张三', value: 20, color: '#36a2eb' },
|
|
|
+ { name: '里斯', value: 25, color: '#cc65fe' },
|
|
|
+ { name: '王五', value: 15, color: '#ffce56' },
|
|
|
+]);
|
|
|
|
|
|
-const props = defineProps<{
|
|
|
- chartData: ChartDataItem[];
|
|
|
-}>();
|
|
|
+const value = ref('7');
|
|
|
+const options = [
|
|
|
+ {
|
|
|
+ value: '7',
|
|
|
+ label: '7天',
|
|
|
+ selected: true,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: '30',
|
|
|
+ label: '30天',
|
|
|
+ },
|
|
|
+];
|
|
|
|
|
|
-const chartRef = ref<HTMLElement | null>(null);
|
|
|
+const chartRef = ref(null);
|
|
|
let chartInstance: echarts.ECharts | null = null;
|
|
|
console.log(chartInstance);
|
|
|
|
|
|
// 初始化图表
|
|
|
const initChart = () => {
|
|
|
- if (!chartRef.value) return;
|
|
|
-
|
|
|
- // 销毁旧实例(如果存在)
|
|
|
- if (chartInstance) {
|
|
|
- chartInstance.dispose();
|
|
|
- }
|
|
|
-
|
|
|
- // 创建新实例
|
|
|
- chartInstance = markRaw(echarts.init(chartRef.value));
|
|
|
- console.log(chartInstance);
|
|
|
-
|
|
|
- // 处理数据
|
|
|
- const scatterData = props.chartData.map((item: ChartDataItem) => ({
|
|
|
- value: [Math.random() * 100, Math.random() * 100, 30 + Math.random() * 20],
|
|
|
- itemStyle: { color: item.color },
|
|
|
- name: `${item.name}\n${item.value}`
|
|
|
- }));
|
|
|
-
|
|
|
-
|
|
|
- // 配置项
|
|
|
- const option = {
|
|
|
- tooltip: {
|
|
|
- trigger: 'item',
|
|
|
- formatter: '{b}'
|
|
|
- },
|
|
|
- xAxis: { show: false },
|
|
|
- yAxis: { show: false },
|
|
|
- series: [{
|
|
|
- type: 'scatter',
|
|
|
- data: scatterData,
|
|
|
- symbolSize: function (data: any) {
|
|
|
- return data[2]*2.4; // 使用第三个值作为气泡大小
|
|
|
- },
|
|
|
- label: {
|
|
|
- show: true,
|
|
|
- position: 'inside',
|
|
|
- color: '#fff',
|
|
|
- fontSize: 14,
|
|
|
- formatter: '{b}'
|
|
|
- },
|
|
|
- emphasis: {
|
|
|
- label: { show: true }
|
|
|
- }
|
|
|
- }]
|
|
|
- };
|
|
|
-
|
|
|
- // 设置配置项
|
|
|
- chartInstance.setOption(option);
|
|
|
-
|
|
|
- // 添加响应式
|
|
|
- window.addEventListener('resize', handleResize);
|
|
|
+ if (!chartRef.value) return;
|
|
|
+
|
|
|
+ // 销毁旧实例(如果存在)
|
|
|
+ if (chartInstance) {
|
|
|
+ chartInstance.dispose();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建新实例
|
|
|
+ chartInstance = echarts.init(chartRef.value);
|
|
|
+ console.log(chartInstance);
|
|
|
+
|
|
|
+ // 处理数据
|
|
|
+ const scatterData = chartData.value.map((item) => ({
|
|
|
+ value: [Math.random() * 100, Math.random() * 100, 30 + Math.random() * 20],
|
|
|
+ itemStyle: { color: item.color },
|
|
|
+ name: `${item.name}\n${item.value}`,
|
|
|
+ }));
|
|
|
+
|
|
|
+ // 配置项
|
|
|
+ const option = {
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'item',
|
|
|
+ formatter: '{b}',
|
|
|
+ },
|
|
|
+ grid: {
|
|
|
+ top: '40%',
|
|
|
+ },
|
|
|
+ xAxis: { show: false },
|
|
|
+ yAxis: { show: false },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ type: 'scatter',
|
|
|
+ data: scatterData,
|
|
|
+ symbolSize: (value: any) => {
|
|
|
+ return Math.sqrt(value[2]) * 10; // 根据值计算气泡大小
|
|
|
+ },
|
|
|
+ label: {
|
|
|
+ show: true,
|
|
|
+ position: 'inside',
|
|
|
+ color: '#fff',
|
|
|
+ fontSize: 14,
|
|
|
+ formatter: '{b}',
|
|
|
+ },
|
|
|
+ emphasis: {
|
|
|
+ label: { show: true },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ };
|
|
|
+
|
|
|
+ // 设置配置项
|
|
|
+ chartInstance.setOption(option);
|
|
|
+
|
|
|
+ // 添加响应式
|
|
|
+ window.addEventListener('resize', handleResize);
|
|
|
};
|
|
|
|
|
|
// 响应窗口大小变化
|
|
|
const handleResize = () => {
|
|
|
- if (chartInstance) {
|
|
|
- chartInstance.resize();
|
|
|
- }
|
|
|
+ if (chartInstance) {
|
|
|
+ chartInstance.resize();
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
// 生命周期钩子
|
|
|
onMounted(() => {
|
|
|
- initChart();
|
|
|
+ initChart();
|
|
|
});
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
- if (chartInstance) {
|
|
|
- window.removeEventListener('resize', handleResize);
|
|
|
- chartInstance.dispose();
|
|
|
- chartInstance = null;
|
|
|
- }
|
|
|
+ if (chartInstance) {
|
|
|
+ window.removeEventListener('resize', handleResize);
|
|
|
+ chartInstance.dispose();
|
|
|
+ chartInstance = null;
|
|
|
+ }
|
|
|
});
|
|
|
-
|
|
|
-// 监听数据变化,更新图表
|
|
|
-watch(() => props.chartData, () => {
|
|
|
- initChart();
|
|
|
-}, { deep: true });
|
|
|
</script>
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
.bubble-chart-container {
|
|
|
- width: 465px;
|
|
|
- height: 330px;
|
|
|
- min-height: 330px;
|
|
|
+ width: 465px;
|
|
|
+ height: 330px;
|
|
|
+ min-height: 330px;
|
|
|
}
|
|
|
|
|
|
.chart {
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
}
|
|
|
</style>
|