From 73e0b3791990bd60c06c2c0388aae9f9faf538a6 Mon Sep 17 00:00:00 2001
From: zxl <763096477@qq.com>
Date: 星期三, 25 三月 2026 09:16:50 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/show-demo' into show_demo

---
 src/views/dataAnalysis/components/DataReLineChart.vue |  202 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 202 insertions(+), 0 deletions(-)

diff --git a/src/views/dataAnalysis/components/DataReLineChart.vue b/src/views/dataAnalysis/components/DataReLineChart.vue
index 782f712..857fd8d 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'
@@ -216,6 +409,7 @@
         ],
       }
       option && this.chartEntity.setOption(option, true)
+      this.bindChartClick()
     },
     setPieUpChart() {
       if (!this.chartEntity) {
@@ -241,6 +435,8 @@
       var option = {
         tooltip: {
           trigger: 'axis',
+          confine: true,
+          extraCssText: 'pointer-events:none;',
           axisPointer: {
             // 鍧愭爣杞存寚绀哄櫒锛屽潗鏍囪酱瑙﹀彂鏈夋晥
             type: 'line', // 榛樿涓虹洿绾匡紝鍙�変负锛�'line' | 'shadow'
@@ -299,6 +495,7 @@
         series: [...data],
       }
       option && this.chartEntity.setOption(option, true)
+      this.bindChartClick()
     },
     setOnlyLineChart() {
       if (!this.chartEntity) {
@@ -309,6 +506,8 @@
       var option = {
         tooltip: {
           trigger: 'axis',
+          confine: true,
+          extraCssText: 'pointer-events:none;',
           axisPointer: {
             // 鍧愭爣杞存寚绀哄櫒锛屽潗鏍囪酱瑙﹀彂鏈夋晥
             type: 'line', // 榛樿涓虹洿绾匡紝鍙�変负锛�'line' | 'shadow'
@@ -442,6 +641,7 @@
         ],
       }
       option && this.chartEntity.setOption(option, true)
+      this.bindChartClick()
     },
   },
 }
@@ -449,5 +649,7 @@
 <style lang="less" scoped>
 .line-chart {
   height: 20vh;
+  position: relative;
+  overflow: hidden;
 }
 </style>

--
Gitblit v1.8.0