效果如图:
思路
- 随机生成120条数据,渲染折线图,引入内置型数据区域缩放组件
- 计算数据窗口15个大致对应的平移步长
step,该值与dataZoom.startdataZoom.end一样,是百分比的形式 - 点击前移按钮触发数据区域缩放行为,数据窗口起点、终点同时减步长,后移同加。端点要进行特殊处理,否则触边再反向移动后,窗口宽度可能会改变。处理如下:前移起点不小于0%,起点为0%时终点为
0+step%;后移终点不大于100%,终点为100%时起点为100-step%
代码
Vue函数、生命周期钩子等已通过unplugin-auto-import自动导入
<template>
<div class="container">
<button class="btn btn-prev" @click="toPrev">L</button>
<div ref="chartRef" style="height: 100%"></div>
<button class="btn btn-next" @click="toNext">R</button>
</div>
</template>
<script setup>
import * as echarts from 'echarts'
const chartRef = shallowRef()
let chart
const option = {
grid: { left: 50, right: 50, bottom: '1%', containLabel: true },
xAxis: {
type: 'category',
data: []
},
yAxis: { type: 'value' },
dataZoom: { type: 'inside', start: 0, end: 100 },
series: [
{
data: [],
type: 'line'
}
],
animation: false
}
let step = 0
const toPrev = () => {
if (!chart) return
const { start, end } = option.dataZoom
if (start === 0) {
alert('前无数据')
} else {
option.dataZoom.start = Math.max(0, start - step)
option.dataZoom.end = option.dataZoom.start === 0 ? 0 + step : end - step
chart.dispatchAction({
type: 'dataZoom',
start: option.dataZoom.start,
end: option.dataZoom.end
})
}
}
const toNext = () => {
if (!chart) return
const { start, end } = option.dataZoom
if (end === 100) {
alert('后无数据')
} else {
option.dataZoom.end = Math.min(100, end + step)
option.dataZoom.start = option.dataZoom.end === 100 ? 100 - step : start + step
chart.dispatchAction({
type: 'dataZoom',
start: option.dataZoom.start,
end: option.dataZoom.end
})
}
}
function renderChart() {
if (chart) chart.clear()
option.xAxis.data.length = 0
option.series[0].data.length = 0
option.dataZoom.start = 0
option.dataZoom.end = 100
/* 重置结束 */
option.xAxis.data = Array.from({ length: 120 }, (_, i) => `Day${i + 1}`)
option.series[0].data = Array.from({ length: 120 }, () => Math.random() * 400)
step = Math.min(100, Math.floor((15 / option.series[0].data.length) * 100)) // 数据窗口15个左右
option.dataZoom.end = step
nextTick(() => {
if (!chart) chart = echarts.init(chartRef.value)
chart.setOption(option)
})
}
onBeforeMount(() => {
renderChart()
})
onBeforeUnmount(() => {
if (chart) chart.dispose()
})
</script>
<style scoped lang="scss">
.container {
position: relative;
height: 400px;
border: 1px solid #ccc;
}
.btn {
position: absolute;
top: 50%;
z-index: 1;
transform: translateY(-50%);
cursor: pointer;
}
.btn-prev {
left: 8px;
}
.btn-next {
right: 8px;
}
</style>