diff --git a/nezha-fronted/src/components/chart/chart/chartAutotopology.vue b/nezha-fronted/src/components/chart/chart/chartAutotopology.vue index 210029540..ae4c92033 100644 --- a/nezha-fronted/src/components/chart/chart/chartAutotopology.vue +++ b/nezha-fronted/src/components/chart/chart/chartAutotopology.vue @@ -137,7 +137,7 @@ export default { } }, mounted () { - // this.queryAllProjectData() + this.queryAllProjectData() this.$get('/topology/icon').then(res => { this.iconArray = [...res.data.list] }) diff --git a/nezha-fronted/src/components/chart/chart/chartBubble.vue b/nezha-fronted/src/components/chart/chart/chartBubble.vue index 586d9eabc..a01f08002 100644 --- a/nezha-fronted/src/components/chart/chart/chartBubble.vue +++ b/nezha-fronted/src/components/chart/chart/chartBubble.vue @@ -58,7 +58,8 @@ export default { value: 0, mapping: {}, show: false - } + }, + svg: null } }, methods: { @@ -108,13 +109,14 @@ export default { }, drawBubbleChart () { this.$nextTick(() => { - d3.select(`#bubble-svg-${this.chartId}`).selectAll('g').remove() // 清空作图区域 - const svg = document.getElementById(`bubble-svg-${this.chartId}`) - if (!svg) { + this.dispose() + this.svg = d3.select(`#bubble-svg-${this.chartId}`) + const svgDom = document.getElementById(`bubble-svg-${this.chartId}`) + if (!svgDom) { return false } - const width = svg.getBoundingClientRect().width - const height = svg.getBoundingClientRect().height + const width = svgDom.getBoundingClientRect().width + const height = svgDom.getBoundingClientRect().height // 定义布局方式 const pack = d3.pack() .size([width, height]) @@ -137,7 +139,7 @@ export default { return b.value - a.value }) const nodes = pack(data).descendants() - const bubbles = d3.select(`#bubble-svg-${this.chartId}`).selectAll('.bubble') + const bubbles = this.svg.selectAll('.bubble') .data(nodes) .enter() .filter(function (d) { @@ -236,11 +238,6 @@ export default { ` } }, - resize () { - setTimeout(() => { - this.drawBubbleChart() - }, 50) - }, bubbleEnter (e, node) { // 移入气泡 this.tooltip.title = node.data.alias this.tooltip.value = node.data.showValue @@ -277,6 +274,20 @@ export default { this.tooltip.y = e.pageY + 15 this.tooltip.x = e.pageX + 15 } + }, + resize () { + setTimeout(() => { + this.drawBubbleChart() + }, 50) + }, + dispose () { + if (this.svg) { + this.svg.selectAll('.bubble').on('mouseenter', null) + this.svg.selectAll('.bubble').on('mousemove', null) + this.svg.selectAll('.bubble').on('mouseleave', null) + this.svg.selectAll('g').remove() + this.svg = null + } } }, mounted () { @@ -284,7 +295,7 @@ export default { this.chartInfo.loaded && this.initChart() }, beforeDestroy () { - d3.select(`#bubble-svg-${this.chartId}`).selectAll('g').remove() // 清空作图区域 + this.dispose() } } diff --git a/nezha-fronted/src/components/chart/chart/chartFunnelNew.vue b/nezha-fronted/src/components/chart/chart/chartFunnelNew.vue index 7b63e01ff..1d61f27fa 100644 --- a/nezha-fronted/src/components/chart/chart/chartFunnelNew.vue +++ b/nezha-fronted/src/components/chart/chart/chartFunnelNew.vue @@ -58,7 +58,8 @@ export default { value: 0, mapping: {}, show: false - } + }, + svg: null } }, methods: { @@ -122,7 +123,7 @@ export default { funnelData = funnelData.filter(item => item.value !== 0) } this.$nextTick(() => { - d3.select(`#funnel-svg-${this.chartId}`).selectAll('g').remove() // 清空作图区域 + this.dispose() // 获取svg宽高 初始化画布 const svgDom = document.getElementById(`funnel-svg-${this.chartId}`) if (!svgDom) { @@ -153,8 +154,8 @@ export default { return d } ) - const svg = d3.select(`#funnel-svg-${this.chartId}`) - const chart = svg.append('g').attr('width', chartWidth).attr('height', chartHeight).attr('transform', `translate(${margin}, ${margin})`) + this.svg = d3.select(`#funnel-svg-${this.chartId}`) + const chart = this.svg.append('g').attr('width', chartWidth).attr('height', chartHeight).attr('transform', `translate(${margin}, ${margin})`) // 渲染梯形 const trapezoids = chart @@ -290,11 +291,6 @@ export default { ` } }, - resize () { - setTimeout(() => { - this.drawChart() - }, 50) - }, chartEnter (e, data) { this.tooltip.title = data.alias this.tooltip.value = data.showValue @@ -367,6 +363,23 @@ export default { (Math.round((t - B) * p) + B) return `#${converted.toString(16).slice(1)}` + }, + resize () { + setTimeout(() => { + this.drawChart() + }, 50) + }, + dispose () { + if (this.svg) { + this.svg.selectAll('.trap').on('mouseover', null) + this.svg.selectAll('.trap').on('mousemove', null) + this.svg.selectAll('.trap').on('mouseleave', null) + this.svg.selectAll('foreignObject').on('mouseover', null) + this.svg.selectAll('foreignObject').on('mousemove', null) + this.svg.selectAll('foreignObject').on('mouseleave', null) + this.svg.selectAll('g').remove() + this.svg = null + } } }, mounted () { @@ -374,7 +387,7 @@ export default { this.chartInfo.loaded && this.initChart(true) }, beforeDestroy () { - d3.select(`#funnel-svg-${this.chartId}`).selectAll('g').remove() // 清空作图区域 + this.dispose() } } diff --git a/nezha-fronted/src/components/chart/chart/chartHexagonD3.vue b/nezha-fronted/src/components/chart/chart/chartHexagonD3.vue index a9e6b9b97..9bf075285 100644 --- a/nezha-fronted/src/components/chart/chart/chartHexagonD3.vue +++ b/nezha-fronted/src/components/chart/chart/chartHexagonD3.vue @@ -45,7 +45,7 @@ export default { mapping: {}, show: false }, - svgDom: null, + svg: null, spaceBetweenHexa: 3, hexagonTimer: null } @@ -53,21 +53,19 @@ export default { methods: { hexbin, initChart () { - this.clearCache().then(() => { - if (this.timer) { - clearTimeout(this.timer) - this.timer = null - } - this.timer = setTimeout(() => { - this.initHexagonData(this.chartInfo, this.chartData).then(() => { - this.getLayout().then(layout => { - this.initHexagon(layout) - }).catch(() => { + if (this.timer) { + clearTimeout(this.timer) + this.timer = null + } + this.timer = setTimeout(() => { + this.initHexagonData(this.chartInfo, this.chartData).then(() => { + this.getLayout().then(layout => { + this.initHexagon(layout) + }).catch(() => { - }) }) - }, 200) - }) + }) + }, 200) }, initHexagonData (chartInfo, originalDatas) { this.HexagonData = [] @@ -135,7 +133,8 @@ export default { const dom = document.getElementById(`chart-canvas-${this.chartId}`) const child = document.getElementById('svgHex' + this.chartId) if (dom && child) { - dom.removeChild(child) + this.clearCache() + // dom.removeChild(child) } if (dom) { const hexaRadius = layout.radius @@ -164,13 +163,11 @@ export default { const hexbin = this.hexbin() .radius(hexaRadius) .extent([[0, 0], [width, height]]) - - const svg = d3.create('svg') + this.svg = d3.create('svg') .attr('id', 'svgHex' + this.chartId) .attr('width', width) .attr('height', height) .on('mousemove', this.hexagonMove) - this.svgDom = 'svgHex' + this.chartId for (let i = 0; i < data.length; i++) { const point = data[i] const col = point.x @@ -179,15 +176,15 @@ export default { const vals = self.getCenter(hexaRadius, row, col) // Gets the Center coordinates with given row and column const x = vals[0] const y = vals[1] - const g = svg.append('g') + const g = this.svg.append('g') const hexa = self.drawHexagon(g, hexaRadius, spaceBetweenHexa, x, y, hexbin) // Draws hexagon hexa.attr('fill', color) // Paints hexagon g.on('mouseenter', self.hexagonOver.bind(self, point)) g.on('mouseleave', self.hexagonOut.bind(self, point)) - self.drawText(svg, vals, point, color, hexaRadius, g) // 文本 + self.drawText(this.svg, vals, point, color, hexaRadius, g) // 文本 data[i].fcolor = color } - return svg.node() + return this.svg.node() }, hexagonOver (that, e) { // 移入六边形 this.tooltip.title = that.alias @@ -414,13 +411,13 @@ export default { }) }, clearCache () { - return new Promise(resolve => { - // if (this.svgDom) { - // const dom = document.getElementById(this.svgDom) - // dom.off('mousemove', this.hexagonMove) - // } - resolve() - }) + if (this.svg) { + this.svg.on('mousemove', null) + this.svg.selectAll('g').on('mouseenter', null) + this.svg.selectAll('g').on('mouseleave', null) + this.svg.remove() + this.svg = null + } }, resize () { if (this.hexagonTimer) { @@ -436,8 +433,6 @@ export default { }, 50) } }, - created () { - }, mounted () { // eslint-disable-next-line vue/no-mutating-props this.chartOption.color || (this.chartOption.color = initColor(20)) @@ -445,6 +440,14 @@ export default { this.chartInfo.loaded && this.initChart(this.chartOption) }, beforeDestroy () { + if (this.timer) { + clearTimeout(this.timer) + this.timer = null + } + if (this.hexagonTimer) { + clearTimeout(this.hexagonTimer) + this.hexagonTimer = null + } this.clearCache() } } diff --git a/nezha-fronted/src/components/chart/chart/chartRank.vue b/nezha-fronted/src/components/chart/chart/chartRank.vue index 228d30d95..0a15d7e78 100644 --- a/nezha-fronted/src/components/chart/chart/chartRank.vue +++ b/nezha-fronted/src/components/chart/chart/chartRank.vue @@ -64,7 +64,8 @@ export default { mapping: {}, rank: 0, show: false - } + }, + svg: null } }, methods: { @@ -115,7 +116,7 @@ export default { drawRankChart () { this.$nextTick(() => { - d3.select(`#rank-svg-${this.chartId}`).selectAll('g').remove() // 清空作图区域 + this.dispose() // 获取svg宽高 初始化画布 const svgDom = document.getElementById(`rank-svg-${this.chartId}`) if (!svgDom) { @@ -128,7 +129,7 @@ export default { const margin = 40 // 计算svg高度 const height = this.rankData.length * (barHeight + margin) + margin - const svg = d3.select(`#rank-svg-${this.chartId}`).attr('height', height) + this.svg = d3.select(`#rank-svg-${this.chartId}`).attr('height', height) const bodyX = 50 const bodyWidth = width - 3 * bodyX @@ -151,7 +152,7 @@ export default { // 柱子最小宽度 const minWidth = 2 // 渲染柱形 - const bars = svg.append('g') + const bars = this.svg.append('g') .attr('transform', `translate(${bodyX})`) .selectAll() .data(rankData) @@ -174,7 +175,7 @@ export default { bars.exit().remove() // 文本标签 - svg.append('g') + this.svg.append('g') .attr('transform', `translate(${bodyX})`) .selectAll() .data(rankData) @@ -203,7 +204,7 @@ export default { .style('overflow', 'visible') // 生成标签和矩形 - svg.append('g') + this.svg.append('g') .attr('transform', `translate(${bodyX})`) .selectAll('text') .data(rankData) @@ -283,11 +284,22 @@ export default { this.tooltip.x = e.pageX + 15 } }, - resize () { setTimeout(() => { this.drawRankChart() }, 50) + }, + dispose () { + if (this.svg) { + this.svg.selectAll('rect').on('mouseenter', null) + this.svg.selectAll('rect').on('mousemove', null) + this.svg.selectAll('rect').on('mouseleave', null) + this.svg.selectAll('foreignObject').on('mouseenter', null) + this.svg.selectAll('foreignObject').on('mousemove', null) + this.svg.selectAll('foreignObject').on('mouseleave', null) + this.svg.selectAll('g').remove() + this.svg = null + } } }, @@ -296,7 +308,7 @@ export default { this.chartInfo.loaded && this.initChart() }, beforeDestroy () { - d3.select(`#rank-svg-${this.chartId}`).selectAll('g').remove() // 清空作图区域 + this.dispose() } } diff --git a/nezha-fronted/src/components/chart/chart/chartSankey.vue b/nezha-fronted/src/components/chart/chart/chartSankey.vue index 7fbf42b3c..89b587d19 100644 --- a/nezha-fronted/src/components/chart/chart/chartSankey.vue +++ b/nezha-fronted/src/components/chart/chart/chartSankey.vue @@ -59,7 +59,8 @@ export default { value: 0, mapping: {}, show: false - } + }, + svg: null } }, methods: { @@ -136,8 +137,7 @@ export default { drawSankeyChart () { this.$nextTick(() => { - d3.select(`#sankey-svg-${this.chartId}`).selectAll('g').remove() // 清空作图区域 - + this.dispose() // 获取svg宽高 初始化画布 const svgDom = document.getElementById(`sankey-svg-${this.chartId}`) if (!svgDom) { @@ -147,8 +147,8 @@ export default { const height = svgDom.getBoundingClientRect().height const margin1 = 100 const margin2 = 50 - const svg = d3.select(`#sankey-svg-${this.chartId}`) - const chart = svg.append('g').attr('transform', `translate(${margin2}, ${margin2})`) + this.svg = d3.select(`#sankey-svg-${this.chartId}`) + const chart = this.svg.append('g').attr('transform', `translate(${margin2}, ${margin2})`) // 创建桑基图生成器 const sankey = d3Sankey @@ -389,6 +389,18 @@ export default { setTimeout(() => { this.drawSankeyChart() }, 50) + }, + dispose () { + if (this.svg) { + this.svg.selectAll('path').on('mouseover', null) + this.svg.selectAll('path').on('mousemove', null) + this.svg.selectAll('path').on('mouseleave', null) + this.svg.selectAll('.node').on('mouseover', null) + this.svg.selectAll('.node').on('mousemove', null) + this.svg.selectAll('.node').on('mouseleave', null) + this.svg.selectAll('g').remove() + this.svg = null + } } }, mounted () { @@ -396,7 +408,7 @@ export default { this.chartInfo.loaded && this.initChart() }, beforeDestroy () { - d3.select(`#sankey-svg-${this.chartId}`).selectAll('g').remove() // 清空作图区域 + this.dispose() } } diff --git a/nezha-fronted/src/components/chart/chartMixin.js b/nezha-fronted/src/components/chart/chartMixin.js index e1246c0be..200627448 100644 --- a/nezha-fronted/src/components/chart/chartMixin.js +++ b/nezha-fronted/src/components/chart/chartMixin.js @@ -439,18 +439,18 @@ export default { this.initChart(this.chartOption) } } - }, - 'chartInfo.loaded': { - immediate: true, - deep: true, - handler (n) { - if (n) { - this.initChart && this.initChart(this.chartOption) - } - } } + // 'chartInfo.loaded': { + // immediate: true, + // deep: true, + // handler (n) { + // if (n) { + // this.initChart && this.initChart(this.chartOption) + // } + // } + // } }, - mounted () { + created () { this.chartId = `${this.chartInfo.id}${this.isFullscreen ? '-fullscreen' : ''}` }, beforeDestroy () { diff --git a/nezha-fronted/src/components/common/pickTime.vue b/nezha-fronted/src/components/common/pickTime.vue index bc987fc72..e04b53e6d 100644 --- a/nezha-fronted/src/components/common/pickTime.vue +++ b/nezha-fronted/src/components/common/pickTime.vue @@ -163,12 +163,12 @@ export default { clearTimeout(this.timer) this.timer = setTimeout(() => { this.refreshDataFunc() - this.timer = '' + this.timer = null }, 200) } else { this.timer = setTimeout(() => { this.refreshDataFunc() - this.timer = '' + this.timer = null }, 200) } } @@ -181,6 +181,12 @@ export default { } }, beforeDestroy () { + if (this.timer) { + this.timer = setTimeout(() => { + this.refreshDataFunc() + this.timer = null + }, 200) + } if (this.intervalTimer) { clearInterval(this.intervalTimer) this.intervalTimer = null