diff --git a/nezha-fronted/src/components/chart/chart/chartBubble.vue b/nezha-fronted/src/components/chart/chart/chartBubble.vue index aba79fc2d..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) { @@ -173,7 +175,10 @@ export default { return d.y - d.r }) .style('font-size', function (d) { - return d.r / 3 > 10 ? d.r / 3 : 0 + let fontSize + fontSize = d.r / 4 > 10 ? d.r / 4 : 0 + fontSize = fontSize > 30 ? 30 : fontSize + return fontSize }) .style('border-radius', '50%') .html((d) => { @@ -233,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 @@ -274,11 +274,28 @@ 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 () { this.colorList = initColor(20) this.chartInfo.loaded && this.initChart() + }, + beforeDestroy () { + this.dispose() } } diff --git a/nezha-fronted/src/components/chart/chart/chartHexagonD3.vue b/nezha-fronted/src/components/chart/chart/chartHexagonD3.vue index 575767708..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,23 +433,22 @@ export default { }, 50) } }, - created () { - }, mounted () { // eslint-disable-next-line vue/no-mutating-props this.chartOption.color || (this.chartOption.color = initColor(20)) this.colorList = this.chartOption.color - try { - this.isStack = this.chartInfo.param.stack - } catch (e) {} 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 e8f9624a3..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,17 +284,31 @@ 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 + } } }, mounted () { this.colorList = initColor(20) this.chartInfo.loaded && this.initChart() + }, + beforeDestroy () { + this.dispose() } } diff --git a/nezha-fronted/src/components/chart/chart/chartSankey.vue b/nezha-fronted/src/components/chart/chart/chartSankey.vue index 857f440ee..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,9 +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) { @@ -148,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 @@ -390,11 +389,26 @@ 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 () { this.colorList = initColor(20) this.chartInfo.loaded && this.initChart() + }, + beforeDestroy () { + this.dispose() } } diff --git a/nezha-fronted/src/components/common/pickTime.vue b/nezha-fronted/src/components/common/pickTime.vue index 5a0b31d46..438eb330c 100644 --- a/nezha-fronted/src/components/common/pickTime.vue +++ b/nezha-fronted/src/components/common/pickTime.vue @@ -152,12 +152,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) } } @@ -170,6 +170,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