echarts 趋势图拖拽缩放的方式配置y轴方向的上下限,附源码
接上一篇:echarts 直角坐标系中多个系列多个y轴展示方案
因为最近比较忙,一直没时间写这个。之前有小伙伴在评论区留言想要知道这个效果怎么写的,这里把代码贴下。
这个点击上下缩放的效果是之前别的项目上的,在某些特殊功能上还是比较有用的。但因为封装的功能和我这边的需求不一致,而且不是很好理解,然后我就参考了下代码自己写了一套,有需要的小伙伴可以参考下,主要是思路。
效果图(简书这个图片经常加载不出来,不知道你们是否能看到下面这个gif)
3.gif4.gif
操作方式就是点击折线后高亮,鼠标滚轮进行缩放,拖拽设置纵向位置,点击chart空白处取消高亮并关闭纵向缩放功能。
下面是组件设计要点:
一、点击线条进行拖拽缩放功能点
1.点击线条高亮,这里采用的是降低其他线条的透明度
2.初始可以缩放,初始时需要重新更改y轴的max和min,扩大范围
3.在y轴缩放时需要将dataZoom事件返回的start,end换算为 startValue 和 endValue,因为start,end是百分比,我们扩大了纵向的范围的,不能使用百分比
4.为了不让x轴跳动,组件内设置x轴的onZero为false,脱离y轴0刻度
5.保留x轴缩放功能,内部缩放的方式在高亮时被禁用,slider方式无限制
二、扩展功能,可以定时刷新图表需要考虑的功能点有:
1.需要保证选择线的高亮不变
2.y轴缩放不变
3.x轴缩放不变
4.legend的选中状态不变
以上功能都需要在各自触发时将信息存储起来,由组件内部会在合适的地方记录这些信息,initYZoom方法第三个参数是是否开启状态继承,默认是true,即后续chart更新将保留之前的状态
当前代码需要的依赖包
"echarts": "^5.3.3","element-ui": "^2.7.2","vue": "^2.5.2","less": "^3.9.0","less-loader": "^4.1.0"
注意:这是vue2的demo!,vue3可自行修改代码
代码如下 github地址:
dragLineMixin.js 这里用mixin的方式,可自行更改为你喜欢的方式
/**
* 纵向缩放chart扩展插件
* @author:yangfeng
* @time: 20220817
* */
/*
注意事项:
1.y轴必须是value类型,使用前提dataZoom需要指定xAxisIndex 和yAxisIndex
2.可以不设置y轴max,min,不设置会取对应系列的最大最小值,若设置了则初始以设置的为准
3.每个y轴都必须有一个唯一dataZoom匹配,因为缩放的是dataZoom
4.保留横向缩放功能
5.因为y轴要缩放用,则x轴会被设置为脱离y轴0刻度
*/
export default {
data() {
return {
yDataZoomTimer: null,// y轴缩放时用于节流
saveInfo: {}, // 存储缩放后的状态信息,针对定时任务的场景
}
},
methods: {
isNull(val) {
return val === null || val === void 0 || val === '' || (val).toString() === 'NaN'
},
// y轴缩放配置 start ----------------
// 清除用于节流缩放的定时器
clearYDataZoomTimer() {
this.yDataZoomTimer && clearTimeout(this.yDataZoomTimer)
},
// 重新给y轴赋值足够大的max,min值【这样初始就可以缩放】,并给对应y轴dataZoom赋值startValue和endValue
setYMaxMin(option) {
if (!option || !option.yAxis) return
if (!Array.isArray(option.yAxis)) { // y轴修改为数组
option.yAxis = [option.yAxis]
}
option.yAxis.map((item, yAxisIndex) => {
let {
max,
min
} = this.getSeriesItemYMaxMin(option, option.series.find(subItem => subItem.yAxisIndex === yAxisIndex)) // 根据数据获取最大最小值
// 没有给y轴设置最大最小值,则使用数据中的极值
let yMax = !this.isNull(item.max) ? item.max : max
let yMin = !this.isNull(item.min) ? item.min : min
// console.log(item, max, min,)
// console.log('xxx', yMax, yMin)
// 修改当前y轴对应的dataZoom startValue和endValue
let findZoom = option.dataZoom.find(subItem => subItem.yAxisIndex === yAxisIndex)
if (findZoom) { // 有对应的dataZoom
delete findZoom.start
delete findZoom.end
let seriesItem = option.series.find(subItem => subItem.yAxisIndex === yAxisIndex)
findZoom.startValue = yMin
findZoom.endValue = yMax
findZoom.id = `yZoom-${yAxisIndex}-${seriesItem.name}` // seriesItem,给对应dataZoom赋值id
this.$set(findZoom, 'disabled', true) // 给option的dataZoom设置此属性,重要!!
// 重新设置最大最小值, 放大缩小最大最小值,这样初始就可以拖动了 - 解决初始没法拖动的问题
let rang = Math.abs(yMax - yMin)
item.max = yMax + rang * 10000 // 这里设置一万倍
item.min = yMin - rang * 10000
}
})
// 让x轴脱离y轴0刻度
if (Array.isArray(option.xAxis)) {
option.xAxis.map(item => {
!item.axisLine && (item.axisLine = {})
item.axisLine.onZero = false
})
} else {
!option.xAxis.axisLine && (option.xAxis.axisLine = {})
option.xAxis.axisLine.onZero = false
}
},
/**
* 获取当前系列的y值最大最小值
* @option: chart 的optin配置
* @seriesItem:需要找极值的series项
* @return {max,min}
* */
getSeriesItemYMaxMin(option, seriesItem) {
let yDATA = [] // 取出对应series的y值
seriesItem.data.map(item => { // 取出
if (this.isNull(item)) return
if (Array.isArray(item)) { // 数组取第二项
yDATA.push(item[1])
} else if (typeof item === 'object') { // 针对echarts 的data数据类型进行取值
yDATA.push(item.value)
} else { // 数值类型
yDATA.push(item)
}
})
// 取出对应series的y值最大最小值
return {
max: Math.max(...yDATA),
min: Math.min(...yDATA)
}
},
// 关闭缩放并取消高亮
closeZoomHighLight(option) {
option.dataZoom.map(item => {
if (item.type !== 'slider') { // slider的保持缩放,
item.disabled = true
}
})
// 取消高亮
// myChart.dispatchAction({
// type: 'downplay',
// seriesIndex: option.series.map((item, index) => index)
// });
// console.log(option, 111)
// 设置透明度来达到高亮效果
option.series.map(item => {
!item.lineStyle && (item.lineStyle = {})
item.lineStyle.opacity = 1
!item.itemStyle && (item.itemStyle = {})
item.itemStyle.opacity = 1
})
},
/**
* 高亮缩放指定seriesIndex的项,只有高亮的系列或者slider类型的才能缩放
* */
openZoomHighLight(option, seriesIndex) {
let yAxisIndex = option.series[seriesIndex].yAxisIndex
let findItem = option.dataZoom.find(item => item.yAxisIndex === yAxisIndex)
findItem.disabled = false
// myChart.dispatchAction({
// type: 'highlight',
// seriesIndex: seriesIndex
// });
// 设置透明度来达到高亮效果
option.series.map(item => {
!item.lineStyle && (item.lineStyle = {})
item.lineStyle.opacity = 0.3
!item.itemStyle && (item.itemStyle = {})
item.itemStyle.opacity = 0.3
})
option.series[seriesIndex].lineStyle.opacity = 1
option.series[seriesIndex].itemStyle.opacity = 1
// console.log(option.series)
},
/**
* 点击到系列上,高亮此系列
* @option
* @seriesIndex:需要高亮系列的索引
* */
highLightSeries(option, seriesIndex) {
if (seriesIndex !== null && seriesIndex > -1) {
this.closeZoomHighLight(option) // 关闭所有缩放
this.openZoomHighLight(option, seriesIndex) // 开启缩放并选中
}
},
/**
* 取消高亮系列
* */
closeHighLightSeries(option) {
this.closeZoomHighLight(option) // 关闭所有缩放
// 开启x轴缩放 - 没有指定yAxisIndex的,认定为x轴
option.dataZoom.map(item => {
if (this.isNull(item.yAxisIndex)) {
item.disabled = false
}
})
},
/**
* 开启y轴缩放功能
* @option:该echarts的option
* @chartInstance: echart 渲染的实例,用于绑定事件
* @keepAlive: Boolean 是否继承上次的缩放状态,针对定时刷新图表情况,能保留之前x,y缩放、高亮、legend选中状态
* Object:若是对象类型,该对象将会和之前存储的saveInfo对象合并【针对某些不需要完全继承上次状态的场景,在改组件外部修改了状态信息,需要以修改的为准】
* */
initYZoom(option, chartInstance, keepAlive = true) {
if (!chartInstance) {
console.error('echarts 实例不存在, 开启y轴缩放失败')
return
}
// option属性赋值
this.setYMaxMin(option) // 重新给y轴赋值max,min值
// 给x轴对应的系列赋值id
option.dataZoom.map((item, index) => {
if (!item.id) {
item.id = `${item.xAxisIndex}-${item.type}-${index}-zoom`
}
})
// console.log(option, 6666)
if (keepAlive) { // 继承上次缩放状态
this.extendZoomInfo(option, chartInstance, keepAlive)
} else {
this.saveInfo = {} // 清空
}
// 利用getZr方法获取点击事件,点击开启缩放
chartInstance.getZr().on('click', (params) => {
// console.log(params, 222)
let target = params.target
if (target) { // 点击线条,开启缩放
let seriesIndex = target.seriesIndex || null // 【注意:echarts 版本不一样这里可能不一样】
if (!seriesIndex) {
Object.keys(target).map(key => {
if (~key.indexOf('__ec_inner_')) {
'seriesIndex' in target[key] && (seriesIndex = target[key].seriesIndex)
}
})
}
this.highLightSeries(option, seriesIndex)
} else { // 未点击线条,闭关缩放功能并取消高亮
this.closeHighLightSeries(option)
}
this.$emit('dataYZoom', params, this.saveZoomInfo(option)) // 将缩放后的上下限抛出,方便父组件使用
});
// 因为在取消缩放后 echarts并没有保存缩放值,而且还需要对超出显示范围的缩放进行处理。因此这里需要dataZoom方法
chartInstance.on('dataZoom', (params) => {
// console.log(params, 'dataZoom')
let dataZoomId; // 缩放的dataZoom id
let start; // 当前缩放开始百分比
let end; // 当前缩放结束百分比
if (params.batch) { // 【注意:echarts 版本不一样这里可能不一样】
let data = params.batch[0]
dataZoomId = data.dataZoomId // 当前缩放的dataZoom
start = data.start
end = data.end
} else {
dataZoomId = params.dataZoomId
start = params.start
end = params.end
}
// 对x轴缩放时,存储start end
if (dataZoomId && !dataZoomId.startsWith('yZoom-')) {
this.setXDataZoom(option, chartInstance, {id: dataZoomId, start, end}) // 存储x轴缩放信息
}
// 换算为比例
start = start / 100
end = end / 100
this.clearYDataZoomTimer() // 清除定时器
// 对某条线进行缩放时,将对应y轴dataZoom的startValue和endValue重新赋值【因为更改了y轴min和max,直接返回的start 和end是百分比,不能直接使用】
if (dataZoomId && dataZoomId.startsWith('yZoom-')) { // 是y轴缩放的逻辑
// 根据y轴的最大最小值将当前缩放的start end 换算为startValue和endValue
let currentDataZoom = option.dataZoom.find(item => item.id === dataZoomId)
if (!currentDataZoom) return
// 对应的y轴
let yAxisIndex = currentDataZoom.yAxisIndex
let {max, min} = option.yAxis[yAxisIndex] // 这里的最大最小值是放大了区间后的值
let rang = Math.abs(max - min)
let startValue = min + rang * start // 注意都是min开始的,因为start、end是占比
let endValue = min + rang * end // 注意都是min开始的,因为start、end是占比
// 处理边界条件,缩放时保证所有数据都在可视区域内
let seriesItem = option.series[yAxisIndex] // 获取对应的series项
let {max: yMax, min: yMin} = this.getSeriesItemYMaxMin(option, seriesItem)
// console.log('y值', `${yMin}-${yMax}`,`${startValue}-${endValue}`)
// 超出范围处理,保证缩放后的数据都在可视范围内
let dispatchZoom = false // 是否调用dispatchAction
if (yMax > endValue) {
endValue = yMax
dispatchZoom = true
}
if (yMin < startValue) {
startValue = yMin
dispatchZoom = true
}
// console.log(currentDataZoom.startValue,'-',currentDataZoom.endValue)
// 保存当前缩放值
currentDataZoom.startValue = startValue
currentDataZoom.endValue = endValue
if (dispatchZoom) { // 只有在超出界限的时候才需要调用这个,如果不限定每次都调用这个将会出现卡顿
this.yDataZoomTimer = setTimeout(() => { // 节流,防止数据量太大的卡顿
let dataZoomIndex = option.dataZoom.findIndex(item => item.id === dataZoomId)
chartInstance.dispatchAction({
type: 'dataZoom',
dataZoomIndex,
// 开始位置的数值
startValue: startValue,
// 结束位置的数值
endValue: endValue
})
})
}
// console.log(startValue,'-', endValue, dataZoomIndex, option.dataZoom[dataZoomIndex])
this.$emit('dataYZoom', params, this.saveZoomInfo(option)) // 将缩放后的上下限抛出,方便父组件使用
}
// })
})
// legend 选择
chartInstance.on('legendselectchanged', (params) => {
// console.log(params.selected, 555)
this.saveZoomInfo(option, {
legendSelected: params.selected // 记录legend的选中状态
})
})
// y轴缩放加载完成事件
this.$emit('dataYZoomFinished', this.saveZoomInfo(option))
},
/**
* 获取y轴可缩放的对应系列当前上下限
* @option: chart的option 配置
* @return [{seriesName:系列名,upper:上限,lower:下限}]
* */
getSeriesUpperLower(option) {
let arr = option.dataZoom.filter(item => item.id && item.id.startsWith('yZoom-'))
let resArr = arr.map(item => {
let IdInfo = item.id.split('-')
return {
seriesName: IdInfo[2],
upper: item.endValue, // 上限
lower: item.startValue, // 下限
}
})
return resArr
},
// 获取当前高亮的系列
getHighLightSeriesName(option) {
let filterArr = option.series.filter(item => item.lineStyle && item.lineStyle.opacity === 1)
// console.log(option,filterArr, 'nnn')
if (filterArr.length > 1) { // 多个则说明没有选择
return ''
} else if (filterArr.length === 1) {
return filterArr[0].name
} else {
return ''
}
},
/**
* 缩放时存储x轴的缩放信息
* */
setXDataZoom(option, chartInstance, {id, start, end}) {
let findItem = option.dataZoom.find(item => item.id === id)
let xAxisIndex = findItem.xAxisIndex || 0 // xAxisIndex可能为数组
// 将缩放相同x轴的dataZoom,缩放设置为当前值
option.dataZoom.map((item, index) => {
if (Array.isArray(xAxisIndex) || Array.isArray(item.xAxisIndex)) { // 是数组
if (JSON.stringify(item.xAxisIndex) === JSON.stringify(xAxisIndex)) {
item.start = start
item.end = end
}
} else if (item.xAxisIndex === xAxisIndex) {
item.start = start
item.end = end
// chartInstance.dispatchAction({
// type: 'dataZoom',
// index,
// // 开始位置的数值
// start,
// // 结束位置的数值
// end
// })
}
})
// console.log(option, 'xxxxxxxx')
this.saveZoomInfo(option)
},
/**
* 存储必要的缩放的信息,若有定时任务让图形可继承上次状态
* @option: 当前chart option
* @obj:其他信息
* */
saveZoomInfo(option, obj) {
// console.log(option, 222)
// x轴对应的dataZoom的缩放信息
let xDataZoomInfo = []
option.dataZoom.map(item => {
if (!item.id.startsWith('yZoom-')) {
xDataZoomInfo.push({
id: item.id,
start: item.start,
end: item.end
})
}
})
let info = {
seriesInfo: this.getSeriesUpperLower(option), // 每个系列的上下限
xDataZoomInfo, // x轴对应的dataZoom的缩放信息
highLightSeriesName: this.getHighLightSeriesName(option) // 当前高亮的seriesName
}
this.saveInfo = {
...this.saveInfo,
...info,
...obj
}
// console.log(info, 7777)
return this.saveInfo
},
// 继承之前的缩放状态 start ----------
extendZoomInfo(option, chartInstance, obj) {
// 传递了对象的以对象为准
if (obj && typeof obj === 'object' && Object.keys(obj).length) {
this.saveInfo = {
...this.saveInfo,
...obj
}
}
if (!this.saveInfo || !Object.keys(this.saveInfo).length) return
let oldInfo = this.saveInfo
// console.log(this.saveInfo, 333)
// 保持高亮状态
let seriesName = oldInfo.highLightSeriesName
if (seriesName) {
let seriesIndex = option.series.findIndex(item => item.name === seriesName)
this.highLightSeries(option, seriesIndex)
}
// 保持y轴缩放
let seriesInfo = oldInfo.seriesInfo
if (seriesInfo && seriesInfo.length) {
option.dataZoom.map(item => {
if (item.id && item.id.startsWith('yZoom-')) {
let IdInfo = item.id.split('-')
let findInfo = seriesInfo.find(sub => sub.seriesName === IdInfo[2])
if (findInfo) { // 更新为上次的上下限
item.endValue = findInfo.upper
item.startValue = findInfo.lower
}
}
})
}
// 保持x轴缩放
let xDataZoomInfo = oldInfo.xDataZoomInfo
if (xDataZoomInfo && xDataZoomInfo.length) {
option.dataZoom.map(item => {
if (!item.id.startsWith('yZoom-')) {
let findInfo = xDataZoomInfo.find(sub => sub.id === item.id)
if (findInfo) {
item.start = findInfo.start
item.end = findInfo.end
}
}
})
}
// 继承之前legend的选中状态
let legendSelected = oldInfo.legendSelected // 格式如[true,false,xxx]
if (option.legend && legendSelected && Object.keys(legendSelected).length) {
option.legend.selected = legendSelected
}
}
// 继承之前的缩放状态 end ----------
// y轴缩放配置 end ----------------
},
beforeDestroy() {
this.clearYDataZoomTimer() // 清除定时器
}
}
dragLineChart.vue
<!--
可拖拽组件
-->
<template>
<div class="chart-base">
<div style="width:100%;height:100%;" :id="id" ref="chartRef"></div>
<div v-if="isChartNull(option)" class="noData">暂无数据</div>
</div>
</template>
<script>
import * as echarts from 'echarts'
import dragLineMixin from './dragLineMixin'
export default {
name: 'dragLineChart',
mixins: [dragLineMixin],
data() {
return {
myChart: '',
}
},
props: {
id: {
type: String,
default: 'ChartBox'
},
option: {
type: Object,
default() {
return {}
}
}
},
mounted() {
// this.myChart = this.$echarts.init(this.$refs.chartRef)
this.myChart = echarts.init(this.$refs.chartRef)
this.drawLine()
// this.initEvent() // event
},
methods: {
isChartNull(chartOption) {
let bool = true
if (chartOption && chartOption.series) {
if (Object.prototype.toString.call(chartOption.series) === '[object Array]') {
chartOption.series.map(item => {
if (item.data && item.data.length) bool = false
})
} else {
chartOption.series.data && chartOption.series.data.length && (bool = false)
}
}
return bool
},
initEvents() {
this.myChart.on('dataZoom', (params) => {
this.$emit('dataZoom', params)
})
},
drawLine() { // 绘制图表
this.myChart.clear()
this.myChart.setOption(this.option)
this.initEvents()
},
resetChartData() { // 刷新数据
this.myChart.setOption(this.option, true)
},
/* showLoading() { // 显示加载动画
this.myChart.showLoading()
},
hideLoading() { // 关闭加载动画
this.myChart.hideLoading()
} */
},
watch: {
option: {
deep: true,
handler: function (value) {
this.resetChartData()
}
}
},
beforeDestroy() {
this.myChart && this.myChart.dispose()
}
}
</script>
<style scoped>
.chart-base {
position: relative;
width: 100%;
height: 100%;
text-align: initial;
}
.noData {
width: 200px;
height: 100px;
line-height: 100px;
position: absolute;
left: 50%;
top: 50%;
margin-left: -100px;
margin-top: -50px;
font-size: 28px;
}
</style>
index.vue 这个是调用的例子,模拟了数据
<template>
<div>
<div class="wrap">
<!--路径图2-->
<div class="com-box">
<h1>可拖拽缩放的方式配置上下限
<el-button type="primary" @click="openTimerTick(true)" v-if="!timer">开启定时任务</el-button>
<el-button type="primary" @click="openTimerTick(false)" v-else>关闭定时任务</el-button>
</h1>
<div class="flex-box">
<div class="info">
<div>
右侧趋势图上下限为:<br/>
<template v-for="(item,index) in chartInfoArr">
<div :style="{color: item.color}">{{ item.seriesName }}<br/>
<div class="input-box">
<span>下限:</span>
<el-input v-model="item.lower" type="number" :disabled="!!timer" placeholder="下限" :style="{color: item.color}" @change="changeUpLow"/>
<span>上限:</span>
<el-input v-model="item.upper" type="number" :disabled="!!timer" placeholder="上限" :style="{color: item.color}" @change="changeUpLow"/>
</div>
</div>
</template>
</div>
<hr/>
</div>
<div class="line-chart" style="height: 700px;">
<drag-line-chart :option="chartOption"
@dataYZoom="chartDataZoom"
@dataYZoomFinished="(val)=>chartDataZoom(null,val)"
ref="dragLineChart"/>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import dragLineChart from './common/dragLineChart'
export default {
name: 'eharts',
components: {
dragLineChart,
},
data() {
return {
chartOption: {},
chartData: [], // 记录chart原始数据
chartDataMaxMin: { // 记录图表数据的上下限,格式{lineSeriesName:{max:xx,min:xx}}
},
chartInfoArr: [], // 显示右侧图表的上下限并可编辑
timer: null
}
},
methods: {
// 范围内随机数
rand(m, n) {
return Math.ceil(Math.random() * (n-m) + m)
},
// 重新刷新chart
changeUpLow() {
let option = this.chartOption
// console.log(option, 111)
this.chartInfoArr.map(item => {
this.chartDataMaxMin[item.seriesName] = { // 记录当前上下限
max: +item.upper,
min: +item.lower
}
})
this.renderChart(this.chartData) // 修改上下限后重新渲染chart
},
// 显示上下限具体信息
chartDataZoom(params, ulInfoArr) {
// console.log(ulInfoArr, 3333)
let {color} = this.getOption()
let chartInfoArr = []
ulInfoArr.seriesInfo.map(({seriesName, upper, lower}) => {
this.chartDataMaxMin[seriesName] = { // 记录当前上下限
max: upper,
min: lower
}
let colorIndex = this.chartOption.series.findIndex(subItem => subItem.name === seriesName)
chartInfoArr.push({
color: color[colorIndex],
seriesName,
upper: (upper).toFixed(2),
lower: (lower).toFixed(2)
})
})
this.chartInfoArr = chartInfoArr
},
getOption() {
let option = {
tooltip: {
trigger: 'axis'
},
legend: {},
grid: [{
show: false,
left: '3%',
right: '4%',
bottom: 380,
top: 50,
containLabel: false
},{
show: false,
left: '3%',
right: '4%',
bottom: 80,
top: 400,
containLabel: false
}],
xAxis: [{
// scale:true,
type: 'category',
boundaryGap: false,
splitLine: {show: false},
gridIndex:0,
},{
// scale:true,
type: 'category',
boundaryGap: false,
splitLine: {show: false},
gridIndex:1,
}],
yAxis: [],
series: []
};
return {
option,
color: [
'#fab83e',
'#e733a3',
'#7482f2',
'#51bcff',
'#47d5e4',
]
}
},
renderChart(resData) {
this.chartData = resData // 记录原始数据
// console.log(resData, 11)
// option赋值
let {option, color} = this.getOption()
let yAxis = [] // y轴
let dataZoom = [ // 缩放设置
{
type: 'inside',
id: 'x-inside-zoom0',
xAxisIndex: [0]
},
{
type: 'slider',
id: 'x-slider-zoom0',
xAxisIndex: [0],
top: 350,
height:20,
},
{
type: 'inside',
id: 'x-inside-zoom1',
xAxisIndex: [1]
},
{
type: 'slider',
id: 'x-slider-zoom1',
xAxisIndex: [1],
bottom:30,
height:20
}
]
resData.map((item, index) => {
let {data, name} = item
let maxMin = this.chartDataMaxMin[name]
let showLine = false
let gridIndex = index < 2 ? 0 : 1 // 前面两条线放上面,后面的放下面
yAxis.push({
type: 'value',
max: maxMin.max, // 上下浮动
min: maxMin.min,
axisLine: {show: showLine},
axisTick: {show: showLine},
axisLabel: {show: showLine},
splitLine: {show: showLine},
gridIndex: gridIndex,
})
option.series.push({
name: name,
type: 'line',
triggerLineEvent: true,
yAxisIndex: index,
xAxisIndex:gridIndex,
data: data,
symbol: 'none',
lineStyle: {
color: color[index]
},
itemStyle: {
color: color[index]
},
// animation:false
})
dataZoom.push({
type: 'inside',
// disabled: true,
yAxisIndex: index,
})
})
option.yAxis = yAxis
option.dataZoom = dataZoom
// console.log(option, 5555)
this.chartOption = option
// 以外部设置线的上下限为准,不使用内部的y方向上下限,两种方式
// 方式一:通过设置keepAlive.seriesInfo为对象的方式覆盖原有状态,这样y轴的max和min可以不指定
// this.$refs['dragLineChart'].initYZoom(this.chartOption, this.$refs['dragLineChart'].myChart, {
// // 以当前上下限为准,y轴上下限交由外部控制,不传则完全交由内部控制
// seriesInfo: Object.keys(this.chartDataMaxMin).map(seriesName => {
// return {
// seriesName,
// lower: +this.chartDataMaxMin[seriesName].min,
// upper: +this.chartDataMaxMin[seriesName].max
// }
// })
// })
// 方式二:通过设置keepAlive.seriesInfo为false的方式,这样内部将以y轴的max,min作为上下限,因为这里手动维护了chartDataMaxMin
this.$refs['dragLineChart'].initYZoom(this.chartOption, this.$refs['dragLineChart'].myChart, {seriesInfo:false})
},
getChartData() {
// 构造测试数据
let resData = []
for (let j = 0; j <= 4; j++) {
resData.push({
name: `line${j + 1}`,
data: []
})
}
for (let i = 1; i < 300; i++) {
resData[0].data.push([i, this.rand(30, 100)])
resData[1].data.push([i, this.rand(-30, -3)])
resData[2].data.push([i, this.rand(5000, 6000)])
resData[3].data.push([i, this.rand(0, 10)])
resData[4].data.push([i, this.rand(800, 900)])
}
// 构造初始数据的上下限
resData.map(item => {
let dataY = item.data.map(item => item[1])
let max = Math.max(...dataY)
let min = Math.min(...dataY)
let jc = Math.abs(max - min)
this.chartDataMaxMin[item.name] = {
max: max + 0.1 * jc, // 上下浮动
min: min - 0.1 * jc,
}
})
this.renderChart(resData)
},
// 定时任务相关 start --------------------
// 清除定时器
clearTimerTick() {
this.timer && clearTimeout(this.timer)
this.timer = null
},
// 开启定时任务,模拟定时刷新数据的情况,
openTimerTick(bool) {
if (bool) {
this.timer = setTimeout(() => {
// 构造测试数据
let resData = this.chartData
let x = resData[0].data[resData[0].data.length - 1][0] + 1
// 末尾追加一项
resData[0].data.push([x, this.rand(30, 100)])
resData[1].data.push([x, this.rand(-30, -3)])
resData[2].data.push([x, this.rand(5000, 6000)])
resData[3].data.push([x, this.rand(0, 10)])
resData[4].data.push([x, this.rand(800, 900)])
// 删除首项
resData.map(item => {
item.data = item.data.slice(1)
})
this.renderChart(resData)
this.openTimerTick(true)
}, 1000)
} else {
this.clearTimerTick()
}
},
// 定时任务相关 end --------------------
},
mounted() {
this.getChartData()
},
beforeDestroy() {
this.clearTimerTick()
}
}
</script>
<style scoped lang="less">
.wrap {
background: #f8f8f8;
overflow: hidden;
display: flex;
justify-content: space-around;
/*flex-direction: ;*/
flex-wrap: wrap;
align-items: center;
}
.line-chart {
width: 100%;
height: 330px;
flex: auto;
}
.com-box {
margin: 60px;
width: 100%;
background: rgba(255, 255, 255, 1);
box-shadow: -.02rem .07rem .15rem 1px rgba(203, 204, 204, 0.18);
border-radius: .03rem;
/*margin: 20px auto;*/
box-sizing: border-box;
padding: 15px 60px;
/deep/ .el-input__inner{
height: 35px;
line-height: 35px;
}
}
.info {
font-size: 20px;
text-align: left;
width: 1000px;
margin-right: 10px;
line-height: 40px;
border: 1px solid #cccccc;
box-sizing: border-box;
padding: 5px;
}
.flex-box {
display: flex;
justify-content: space-between;
align-content: flex-start;
margin-top: 10px;
}
.input-box {
display: flex;
justify-content: space-between;
align-content: center;
margin-bottom: 5px;
> span {
align-self: center;
flex: none;
width: 50px;
margin-right: 5px;
}
}
.content-info{
text-align: left;
line-height: 30px;
font-size: 16px;
>div{
padding: 10px;
}
}
</style>
组件使用注意事项:
1.每条线也就是每个series对应一个y轴,每个y轴对应一个dataZoom【纵向缩放原理其实就是借用的echarts 的dataZoom功能实现的】
2.在取得chart 实例后,最后调用initYZoom方法开启纵向缩放功能,内部需要chart 实例绑定事件,如click, 缩放,legend点击
3.这里组件通过mixin的方式嵌入到基础chart中【也可以单独抽离成js文件引入,但是需要在合适的地方将内部用于节流的定时器清除,vue 的$set也要修改,然后自己找准时机将chart更新】
4.组件支持使用多个x轴,保留缩放功能,但在高亮时禁用内部x轴缩放
可参考下面这个最基础配置帮助理解上面的代码,功能都是在这上面衍生出来的
option = {
xAxis: [
{
type: 'category',
gridIndex: 0,
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
{
type: 'category',
gridIndex: 1,
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
}
],
grid: [
{
show: false,
left: '3%',
right: '4%',
bottom: 380,
top: 50,
containLabel: false
},
{
show: false,
left: '3%',
right: '4%',
bottom: 80,
top: 400,
containLabel: false
}
],
yAxis: [
{
type: 'value',
gridIndex: 0
},
{
type: 'value',
gridIndex: 1
}
],
dataZoom: [
// x轴缩放
{
type: 'inside',
top: 500,
xAxisIndex: 0
},
{
type: 'slider',
top: 350,
xAxisIndex: 0
},
{
type: 'inside',
xAxisIndex: 1
},
{
type: 'slider',
xAxisIndex: 1
},
// y轴缩放
{
type: 'inside',
yAxisIndex: 0
},
{
type: 'inside',
yAxisIndex: 1
},
],
series: [
{
data: [150, 230, 224, 218, 135, 147, 260],
type: 'line',
xAxisIndex: 0,
yAxisIndex: 0
},
{
data: [150, 230, 224, 218, 135, 147, 260],
type: 'line',
xAxisIndex: 1,
yAxisIndex: 1
}
]
};
image.png
最后
若对你有帮助,请点个赞吧,若能打赏不胜感激,谢谢支持!
本文地址:https://www.jianshu.com/p/755db59cf4e4?v=1682584623209,转载请注明出处,谢谢。