123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- <template>
- <div ref="chartRef" class="chart"></div>
- </template>
- <script lang="ts" setup>
- import * as echarts from 'echarts';
- import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
- const props = defineProps({
- dates: { type: Array, required: true }, // x轴日期
- natural: { type: Array, required: true }, // 自然流量
- paid: { type: Array, required: true }, // 付费流量
- centerText: { type: String, default: '自然流量' } // 环形中间文字
- });
- const chartRef = ref(null);
- let chartInstance: any = null;
- const initChart = () => {
- if (!chartRef.value) return;
- chartInstance = echarts.init(chartRef.value);
- const paidsTotal: any = props.paid.reduce((a: any, b: any) => a + b);
- const naturalTotal: any = props.natural.reduce((a: any, b: any) => a + b);
- const option = {
- tooltip: {
- trigger: 'axis'
- },
- title: {
- text: '网站历史数据',
- left: 18,
- top: 0,
- textStyle: { fontSize: 16, fontWeight: 'bold', color: '#282E30' }
- },
- legend: {
- data: ['自然', '付费'],
- right: 'center',
- itemGap: 30,
- top: 0,
- textStyle: {
- color: '#282E30', // 图例文字颜色
- fontSize: 16
- }
- },
- graphic: [
- // {
- // type: 'text',
- // right: 17, // 整体靠右
- // top: 12,
- // style: {
- // text: `{a|自}{b|人工}{c|以来的完整历史数据 }`, // 使用富文本标记
- // rich: {
- // a: { color: '#000000', font: '12px Arial', padding: [0, 0, 0, 0] },
- // b: { color: '#036EB8', font: '12px Arial', padding: [0, 0, 0, 0] },
- // c: { color: '#000000', font: '12px Arial', padding: [0, 0, 0, 0] }
- // }
- // }
- // },
- {
- type: 'text',
- left: 'center', // 居中
- bottom: 0, // legend 下方位置,根据 legend.top 调整
- style: {
- text: '来自 Google 的流量-自然与付费',
- fill: 'rgba(40,46,48,0.6)', // 文字颜色
- font: '16px Arial'
- }
- }
- ],
- grid: {
- left: '9%',
- right: '3%'
- // top: '15%',
- // bottom: '15%'
- },
- xAxis: {
- type: 'category',
- data: props.dates,
- // boundaryGap: false,
- // axisTick: { alignWithLabel: true },
- splitLine: {
- // x 轴竖直方向虚线
- show: true,
- lineStyle: {
- type: 'dashed',
- color: '#ccc'
- }
- },
- axisLabel: {
- color: '#282E30', // 字体颜色
- fontSize: 12, // 字体大小
- fontWeight: '400' // 字体粗细 normal | bold | bolder | lighter
- },
- boundaryGap: true // 开启后类目会在刻度中间,而不是在刻度线上
- },
- yAxis: {
- type: 'value',
- min: 0,
- splitLine: {
- // y 轴水平方向虚线
- show: true,
- lineStyle: {
- type: 'dashed',
- color: '#ccc'
- }
- }
- },
- series: [
- {
- name: '自然',
- type: 'line',
- data: props.natural,
- smooth: false,
- symbol: 'circle',
- symbolSize: 12,
- lineStyle: {
- color: '#7ECEF4'
- },
- itemStyle: {
- color: '#7ECEF4',
- borderColor: '#fff',
- borderWidth: 2,
- shadowColor: 'rgba(126, 206, 244, 0.4)',
- shadowBlur: 10
- },
- areaStyle: null
- },
- {
- name: '付费',
- type: 'line',
- data: props.paid,
- smooth: false,
- symbol: 'circle',
- symbolSize: 10,
- lineStyle: {
- color: '#036EB8'
- },
- itemStyle: {
- color: '#036EB8',
- borderColor: '#fff',
- borderWidth: 2,
- shadowColor: 'rgba(3, 110, 184, 0.4)',
- shadowBlur: 10
- },
- areaStyle: null
- },
- // 白色圆形背景
- {
- type: 'pie',
- radius: ['48%'], // 半径比主环形图小一点或相同
- center: ['45%', '50%'],
- data: [{ value: 1, name: 'background' }],
- silent: true, // 不响应鼠标事件
- label: { show: false }, // 不显示文字
- itemStyle: { color: '#fff' }, // 白色
- z: 8 // 放在折线下方,但环形上方
- },
- // 中心环形图
- {
- type: 'pie',
- radius: ['35%', '45%'],
- center: ['45%', '50%'],
- data: [
- { value: paidsTotal, name: '付费', itemStyle: { color: '#036EB8' } },
- { value: naturalTotal, name: '自然', itemStyle: { color: '#7ECEF4' } }
- ],
- label: {
- show: false,
- position: 'center',
- fontSize: 16
- // fontWeight: 'bold'
- },
- emphasis: {
- label: {
- show: true, // 悬浮时显示
- formatter: '{b}流量', // 名称+数值
- fontSize: 16,
- fontWeight: 'bold',
- color: '#282E30'
- }
- },
- tooltip: {
- trigger: 'item'
- // formatter: '{b}: {c}' // 付费: 120
- },
- z: 10
- }
- ]
- };
- chartInstance.setOption(option);
- };
- // 自动 resize
- const resizeHandler = () => {
- chartInstance && chartInstance.resize();
- };
- onMounted(() => {
- initChart();
- window.addEventListener('resize', resizeHandler);
- });
- onBeforeUnmount(() => {
- window.removeEventListener('resize', resizeHandler);
- chartInstance && chartInstance.dispose();
- });
- // 监听数据变化,实时更新
- watch(
- () => [props.dates, props.natural, props.paid, props.centerText],
- () => {
- initChart();
- },
- { deep: true }
- );
- </script>
- <style lang="scss" scoped>
- .chart {
- width: 100%;
- height: 100%;
- position: relative;
- // left: 30px;
- :deep(canvas) {
- // left: 30px !important;
- }
- }
- </style>
|