| | |
| | | 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) |
| | |
| | | var option = { |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | confine: true, |
| | | extraCssText: 'pointer-events:none;', |
| | | axisPointer: { |
| | | // 坐标轴指示器,坐标轴触发有效 |
| | | type: 'line', // 默认为直线,可选为:'line' | 'shadow' |
| | |
| | | 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: { |
| | |
| | | }, |
| | | axisLabel: { |
| | | show: true, |
| | | formatter: '{value} %', //右侧Y轴文字显示 |
| | | formatter: (value, index) => { |
| | | return value + (this.showpercent ? '%' : '') |
| | | }, |
| | | formatter: this.showpercent ? '{value} %' : '{value}', |
| | | 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', |
| | | yAxisIndex: 1, |
| | | 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', |
| | | yAxisIndex: 1, |
| | | 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) { |
| | |
| | | var option = { |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | confine: true, |
| | | extraCssText: 'pointer-events:none;', |
| | | axisPointer: { |
| | | // 坐标轴指示器,坐标轴触发有效 |
| | | type: 'line', // 默认为直线,可选为:'line' | 'shadow' |
| | |
| | | series: [...data], |
| | | } |
| | | option && this.chartEntity.setOption(option, true) |
| | | this.bindChartClick() |
| | | }, |
| | | setOnlyLineChart() { |
| | | if (!this.chartEntity) { |
| | |
| | | var option = { |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | confine: true, |
| | | extraCssText: 'pointer-events:none;', |
| | | axisPointer: { |
| | | // 坐标轴指示器,坐标轴触发有效 |
| | | type: 'line', // 默认为直线,可选为:'line' | 'shadow' |
| | |
| | | ], |
| | | } |
| | | option && this.chartEntity.setOption(option, true) |
| | | this.bindChartClick() |
| | | }, |
| | | }, |
| | | } |
| | |
| | | <style lang="less" scoped> |
| | | .line-chart { |
| | | height: 20vh; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | </style> |