You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
4.3 KiB
157 lines
4.3 KiB
<template>
|
|
<div ref="chart" class="chart-box" />
|
|
</template>
|
|
|
|
<script>
|
|
import { debounce } from '@/utils/index'
|
|
|
|
export default {
|
|
name: 'YearInFlowChart',
|
|
props: {
|
|
yearData: {
|
|
type: Array,
|
|
default: () => []
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
chart: null,
|
|
ro: null
|
|
}
|
|
},
|
|
computed: {
|
|
xAxis() {
|
|
return this.yearData.map((i) => i.month + '月')
|
|
},
|
|
series() {
|
|
return this.yearData.map((i) => i.count || 0)
|
|
}
|
|
},
|
|
watch: {
|
|
yearData() {
|
|
this.setOption()
|
|
}
|
|
},
|
|
mounted() {
|
|
this.$nextTick(() => this.initChart())
|
|
},
|
|
beforeDestroy() {
|
|
this.stopTipLoop()
|
|
if (this.ro) {
|
|
this.ro.disconnect()
|
|
this.ro = null
|
|
}
|
|
if (this.chart) {
|
|
this.chart.dispose()
|
|
this.chart = null
|
|
}
|
|
},
|
|
methods: {
|
|
initChart() {
|
|
this.chart = this.$echarts.init(this.$refs.chart)
|
|
this.setOption()
|
|
// 用 ResizeObserver 监听容器自身尺寸变化,比 window.resize 更可靠
|
|
const doResize = debounce(() => {
|
|
if (this.chart) this.chart.resize()
|
|
}, 100)
|
|
this.ro = new ResizeObserver(() => doResize())
|
|
this.ro.observe(this.$refs.chart)
|
|
},
|
|
setOption() {
|
|
if (!this.chart) return
|
|
const idx = Math.max(0, this.series.length - 1)
|
|
const lastVal = this.series[idx]
|
|
this.chart.setOption({
|
|
tooltip: {
|
|
trigger: 'axis',
|
|
backgroundColor: 'rgba(11, 26, 48, 0.92)',
|
|
borderColor: '#18E3A7',
|
|
textStyle: { color: '#e2e8f0', fontSize: 14 },
|
|
axisPointer: { type: 'line', lineStyle: { color: '#18E3A7' }}
|
|
},
|
|
grid: { left: 40, right: 20, top: 50, bottom: 30, containLabel: false },
|
|
xAxis: {
|
|
type: 'category',
|
|
data: this.xAxis,
|
|
boundaryGap: false,
|
|
axisLine: { lineStyle: { color: 'rgba(24,227,167,0.4)' }},
|
|
axisTick: { show: false },
|
|
axisLabel: { color: 'rgba(255,255,255,0.7)', fontSize: 12, interval: 'auto' },
|
|
splitLine: { show: false }
|
|
},
|
|
yAxis: {
|
|
type: 'value',
|
|
min: 0,
|
|
max: (v) => v.max === 0 ? 100 : Math.ceil(v.max * 1.25),
|
|
axisLine: { show: false },
|
|
axisTick: { show: false },
|
|
axisLabel: { color: 'rgba(255,255,255,0.6)', fontSize: 12 },
|
|
splitLine: { lineStyle: { color: 'rgba(24,227,167,0.12)', type: 'dashed' }}
|
|
},
|
|
series: [{
|
|
name: '进馆人次',
|
|
type: 'line',
|
|
smooth: true,
|
|
symbol: 'none',
|
|
showSymbol: false,
|
|
data: this.series,
|
|
lineStyle: { color: '#18E3A7', width: 3, shadowColor: '#18E3A7', shadowBlur: 12 },
|
|
itemStyle: { color: '#18E3A7' },
|
|
areaStyle: {
|
|
color: new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{ offset: 0, color: 'rgba(24,227,167,0.45)' },
|
|
{ offset: 1, color: 'rgba(24,227,167,0.02)' }
|
|
])
|
|
},
|
|
markPoint: {
|
|
symbol: 'circle',
|
|
symbolSize: 12,
|
|
label: {
|
|
position: 'top',
|
|
distance: 12,
|
|
formatter: () => String(lastVal),
|
|
fontSize: 26,
|
|
fontWeight: 800,
|
|
color: '#fff',
|
|
textShadowColor: 'rgba(24,227,167,0.8)',
|
|
textShadowBlur: 10
|
|
},
|
|
itemStyle: {
|
|
color: '#18E3A7',
|
|
shadowColor: 'rgba(24,227,167,1)',
|
|
shadowBlur: 12
|
|
},
|
|
data: [{ coord: [idx, lastVal] }]
|
|
}
|
|
}]
|
|
})
|
|
this.startTipLoop()
|
|
},
|
|
// 动态轮播 tooltip,适配大屏无人交互场景
|
|
startTipLoop() {
|
|
this.stopTipLoop()
|
|
if (!this.series.length) return
|
|
this.tipIndex = -1
|
|
this.tipTimer = setInterval(() => {
|
|
if (!this.chart || !this.series.length) return
|
|
this.tipIndex = (this.tipIndex + 1) % this.series.length
|
|
this.chart.dispatchAction({
|
|
type: 'showTip',
|
|
seriesIndex: 0,
|
|
dataIndex: this.tipIndex
|
|
})
|
|
}, 2500)
|
|
},
|
|
stopTipLoop() {
|
|
if (this.tipTimer) {
|
|
clearInterval(this.tipTimer)
|
|
this.tipTimer = null
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
@import "~@/assets/styles/index.scss";
|
|
</style>
|