summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzhangyu <[email protected]>2023-11-06 17:40:23 +0800
committerzhangyu <[email protected]>2023-11-06 17:40:23 +0800
commit0b39d9b124fbb8d50a8f48fede084638f4de6374 (patch)
treec47045dcd3634995be1fddca16895917bda4d893
parent6ccd322fe3f3b3789fe01407d48011901d4fc0d6 (diff)
NEZ-3211 feat: 处理tooltip的显示 以及 右Y轴
-rw-r--r--nezha-fronted/src/assets/css/common.scss27
-rw-r--r--nezha-fronted/src/components/chart/chart/legend.vue21
-rw-r--r--nezha-fronted/src/components/chart/chart/uplot/chartTimeSeries.vue40
-rw-r--r--nezha-fronted/src/components/chart/chart/uplot/chartTimeSeriesMixin.js275
4 files changed, 281 insertions, 82 deletions
diff --git a/nezha-fronted/src/assets/css/common.scss b/nezha-fronted/src/assets/css/common.scss
index 7856ea690..8e60399da 100644
--- a/nezha-fronted/src/assets/css/common.scss
+++ b/nezha-fronted/src/assets/css/common.scss
@@ -440,7 +440,7 @@ td .nz-icon-gear:before {
.chart-bar,
.chart-gauge,
.chart-sankey,
-.chart-time-series,
+.chart-time-series-tooltip,
.chart-treemap,
.chart-pie,
.chart-bubble,
@@ -456,7 +456,7 @@ td .nz-icon-gear:before {
color: $--color-text-regular !important;
box-shadow: none !important;
}
-.chart-time-series,
+.chart-time-series-tooltip,
.chart-pie,
.chart-bar,
.chart-treemap,
@@ -464,7 +464,26 @@ td .nz-icon-gear:before {
visibility: hidden;
position: absolute;
}
-
+.chart-time-series-tooltip {
+ position: absolute;
+ display: block;
+ border-style: solid;
+ white-space: nowrap;
+ 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;
+ background-color: rgb(255, 255, 255);
+ border-width: 1px;
+ border-radius: 4px;
+ color: rgb(102, 102, 102);
+ font: 14px / 21px "Microsoft YaHei";
+ padding: 10px;
+ top: 0px;
+ left: 0px;
+ border-color: rgb(255, 255, 255);
+ z-index: 99999999;
+ visibility: visible;
+ pointer-events: none;
+}
.yAxis-icon{
margin-right: 4px;
background: transparent !important;
@@ -543,7 +562,7 @@ i.nz-icon-override{
outline: none;
}
}
-.chart-time-series.hide{
+.chart-time-series-tooltip.hide{
display: none !important;
}
.alert-rule-info-two{
diff --git a/nezha-fronted/src/components/chart/chart/legend.vue b/nezha-fronted/src/components/chart/chart/legend.vue
index 719ab46d7..2540f1176 100644
--- a/nezha-fronted/src/components/chart/chart/legend.vue
+++ b/nezha-fronted/src/components/chart/chart/legend.vue
@@ -247,26 +247,15 @@ export default {
if (this.isGrey[index]) {
return false
}
- return
if (this.chartInfo.type === 'pie' || this.chartInfo.type === 'doughnut' || this.chartInfo.type === 'rose') {
this.$emit('hoverLegendD3', legendName, index, type)
} else if (this.isTimeSeries) {
- if (type == 'highlight' && getChart(this.chartId)) {
- const option = getChart(this.chartId).getOption()
- const series = this.$lodash.cloneDeep(option.series)
- series[index].emphasis.focus = 'series'
- getChart(this.chartId).setOption({ series })
- } else if (getChart(this.chartId)) {
- const option = getChart(this.chartId).getOption()
- const series = this.$lodash.cloneDeep(option.series)
- series[index].emphasis.focus = 'none'
- getChart(this.chartId).setOption({ series })
+ const echarts = getChart(this.chartId)
+ if (type == 'highlight') {
+ echarts.setSeries(index + 1, {focus:true})
+ } else {
+ echarts.setSeries(null, {focus: true})
}
- getChart(this.chartId) && getChart(this.chartId).dispatchAction({
- type: type,
- seriesIndex: index,
- name: legendName
- })
} else {
getChart(this.chartId) && getChart(this.chartId).dispatchAction({
type: type,
diff --git a/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeries.vue b/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeries.vue
index 744993a55..940ad3763 100644
--- a/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeries.vue
+++ b/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeries.vue
@@ -200,7 +200,7 @@ export default {
}
})
],
- padding: [15, 15, 15, 15],
+ padding: [15, this.autoPadRight, 15, 15],
legend: {
show: false
},
@@ -214,11 +214,11 @@ export default {
{
scale: 'left',
values: (u, vals, space) => vals.map(v => leftUnitCompute.compute(v, null, -1, decimals)),
- formatValue: (v, d) => {
- console.log(v, d, 'vd')
- return v
- },
incrs: incrs,
+ // space: (self) => {
+ // console.log(self)
+ // return 50
+ // },
size (self, values, axisIdx, cycleNum) {
const axis = self.axes[axisIdx]
@@ -243,34 +243,14 @@ export default {
{
show: true,
side: 1,
- grid: { show: false, width: 0 },
+ grid: { show: false },
scale: 'right',
+ // space: (self) => {
+ // console.log(self)
+ // return 50
+ // },
values: (u, vals, space) => vals.map(v => rightUnitCompute.compute(v, null, -1, decimals)),
- formatValue: (v, d) => {
- console.log(v, d, 'vd')
- return v
- },
incrs: rightIncrs
- // size (self, values, axisIdx, cycleNum) {
- // const axis = self.axes[axisIdx]
- //
- // // bail out, force convergence
- // if (cycleNum > 1) { return axis._size }
- //
- // let axisSize = axis.ticks.size + axis.gap
- //
- // // find longest value
- // const longestVal = (values ?? []).reduce((acc, val) => (
- // val.length > acc.length ? val : acc
- // ), '')
- //
- // if (longestVal != '') {
- // self.ctx.font = axis.font[0]
- // axisSize += self.ctx.measureText(longestVal).width / devicePixelRatio
- // }
- //
- // return Math.ceil(axisSize)
- // }
}
]
}
diff --git a/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeriesMixin.js b/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeriesMixin.js
index bb58b0658..86a460957 100644
--- a/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeriesMixin.js
+++ b/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeriesMixin.js
@@ -2,8 +2,9 @@ import { initColor, Incrs } from '@/components/chart/chart/tools'
import { randomcolor } from '@/components/common/js/radomcolor/randomcolor'
import chartDataFormat from '@/components/chart/chartDataFormat'
import lodash from 'lodash'
-import { getMetricTypeValue } from '@/components/common/js/tools'
+import { formatScientificNotation, getMetricTypeValue } from '@/components/common/js/tools'
import uPlot from 'uplot'
+import bus from '@/libs/bus'
export default {
data () {
return {
@@ -75,9 +76,12 @@ export default {
const elementNames = this.$lodash.get(this.chartInfo, 'param.rightYAxis.elementNames', [])
isRight = elementNames.indexOf(series.elements.name) !== -1
}
+ const name = legend.name
+ const alias = legend.alias
+ const statistics = series.statistics
const obj = {
- name: series.elements.name + JSON.stringify(series.metric),
- label: series.elements.name + JSON.stringify(series.metric),
+ name: name,
+ label: alias,
class: series.elements.name + JSON.stringify(series.metric),
scale: isRight ? 'right' : 'left', // right
yAxisIndex: isRight ? 1 : 0, // right
@@ -85,9 +89,6 @@ export default {
stroke: this.seriesColor[chartIndex],
width: 1 / devicePixelRatio
}
- const name = legend.name
- const alias = legend.alias
- const statistics = series.statistics
this.legends.push({ name, alias, statistics, color: this.seriesColor[chartIndex] })
return obj
},
@@ -96,17 +97,11 @@ export default {
let tooltipTopOffset = 0
const self = this
const tooltip = document.createElement('div')
- tooltip.className = 'u-tooltip'
-
let seriesIdx = null
let dataIdx = null
-
- const fmtDate = uPlot.fmtDate('{M}/{D}/{YY} {h}:{mm}:{ss} {AA}')
-
let over
-
let tooltipVisible = false
-
+ let isRender = false
function showTooltip () {
if (!tooltipVisible) {
tooltip.style.display = 'block'
@@ -123,23 +118,240 @@ export default {
}
}
- function setTooltip (u) {
+ function setTooltip (u) { // 生成tooltip内容
showTooltip()
-
- const top = u.valToPos(u.data[seriesIdx][dataIdx], 'y')
+ if (!self.$lodash.get(self.chartInfo, 'param.enable.tooltip', false)) {
+ return
+ }
+ isRender = false
+ console.log(self.chartInfo, seriesIdx, dataIdx, u)
+ const { left, top } = u.cursor
const lft = u.valToPos(u.data[0][dataIdx], 'x')
-
tooltip.style.top = (tooltipTopOffset + top + shiftX) + 'px'
tooltip.style.left = (tooltipLeftOffset + lft + shiftY) + 'px'
+ let params = []
+ const tooltipModel = self.$lodash.get(self.chartInfo, 'param.tooltip.mode', 'single')
+ console.log(tooltipModel)
+ if (self.chartInfo.param && !(tooltipModel == 'single')) {
+ params = self.series.map((s, i) => {
+ return {
+ seriesIndex: i,
+ yAxisIndex: s.yAxisIndex,
+ value: [u.data[0][dataIdx], u.data[i + 1][dataIdx]],
+ seriesName: s.label
+ }
+ })
+ params = params.filter(item => {
+ console.log(item.value[1], typeof (item.value[1]) == 'undefined')
+ const flag = typeof (item.value[1]) == 'undefined'
+ return !flag
+ })
+ } else if (seriesIdx) {
+ const obj = self.series[seriesIdx - 1]
+ params = [{
+ seriesIndex: seriesIdx - 1,
+ yAxisIndex: obj.yAxisIndex,
+ value: [u.data[0][dataIdx], u.data[seriesIdx][dataIdx]],
+ seriesName: obj.label
+ }]
+ }
+ isRender = !!params.length
+ console.log(isRender, 'isRender')
+ if (!isRender) {
+ tooltip.style.display = 'none'
+ over.style.cursor = null
+ return
+ } else {
+ tooltip.style.display = 'block'
+ over.style.cursor = 'pointer'
+ }
+ tooltip.className = 'chart-time-series-tooltip'
+ let str = '<div class="nz-tooltip nz-chart__tooltip">'
+ const hasTotal = self.isStack
+ const decimals = self.chartInfo.param.decimals || 2
+ // 区分左y轴右y轴
+ params.forEach(item => {
+ if (self.series[item.seriesIndex]) {
+ item.yAxisIndex = self.series[item.seriesIndex].yAxisIndex
+ }
+ })
+ // 排序先展示左y轴
+ params.sort((a, b) => a.yAxisIndex - b.yAxisIndex)
+ // 分割
+ const rightYAxisIndex = params.findIndex(item => item.yAxisIndex == 1)
+ let leftYAxis = []
+ let rightYAxis = []
+ if (rightYAxisIndex != -1) {
+ leftYAxis = params.slice(0, rightYAxisIndex)
+ rightYAxis = params.slice(rightYAxisIndex)
+ } else {
+ leftYAxis = params
+ }
+ handler(leftYAxis, 'left')
+ handler(rightYAxis, 'right')
+ function handler (arr, type) {
+ console.log(arr, type)
+ if (!arr.length) {
+ return
+ }
- tooltip.style.borderColor = self.seriesColor[seriesIdx - 1]
- const pctSinceStart = (((u.data[seriesIdx][dataIdx] - u.data[seriesIdx][0]) / u.data[seriesIdx][0]) * 100).toFixed(2)
- tooltip.textContent = (
- fmtDate(new Date(u.data[0][dataIdx] * 1e3)) + ' - ' + '\n' +
- uPlot.fmtNum(u.data[seriesIdx][dataIdx]) + ' (' + pctSinceStart + '% since start)'
- )
- }
+ // tooltip排序
+ let sortBy
+ if (self.$lodash.get(self.chartInfo, 'param.enable.tooltip') && self.$lodash.get(self.chartInfo, 'param.tooltip.mode') !== 'single' && self.$lodash.get(self.chartInfo, 'param.tooltip.sort') !== 'none') {
+ sortBy = self.$lodash.get(self.chartInfo, 'param.tooltip.sort')
+ }
+ const previousIndex = arr.findIndex(item => item.seriesName.indexOf('Previous') !== -1)
+ if (previousIndex != -1) { // 对比状态
+ const arrNow = arr.slice(0, previousIndex)
+ const arrPrevious = arr.slice(previousIndex)
+ if (sortBy === 'asc') {
+ arrNow.sort((a, b) => a.value[1] - b.value[1])
+ arrPrevious.sort((a, b) => a.value[1] - b.value[1])
+ } else if (sortBy === 'desc') {
+ arrNow.sort((a, b) => b.value[1] - a.value[1])
+ arrPrevious.sort((a, b) => b.value[1] - a.value[1])
+ }
+ arr = [...arrNow, ...arrPrevious]
+ } else {
+ if (sortBy === 'asc') {
+ arr.sort((a, b) => a.value[1] - b.value[1])
+ } else if (sortBy === 'desc') {
+ arr.sort((a, b) => b.value[1] - a.value[1])
+ }
+ }
+
+ let sum = 0
+ let flag = true
+ arr.forEach((item, i) => {
+ let unit = self.chartInfo.unit ? self.chartInfo.unit : 2
+ if (type == 'right') {
+ unit = lodash.get(self, 'chartInfo.param.rightYAxis.unit', 2)
+ }
+ const nameArr = item.seriesName.split('-')
+ // if (nameArr.length > 1) {
+ // nameArr.splice(nameArr.length - 1, 1)
+ // }
+ const seriesName = nameArr.join('-')
+ if (i === 0 && item.seriesName.indexOf('Previous') === -1 && type == 'left') {
+ const value = bus.computeTimezone(item.value[0] * 1000)
+ const tData = new Date(value)
+ str += '<div class="tooltip-title" style="margin-bottom: 5px">'
+ str += bus.timeFormate(tData)
+ str += '</div>'
+ }
+ // 两条y轴数据分割线
+ if (i == 0 && rightYAxisIndex != 0 && type == 'right') {
+ str += '<div style="border: 1px solid #EEEEEE;margin-top: 5px;margin-bottom: 5px"></div>'
+ }
+ if (item.seriesName.indexOf('Previous') === -1 && type == 'right') {
+ if (i == 0 && (rightYAxisIndex == 0 || (arr.some(item => item.seriesName.indexOf('Previous') !== -1)))) {
+ const value = bus.computeTimezone(item.value[0] * 1000)
+ const tData = new Date(value)
+ str += '<div class="tooltip-title" style="margin-bottom: 5px">'
+ str += bus.timeFormate(tData)
+ str += '</div>'
+ }
+ }
+ // Previous分割线
+ if (i !== 0 && flag && item.seriesName.indexOf('Previous') !== -1) {
+ str += '<div style="border: 1px solid #EEEEEE;margin-top: 5px;margin-bottom: 5px"></div>'
+ }
+ if (flag && item.seriesName.indexOf('Previous') !== -1) {
+ flag = false
+ const value = bus.computeTimezone(item.value[0] * 1000 - self.minusTime)
+ const tData = new Date(value)
+ str += '<div class="tooltip-title" style="margin-bottom: 5px">'
+ str += bus.timeFormate(tData)
+ str += '</div>'
+ }
+ const color = self.colorList[item.seriesIndex]
+ const previousItem = arr.find((series) => ('Previous ' + item.seriesName) === series.seriesName)
+ let paramsDot = bus.countDecimals(item.value[1])
+ if (paramsDot < decimals) {
+ paramsDot = decimals
+ } else if (paramsDot > 6) {
+ paramsDot = 6
+ }
+ const val = formatScientificNotation(item.value[1], paramsDot)
+ sum += isNaN(self.numberWithEConvent(val)) ? 0 : parseFloat(self.numberWithEConvent(val))
+ let previousDom = ''
+ if (previousItem) {
+ const previousVal = formatScientificNotation(previousItem.value[1], paramsDot)
+ let minusVal = 0
+ let operator
+ if (previousVal <= val) {
+ minusVal = val - previousVal
+ operator = '+'
+ } else {
+ minusVal = previousVal - val
+ operator = '-'
+ }
+ previousDom = `
+ <span>${operator}${chartDataFormat.getUnit(unit).compute(minusVal, null, -1, decimals)}</span>
+ `
+ }
+
+ // 根据左右轴设置图标
+ let className = 'row__color-block'
+ if (item.yAxisIndex == 0) {
+ className = 'yAxis-icon nz-icon nz-icon-zuozongzhou'
+ } else if (item.yAxisIndex == 1) {
+ className = 'yAxis-icon nz-icon nz-icon-youzongzhou'
+ }
+ // 鼠标悬浮 series data symbol 时,tooltip 中相应的legend 高亮显示
+ str += `
+ <div class="${(seriesIdx - 1 == item.seriesIndex) ? 'tooltip__row highlight' : 'tooltip__row'}" title="${seriesName}">
+ <div class="row__label">
+ <span class="${className}" style="background-color: ${color};color: ${color}"></span>
+ <span>${seriesName}</span>
+ </div>
+ <div class="row__value">
+ <span>${chartDataFormat.getUnit(unit).compute(val, null, -1, decimals)}</span>
+ ${previousDom}
+ </div>
+ </div>
+ `
+ })
+ // 显示total
+ if (hasTotal) {
+ sum = parseFloat(Number(sum).toFixed(2))
+ let unit = self.chartInfo.unit ? self.chartInfo.unit : 2
+ let className = 'row__color-block'
+ let color = ''
+ if (type == 'left') {
+ // 判断是否开启rightYAxis 否则显示普通图标
+ if (self.series.some(item => item.yAxisIndex == 0)) {
+ className = 'yAxis-icon nz-icon nz-icon-zuozongzhou'
+ }
+ if (!self.stackTotalColor) {
+ self.stackTotalColor = randomcolor()
+ }
+ color = self.stackTotalColor
+ } else {
+ unit = lodash.get(self, 'chartInfo.param.rightYAxis.unit', 2)
+ className = 'yAxis-icon nz-icon nz-icon-youzongzhou'
+ if (!self.stackTotalColorRight) {
+ self.stackTotalColorRight = randomcolor()
+ }
+ color = self.stackTotalColorRight
+ }
+ str += `
+ <div class="tooltip__row">
+ <div class="row__label" title="${self.$t('dashboard.dashboard.chartTotal')}">
+ <span class="${className}" style="background-color: ${color};color: ${color}"></span>
+ <span>${self.$t('dashboard.dashboard.chartTotal')}</span>
+ </div>
+ <div class="row__value">
+ <span>${chartDataFormat.getUnit(unit).compute(sum, null, -1, decimals)}</span>
+ </div>
+ </div>
+ `
+ }
+ }
+ str += '</div>'
+ tooltip.innerHTML = str
+ }
return {
hooks: {
ready: [
@@ -151,14 +363,16 @@ export default {
let clientX
let clientY
-
+ over.addEventListener('mouseleave', () => {
+ if (!u.cursor._lock) {
+ hideTooltip()
+ }
+ })
over.addEventListener('mousedown', e => {
clientX = e.clientX
clientY = e.clientY
})
-
over.addEventListener('mouseup', e => {
- // clicked in-place
if (e.clientX == clientX && e.clientY == clientY) {
if (seriesIdx != null && dataIdx != null) {
onclick(u, seriesIdx, dataIdx)
@@ -170,11 +384,9 @@ export default {
setCursor: [
u => {
const c = u.cursor
-
if (dataIdx != c.idx) {
dataIdx = c.idx
-
- if (seriesIdx != null) { setTooltip(u) }
+ setTooltip(u)
}
}
],
@@ -182,8 +394,7 @@ export default {
(u, sidx) => {
if (seriesIdx != sidx) {
seriesIdx = sidx
-
- if (sidx == null) { hideTooltip() } else if (dataIdx != null) { setTooltip(u) }
+ if (dataIdx != null) { setTooltip(u) }
}
}
]