接上一篇:echarts 直角坐標系中多個系列多個y軸展示方案
因為最近比較忙,一直沒時間寫這個。之前有小伙伴在評論區留言想要知道這個效果怎么寫的,這里把代碼貼下。
這個點擊上下縮放的效果是之前別的項目上的,在某些特殊功能上還是比較有用的。但因為封裝的功能和我這邊的需求不一致,而且不是很好理解,然后我就參考了下代碼自己寫了一套,有需要的小伙伴可以參考下,主要是思路。
效果圖(簡書這個圖片經常加載不出來,不知道你們是否能看到下面這個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',
xAxisIndex: 0
},
{
type: 'slider',
top: 350,
xAxisIndex: 0
},
// 下
{
type: 'inside',
xAxisIndex: 1
},
{
type: 'slider',
bottom: 10,
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
}
]
};
最后
若對你有幫助,請點個贊吧,若能打賞不勝感激,謝謝支持!
本文地址:http://www.lxweimin.com/p/755db59cf4e4?v=1682584623209,轉載請注明出處,謝謝。