From 48071f0d41aaab168c3921c93d05bbf60888e423 Mon Sep 17 00:00:00 2001 From: zhangyu Date: Wed, 29 Dec 2021 11:50:24 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=20=E6=B7=BB=E5=8A=A0=20hexagon?= =?UTF-8?q?=E7=9A=84tooltip=20=E4=BB=A5=E5=8F=8A=20panel=20=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E9=94=81=E5=AE=9A=E7=8A=B6=E6=80=81=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../assets/css/components/chart/chart.scss | 34 +++++ .../src/components/chart/chart/chartBar.vue | 1 + .../components/chart/chart/chartHexagonD3.vue | 122 +++++++++++++----- .../src/components/chart/chart/chartPie.vue | 1 + .../src/components/page/dashboard/panel.vue | 2 +- 5 files changed, 127 insertions(+), 33 deletions(-) diff --git a/nezha-fronted/src/assets/css/components/chart/chart.scss b/nezha-fronted/src/assets/css/components/chart/chart.scss index 12115be43..66032b543 100644 --- a/nezha-fronted/src/assets/css/components/chart/chart.scss +++ b/nezha-fronted/src/assets/css/components/chart/chart.scss @@ -494,3 +494,37 @@ transition: none } } +.chart-canvas-tooltip{ + position: fixed; + min-width: 150px; + max-width: 600px; + display: block; + border-style: solid; + white-space: nowrap; + will-change: transform; + box-shadow: rgba(0,0,0,0.2) 1px 2px 10px; + transition: opacity 0.2s cubic-bezier(0.23, 1, 0.32, 1) 0s, visibility 0.2s cubic-bezier(0.23, 1, 0.32, 1) 0s, transform 0.4s cubic-bezier(0.23, 1, 0.32, 1) 0s; + border-width: 1px; + border-radius: 4px; + font: 14 px/ 21px "Microsoft YaHei"; + padding: 10px; + z-index: 99999999; + pointer-events: none; + overflow: hidden; + background-color: #dde4ed !important; + border-color: #fff !important; + color: #666665 !important; +} +.chart-canvas-tooltip-title{ + max-width: 500px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-bottom: 5px; + font-size: 14px; +} +.chart-canvas-tooltip-content{ + font-size: 12px; + display: flex; + justify-content: space-between; +} diff --git a/nezha-fronted/src/components/chart/chart/chartBar.vue b/nezha-fronted/src/components/chart/chart/chartBar.vue index 1759a3728..00a2a58e5 100644 --- a/nezha-fronted/src/components/chart/chart/chartBar.vue +++ b/nezha-fronted/src/components/chart/chart/chartBar.vue @@ -108,6 +108,7 @@ export default { } } chartOption.tooltip.formatter = this.formatterFunc + chartOption.tooltip.position = this.tooltipPosition /* 使用setTimeout延迟渲染图表,避免样式错乱 */ setTimeout(() => { const myChart = this.isInit ? echarts.init(document.getElementById(`chart-canvas-${this.chartId}`)) : getChart(this.chartId) diff --git a/nezha-fronted/src/components/chart/chart/chartHexagonD3.vue b/nezha-fronted/src/components/chart/chart/chartHexagonD3.vue index 6fdc0fe35..0b76a3a2c 100644 --- a/nezha-fronted/src/components/chart/chart/chartHexagonD3.vue +++ b/nezha-fronted/src/components/chart/chart/chartHexagonD3.vue @@ -1,6 +1,15 @@ @@ -23,31 +32,39 @@ export default { HexagonData: [], boxWidth: 0, boxHeight: 0, - boxPadding: 5 + boxPadding: 5, + tooltip: { + x: 0, + y: 0, + title: 0, + value: 0, + show: false + }, + svgDom: null } }, methods: { hexbin, initChart () { - if (this.timer) { - clearTimeout(this.timer) - this.timer = null - } - this.timer = setTimeout(() => { - this.initHexagonData(this.chartInfo, this.chartData).then(() => { - this.getLayout().then(layout => { - console.log(layout, this.boxWidth, this.boxHeight) - this.initHexagon(layout) + 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) + }) }) - }) - }, 200) + }, 200) + }) }, initHexagonData (chartInfo, originalDatas) { this.HexagonData = [] this.isInit = false return new Promise(resolve => { let colorIndex = 0 - console.log('init', 1) originalDatas.forEach((originalData, expressionIndex) => { originalData.forEach((data, dataIndex) => { this.isNoData = false @@ -87,7 +104,6 @@ export default { }, initHexagon (layout) { this.isInit = false - console.log(layout, this.HexagonData) let rowIndex = 0 let colIndex = -1 const data = this.HexagonData.map(item => { @@ -121,6 +137,7 @@ export default { } }, showHexagons (data, hexaRadiu = 60, row, col) { + // 清除资源 释放缓存 // Initial Geometrical Calculations const self = this const hexaRadius = hexaRadiu @@ -139,34 +156,63 @@ export default { .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 const row = point.y const color = point.mapping ? point.mapping.color.bac : this.colorList[i] - console.log(color) 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 hexa = self.drawHexagon(svg, hexaRadius, spaceBetweenHexa, x, y, hexbin) // Draws hexagon + const g = svg.append('g') + const hexa = self.drawHexagon(g, hexaRadius, spaceBetweenHexa, x, y, hexbin) // Draws hexagon hexa.attr('fill', color) // Paints hexagon - hexa.on('mouseenter', self.hexagonOver.bind(self, hexa)) - hexa.on('mouseleave', self.hexagonOut.bind(self, hexa)) - self.drawText(svg, vals, point, color, hexaRadius) // 文本 + g.on('mouseenter', self.hexagonOver.bind(self, point)) + g.on('mouseleave', self.hexagonOut.bind(self, point)) + self.drawText(svg, vals, point, color, hexaRadius, g) // 文本 data[i].fcolor = color } return svg.node() }, hexagonOver (that, e) { // 移入六边形 // console.log(that, e) + this.tooltip.title = that.alias + this.tooltip.value = that.showValue + this.tooltip.show = true + this.setPosition(e) }, - hexagonMove (that, e) { // 六边形内移动 - // console.log(that, e) - // this.$emit('assetMove',e) + hexagonMove (e) { // 六边形内移动 + // console.log(e) + if (this.tooltip.show) { + this.setPosition(e) + } }, hexagonOut (that) { - + this.tooltip.show = false + }, + setPosition (e) { + const windowWidth = window.innerWidth// 窗口宽度 + const windowHeight = window.innerHeight// 窗口高度 + const box = document.getElementById(`chart-canvas-tooltip-${this.chartId}`) + if (box) { + const boxWidth = box.offsetWidth + const boxHeight = box.offsetHeight + if (e.pageX < (windowWidth / 2)) { // 说明鼠标在左边放不下提示框 + this.tooltip.x = e.pageX + 15 + } else { + this.tooltip.x = e.pageX - boxWidth - 15 + } + if (e.pageY + 50 + boxHeight < windowHeight) { // 说明鼠标上面放不下提示框 + this.tooltip.y = e.pageY + 15 + } else { + this.tooltip.y = e.pageY - boxHeight - 10 + } + } else { + this.tooltip.y = e.pageY + 15 + this.tooltip.x = e.pageX + 15 + } }, formatStr (d) { const self = this @@ -182,7 +228,7 @@ export default { .attr('transform', 'translate(' + x + ',' + y + ')') return hexagon }, - drawText (svg, vals, point, color, hexbinRadius) { + drawText (svg, vals, point, color, hexbinRadius, group) { let str = '' let valueStr = '' const self = this @@ -202,12 +248,12 @@ export default { str += '' } if (str && valueStr) { - const fObj = svg.append('foreignObject') + const fObj = group.append('foreignObject') .attr('width', hexWidth || 60) - .attr('height', 20) + .attr('height', 24) fObj .attr('x', vals[0] - hexWidth / 2) - .attr('y', vals[1] - 16) + .attr('y', vals[1] - 24) // .text(str) .attr('text-anchor', 'middle') .attr('alignment-baseline', 'central') @@ -216,7 +262,7 @@ export default { const scrollDiv = fObj.append('xhtml:div') scrollDiv .html(`
${str}
`) - svg.append('text') + group.append('text') .attr('x', vals[0]) .attr('y', vals[1] + 16) .text(valueStr) @@ -227,9 +273,9 @@ export default { return } if (str) { - const fObj = svg.append('foreignObject') + const fObj = group.append('foreignObject') .attr('width', hexWidth || 60) - .attr('height', 20) + .attr('height', 24) fObj .attr('x', vals[0] - hexWidth / 2) .attr('y', vals[1] - 10) @@ -244,7 +290,7 @@ export default { return } if (valueStr) { - svg.append('text') + group.append('text') .attr('x', vals[0]) .attr('y', vals[1]) .text(valueStr) @@ -315,6 +361,15 @@ export default { } resolve({ col, row, radius: radius - 2 }) }) + }, + clearCache () { + return new Promise(resolve => { + // if (this.svgDom) { + // const dom = document.getElementById(this.svgDom) + // dom.off('mousemove', this.hexagonMove) + // } + resolve() + }) } }, created () { @@ -327,6 +382,9 @@ export default { this.isStack = this.chartInfo.param.stack } catch (e) {} this.chartInfo.loaded && this.initChart(this.chartOption) + }, + beforeDestroy () { + this.clearCache() } } diff --git a/nezha-fronted/src/components/chart/chart/chartPie.vue b/nezha-fronted/src/components/chart/chart/chartPie.vue index 1dea690ab..2e7e3e442 100644 --- a/nezha-fronted/src/components/chart/chart/chartPie.vue +++ b/nezha-fronted/src/components/chart/chart/chartPie.vue @@ -85,6 +85,7 @@ export default { } // chartOption.series.label.formatter = this.pieFormatterLabel chartOption.tooltip.formatter = this.formatterFunc + chartOption.tooltip.position = this.tooltipPosition /* 使用setTimeout延迟渲染图表,避免样式错乱 */ setTimeout(() => { const myChart = this.isInit ? echarts.init(document.getElementById(`chart-canvas-${this.chartId}`)) : getChart(this.chartId) diff --git a/nezha-fronted/src/components/page/dashboard/panel.vue b/nezha-fronted/src/components/page/dashboard/panel.vue index 83604cec9..3599e90dc 100644 --- a/nezha-fronted/src/components/page/dashboard/panel.vue +++ b/nezha-fronted/src/components/page/dashboard/panel.vue @@ -170,7 +170,7 @@ export default { panelTabLoading: false, overScroll10: false, isLoading: true, - panelLock: false, + panelLock: true, showTopBtn: false, // top按钮 visible: false, chartListLoading: true,