NEZ-3211 feat: 处理tooltip的显示 以及 右Y轴

This commit is contained in:
zhangyu
2023-11-06 17:40:23 +08:00
parent 6ccd322fe3
commit 0b39d9b124
4 changed files with 281 additions and 82 deletions

View File

@@ -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{

View File

@@ -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,

View File

@@ -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)
// }
}
]
}

View File

@@ -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) }
}
}
]