|
@@ -0,0 +1,134 @@
|
|
|
+<!-- 访客趋势图组件 -->
|
|
|
+<template>
|
|
|
+ <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';
|
|
|
+
|
|
|
+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 value = ref('7');
|
|
|
+const options = [
|
|
|
+ {
|
|
|
+ value: '7',
|
|
|
+ label: '7天',
|
|
|
+ selected: true,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: '30',
|
|
|
+ label: '30天',
|
|
|
+ },
|
|
|
+];
|
|
|
+
|
|
|
+const chartRef = ref(null);
|
|
|
+let chartInstance: echarts.ECharts | null = null;
|
|
|
+console.log(chartInstance);
|
|
|
+
|
|
|
+// 初始化图表
|
|
|
+const initChart = () => {
|
|
|
+ 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();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 生命周期钩子
|
|
|
+onMounted(() => {
|
|
|
+ initChart();
|
|
|
+});
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ if (chartInstance) {
|
|
|
+ window.removeEventListener('resize', handleResize);
|
|
|
+ chartInstance.dispose();
|
|
|
+ chartInstance = null;
|
|
|
+ }
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+.bubble-chart-container {
|
|
|
+ width: 465px;
|
|
|
+ height: 330px;
|
|
|
+ min-height: 330px;
|
|
|
+}
|
|
|
+
|
|
|
+.chart {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+</style>
|