From 27c7661cae945f65f8d2752cae41801e3c2b1485 Mon Sep 17 00:00:00 2001
From: zxl <763096477@qq.com>
Date: 星期三, 25 三月 2026 14:21:37 +0800
Subject: [PATCH] 修改折线图
---
src/views/dataAnalysis/components/DataReLineChart.vue | 403 ++++++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 309 insertions(+), 94 deletions(-)
diff --git a/src/views/dataAnalysis/components/DataReLineChart.vue b/src/views/dataAnalysis/components/DataReLineChart.vue
index 764b5d8..228831b 100644
--- a/src/views/dataAnalysis/components/DataReLineChart.vue
+++ b/src/views/dataAnalysis/components/DataReLineChart.vue
@@ -22,13 +22,204 @@
type: Boolean,
default: false,
},
+ enablePointClick: {
+ type: Boolean,
+ default: false,
+ },
},
data() {
return {
chartEntity: null,
+ zrClickHandler: null,
+ zrMoveHandler: null,
+ zrMouseOutHandler: null,
+ lastHoverIndex: -1,
+ lastEmitName: '',
+ lastEmitAt: 0,
+ lastLegendToggleAt: 0,
}
},
methods: {
+ getOffsetPoint(event) {
+ if (!event) {
+ return null
+ }
+ if (event.offsetX !== undefined && event.offsetY !== undefined) {
+ return [event.offsetX, event.offsetY]
+ }
+ if (event.event && event.event.offsetX !== undefined && event.event.offsetY !== undefined) {
+ return [event.event.offsetX, event.event.offsetY]
+ }
+ return null
+ },
+ isPointInGrid(point) {
+ if (!this.chartEntity || !this.chartEntity.containPixel || !point) {
+ return false
+ }
+ return this.chartEntity.containPixel({ gridIndex: 0 }, point)
+ },
+ getXData() {
+ return this.chartData && this.chartData.xData ? this.chartData.xData : []
+ },
+ resolveNearestIndexByOffsetX(offsetX) {
+ let xData = this.getXData()
+ if (!this.chartEntity || !this.chartEntity.convertToPixel || !xData.length) {
+ return -1
+ }
+ let nearestIndex = -1
+ let minDistance = Number.MAX_VALUE
+ for (let i = 0; i < xData.length; i++) {
+ let xPixel = this.chartEntity.convertToPixel({ xAxisIndex: 0 }, xData[i])
+ if (Array.isArray(xPixel)) {
+ xPixel = xPixel[0]
+ }
+ if (xPixel === undefined || xPixel === null || Number.isNaN(Number(xPixel))) {
+ continue
+ }
+ let distance = Math.abs(Number(offsetX) - Number(xPixel))
+ if (distance < minDistance) {
+ minDistance = distance
+ nearestIndex = i
+ }
+ }
+ if (nearestIndex === -1) {
+ return -1
+ }
+ return nearestIndex
+ },
+ resolveClickIndex(event, params) {
+ let xData = this.getXData()
+ if (!xData.length) {
+ return -1
+ }
+ let point = this.getOffsetPoint(event)
+ if (!this.isPointInGrid(point)) {
+ return -1
+ }
+ if (params && typeof params.dataIndex === 'number' && xData[params.dataIndex] !== undefined) {
+ return params.dataIndex
+ }
+ if (params && params.name) {
+ let nameIndex = xData.findIndex((item) => item === params.name)
+ if (nameIndex > -1) {
+ return nameIndex
+ }
+ }
+ if (this.chartEntity && this.chartEntity.convertFromPixel && event) {
+ let xAxisValue = this.chartEntity.convertFromPixel({ xAxisIndex: 0 }, [event.offsetX, event.offsetY])
+ if (xAxisValue !== undefined && xAxisValue !== null && !Number.isNaN(Number(xAxisValue))) {
+ let xIndex = Math.round(Number(xAxisValue))
+ if (xIndex >= 0 && xIndex < xData.length) {
+ return xIndex
+ }
+ }
+ }
+ if (event && event.offsetX !== undefined && event.offsetX !== null) {
+ return this.resolveNearestIndexByOffsetX(event.offsetX)
+ }
+ return -1
+ },
+ emitChartClickByIndex(index, seriesName) {
+ let xData = this.getXData()
+ if (index < 0 || index >= xData.length) {
+ return
+ }
+ let clickName = xData[index]
+ let now = Date.now()
+ if (this.lastEmitName === clickName && now - this.lastEmitAt < 120) {
+ return
+ }
+ this.lastEmitName = clickName
+ this.lastEmitAt = now
+ this.$emit('chart-click', {
+ name: clickName,
+ seriesName: seriesName || null,
+ })
+ },
+ hideTooltip() {
+ if (!this.chartEntity) {
+ return
+ }
+ this.chartEntity.dispatchAction({
+ type: 'hideTip',
+ })
+ },
+ bindChartClick() {
+ if (!this.chartEntity) {
+ return
+ }
+ this.chartEntity.off('click')
+ if (this.chartEntity.getZr) {
+ let zr = this.chartEntity.getZr()
+ if (this.zrClickHandler) {
+ zr.off('click', this.zrClickHandler)
+ }
+ if (this.zrMoveHandler) {
+ zr.off('mousemove', this.zrMoveHandler)
+ }
+ if (this.zrMouseOutHandler) {
+ zr.off('globalout', this.zrMouseOutHandler)
+ }
+ }
+ if (!this.enablePointClick) {
+ let chartDom = document.getElementById(this.domId)
+ if (chartDom) {
+ chartDom.style.cursor = 'default'
+ }
+ return
+ }
+ let chartDom = document.getElementById(this.domId)
+ if (chartDom) {
+ chartDom.style.cursor = 'pointer'
+ }
+ this.chartEntity.on('legendselectchanged', () => {
+ this.lastLegendToggleAt = Date.now()
+ })
+ this.chartEntity.on('click', (params) => {
+ if (params && params.componentType === 'legend') {
+ return
+ }
+ if (Date.now() - this.lastLegendToggleAt < 180) {
+ return
+ }
+ let index = this.resolveClickIndex(params && params.event ? params.event : null, params)
+ this.emitChartClickByIndex(index, params ? params.seriesName : null)
+ })
+ this.zrMoveHandler = (event) => {
+ let xData = this.getXData()
+ if (!xData.length) {
+ return
+ }
+ let xIndex = this.resolveClickIndex(event, null)
+ if (xIndex < 0 || xIndex >= xData.length) {
+ return
+ }
+ if (this.lastHoverIndex === xIndex) {
+ return
+ }
+ this.lastHoverIndex = xIndex
+ this.chartEntity.dispatchAction({
+ type: 'showTip',
+ seriesIndex: 0,
+ dataIndex: xIndex,
+ })
+ }
+ this.zrMouseOutHandler = () => {
+ this.lastHoverIndex = -1
+ this.hideTooltip()
+ }
+ this.zrClickHandler = (event) => {
+ if (Date.now() - this.lastLegendToggleAt < 180) {
+ return
+ }
+ let index = this.resolveClickIndex(event, null)
+ this.emitChartClickByIndex(index, null)
+ }
+ let zr = this.chartEntity.getZr()
+ zr.on('mousemove', this.zrMoveHandler)
+ zr.on('globalout', this.zrMouseOutHandler)
+ zr.on('click', this.zrClickHandler)
+ },
setChart() {
if (!this.chartEntity) {
let chartDom = document.getElementById(this.domId)
@@ -38,6 +229,8 @@
var option = {
tooltip: {
trigger: 'axis',
+ confine: true,
+ extraCssText: 'pointer-events:none;',
axisPointer: {
// 鍧愭爣杞存寚绀哄櫒锛屽潗鏍囪酱瑙﹀彂鏈夋晥
type: 'line', // 榛樿涓虹洿绾匡紝鍙�変负锛�'line' | 'shadow'
@@ -54,15 +247,29 @@
shadowBlur: 10,
formatter: (params) => {
let strName1 = params[0].name
- let value1 = params[0].value
- let value2 = params[1] ? params[1].value : '鏈紑鍚�'
- return `<div style="color:#fff;font-size:16px;">${strName1}</div>
- <div><span style="color:#fff;display: inline-block;width: 86px;">${
- this.chartData.barName
- }</span><span style="color:#5DB6FB">${value1}
- </span></div><div><span style="color:#fff;display: inline-block;width: 86px;">${
- this.chartData.lineName
- }</span><span style="color:#5DB6FB">${value2}${this.showpercent ? '%' : ''}`
+ let result = `<div style="color:#fff;font-size:16px;">${strName1}</div>`
+
+ if (params[0] && this.chartData.barName) {
+ let value1 = params[0].value !== undefined ? params[0].value : 0
+ result += `<div><span style="color:#fff;display: inline-block;width: 86px;">${this.chartData.barName}</span><span style="color:#5DB6FB">${value1}</span></div>`
+ }
+
+ if (params[1] && this.chartData.lineName) {
+ let value2 = params[1].value !== undefined ? params[1].value : 0
+ result += `<div><span style="color:#fff;display: inline-block;width: 86px;">${this.chartData.lineName}</span><span style="color:#5DB6FB">${value2}</span></div>`
+ }
+
+ if (params[2] && this.chartData.barName2) {
+ let value3 = params[2].value !== undefined ? params[2].value : 0
+ result += `<div><span style="color:#fff;display: inline-block;width: 86px;">${this.chartData.barName2}</span><span style="color:#FF6B6B">${value3}</span></div>`
+ }
+
+ if (params[3] && this.chartData.lineName2) {
+ let value4 = params[3].value !== undefined ? params[3].value : 0
+ result += `<div><span style="color:#fff;display: inline-block;width: 86px;">${this.chartData.lineName2}</span><span style="color:#FFD93D">${value4}</span></div>`
+ }
+
+ return result
},
textStyle: {
rich: {
@@ -119,95 +326,95 @@
show: false,
},
},
- {
- type: 'value',
- nameTextStyle: {
- color: 'rgba(185, 185, 185, 1)',
- },
- position: 'right',
- axisLine: {
- show: false,
- },
- splitLine: {
- show: false,
- },
- axisTick: {
- show: false,
- },
- axisLabel: {
- show: true,
- formatter: '{value} %', //鍙充晶Y杞存枃瀛楁樉绀�
- formatter: (value, index) => {
- return value + (this.showpercent ? '%' : '')
- },
- textStyle: {
- color: 'rgba(185, 185, 185, 1)',
- },
- },
- },
],
- series: [
- {
- name: this.chartData.barName,
- type: 'bar',
- barWidth: '12px',
- itemStyle: {
- normal: {
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
- {
- offset: 0,
- color: '#5B81F9',
- },
- {
- offset: 1,
- color: '#151A22',
- },
- ]),
- },
- },
- data: this.chartData.barData,
- },
-
- {
- name: this.chartData.lineName,
- type: 'line',
- // smooth: true,
- yAxisIndex: 1, //浣跨敤鐨� y 杞寸殑 index锛屽湪鍗曚釜鍥捐〃瀹炰緥涓瓨鍦ㄥ涓� y杞寸殑鏃跺�欐湁鐢�
-
- symbol: 'emptycircle', //鏍囪鐨勫浘褰负瀹炲績鍦�
- symbolSize: 0, //鏍囪鐨勫ぇ灏�
- areaStyle: {
- normal: {
- color: {
- type: 'linear',
- x: 0,
- y: 0,
- x2: 0,
- y2: 1,
- colorStops: [
- {
- offset: 0,
- color: 'rgba(87, 147, 67, .5)', // 0% 澶勭殑棰滆壊
- },
- {
- offset: 1,
- color: 'rgba(87, 147, 67, 0.1)', // 100% 澶勭殑棰滆壊
- },
- ],
- global: false, // 缂虹渷涓� false
- },
- },
- },
- itemStyle: {
- color: 'rgba(65, 197, 95, 1)',
- },
-
- data: this.chartData.lineData,
- },
- ],
+ series: [],
}
+
+ if (this.chartData.barData) {
+ option.series.push({
+ name: this.chartData.barName,
+ type: 'bar',
+ barWidth: '12px',
+ itemStyle: {
+ normal: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ {
+ offset: 0,
+ color: '#5B81F9',
+ },
+ {
+ offset: 1,
+ color: '#151A22',
+ },
+ ]),
+ },
+ },
+ data: this.chartData.barData,
+ })
+ }
+
+ if (this.chartData.lineData) {
+ option.series.push({
+ name: this.chartData.lineName,
+ type: 'line',
+ smooth: true,
+ symbol: 'circle',
+ symbolSize: 6,
+ lineStyle: {
+ width: 2,
+ color: '#16B777',
+ },
+ itemStyle: {
+ color: '#16B777',
+ },
+ data: this.chartData.lineData,
+ })
+ }
+
+ if (this.chartData.barData2) {
+ option.series.push({
+ name: this.chartData.barName2,
+ type: 'bar',
+ barWidth: '12px',
+ itemStyle: {
+ normal: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ {
+ offset: 0,
+ color: '#FF6B6B',
+ },
+ {
+ offset: 1,
+ color: '#8B0000',
+ },
+ ]),
+ },
+ },
+ data: this.chartData.barData2,
+ })
+ }
+
+ if (this.chartData.lineData2) {
+ option.series.push({
+ name: this.chartData.lineName2,
+ type: 'line',
+ smooth: true,
+ symbol: 'circle',
+ symbolSize: 6,
+ lineStyle: {
+ width: 2,
+ color: '#FFD93D',
+ },
+ itemStyle: {
+ color: '#FFD93D',
+ },
+ data: this.chartData.lineData2,
+ })
+ }
+
option && this.chartEntity.setOption(option, true)
+ this.bindChartClick()
},
setPieUpChart() {
if (!this.chartEntity) {
@@ -233,6 +440,8 @@
var option = {
tooltip: {
trigger: 'axis',
+ confine: true,
+ extraCssText: 'pointer-events:none;',
axisPointer: {
// 鍧愭爣杞存寚绀哄櫒锛屽潗鏍囪酱瑙﹀彂鏈夋晥
type: 'line', // 榛樿涓虹洿绾匡紝鍙�変负锛�'line' | 'shadow'
@@ -291,6 +500,7 @@
series: [...data],
}
option && this.chartEntity.setOption(option, true)
+ this.bindChartClick()
},
setOnlyLineChart() {
if (!this.chartEntity) {
@@ -301,6 +511,8 @@
var option = {
tooltip: {
trigger: 'axis',
+ confine: true,
+ extraCssText: 'pointer-events:none;',
axisPointer: {
// 鍧愭爣杞存寚绀哄櫒锛屽潗鏍囪酱瑙﹀彂鏈夋晥
type: 'line', // 榛樿涓虹洿绾匡紝鍙�変负锛�'line' | 'shadow'
@@ -434,6 +646,7 @@
],
}
option && this.chartEntity.setOption(option, true)
+ this.bindChartClick()
},
},
}
@@ -441,5 +654,7 @@
<style lang="less" scoped>
.line-chart {
height: 20vh;
+ position: relative;
+ overflow: hidden;
}
</style>
--
Gitblit v1.8.0