summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nezha-fronted/src/assets/css/common.scss27
-rw-r--r--nezha-fronted/src/assets/css/components/common/project/L5/CanvasProps.scss12
-rw-r--r--nezha-fronted/src/components/chart/chart.vue3
-rw-r--r--nezha-fronted/src/components/chart/chart/chartTable.vue3
-rw-r--r--nezha-fronted/src/components/chart/chart/chartTimeSeries.vue1
-rw-r--r--nezha-fronted/src/components/chart/chart/legend.vue66
-rw-r--r--nezha-fronted/src/components/chart/chart/tools.js8
-rw-r--r--nezha-fronted/src/components/chart/chart/uplot/chartTimeSeries.vue614
-rw-r--r--nezha-fronted/src/components/chart/chart/uplot/chartTimeSeriesMixin.js665
-rw-r--r--nezha-fronted/src/components/chart/chart/uplot/stack.js63
-rw-r--r--nezha-fronted/src/components/chart/chart/uplot/testData.js2
-rw-r--r--nezha-fronted/src/components/chart/chartMixin.js23
-rw-r--r--nezha-fronted/src/components/common/bottomBox/tabs/alertMessageTabNew.vue1
-rw-r--r--nezha-fronted/src/components/common/bottomBox/tabs/dashboardTab.vue4
-rw-r--r--nezha-fronted/src/components/common/mixin/mainMixinFun.js1
-rw-r--r--nezha-fronted/src/components/common/pickTime.vue3
-rw-r--r--nezha-fronted/src/components/common/rightBox/panelBox.vue4
-rw-r--r--nezha-fronted/src/components/common/timePicker.vue1
-rw-r--r--nezha-fronted/src/components/page/alert/alertMessage.vue2
-rw-r--r--nezha-fronted/src/components/page/dashboard/dashboard.vue4
-rw-r--r--nezha-fronted/src/components/page/dashboard/explore/exploreItem.vue2
-rw-r--r--nezha-fronted/src/components/page/dashboard/explore/histoyrComponent/exploreHistory.vue2
-rw-r--r--nezha-fronted/src/components/page/dashboard/explore/queryPrompt/queryPrompt.vue4
-rw-r--r--nezha-fronted/src/entrance/app/main.js1
-rw-r--r--nezha-fronted/src/entrance/exportHtml/exportHtml.js1
25 files changed, 1427 insertions, 90 deletions
diff --git a/nezha-fronted/src/assets/css/common.scss b/nezha-fronted/src/assets/css/common.scss
index 7856ea690..6cc276abf 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: 9998;
+ 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/assets/css/components/common/project/L5/CanvasProps.scss b/nezha-fronted/src/assets/css/components/common/project/L5/CanvasProps.scss
index 01b1bd5f8..4457ad29d 100644
--- a/nezha-fronted/src/assets/css/components/common/project/L5/CanvasProps.scss
+++ b/nezha-fronted/src/assets/css/components/common/project/L5/CanvasProps.scss
@@ -376,6 +376,18 @@
margin-top: 10px;
}
+.ml10{
+ margin-left: 10px;
+}
+
+.mb10{
+ margin-bottom: 10px;
+}
+
+.mr10{
+ margin-right: 10px;
+}
+
.p10 {
padding: 10px;
}
diff --git a/nezha-fronted/src/components/chart/chart.vue b/nezha-fronted/src/components/chart/chart.vue
index 0e8be79b7..0ee25b98c 100644
--- a/nezha-fronted/src/components/chart/chart.vue
+++ b/nezha-fronted/src/components/chart/chart.vue
@@ -280,7 +280,8 @@ import chartRose from './chart/chartRose'
import chartStat from './chart/chartStat'
import chartTable from './chart/chartTable'
import chartText from './chart/chartText'
-import chartTimeSeries from './chart/chartTimeSeries'
+// import chartTimeSeries from './chart/chartTimeSeries'
+import chartTimeSeries from './chart/uplot/chartTimeSeries'
import chartTreemap from './chart/chartTreemap'
import chartUrl from './chart/chartUrl'
import chartHexagonD3 from './chart/chartHexagonD3'
diff --git a/nezha-fronted/src/components/chart/chart/chartTable.vue b/nezha-fronted/src/components/chart/chart/chartTable.vue
index 1269e103e..3954dd08f 100644
--- a/nezha-fronted/src/components/chart/chart/chartTable.vue
+++ b/nezha-fronted/src/components/chart/chart/chartTable.vue
@@ -303,7 +303,6 @@ export default {
oldValue: ''
}
const display = this.globalVariablesReplace(column.display)
- console.log(column, display, /\{\{.+\}\}/.test(display), params)
if (/\{\{.+\}\}/.test(display)) {
const labelValue = display.replace(/(\{\{.+?\}\})/g, function (i) {
const label = i.substr(i.indexOf('{{') + 2, i.indexOf('}}') - i.indexOf('{{') - 2)
@@ -313,7 +312,6 @@ export default {
if (label.indexOf('$value') !== -1) {
value = chartDataFormat.getUnit(column.unit ? column.unit : 2).compute(value, null, -1, 2)
}
- console.log(value)
if (!((typeof value) == 'string' && value.constructor == String) && isNaN(value)) {
let legend = ''
if (value.__name__) {
@@ -363,7 +361,6 @@ export default {
}
return value || ''
})
- console.log(labelValue)
obj[column.title + 'display'] = {
display: labelValue,
oldValue: oldLabelValue
diff --git a/nezha-fronted/src/components/chart/chart/chartTimeSeries.vue b/nezha-fronted/src/components/chart/chart/chartTimeSeries.vue
index e26f64969..1feb8df55 100644
--- a/nezha-fronted/src/components/chart/chart/chartTimeSeries.vue
+++ b/nezha-fronted/src/components/chart/chart/chartTimeSeries.vue
@@ -166,6 +166,7 @@ export default {
methods: {
initChart (chartOptions = this.chartOption) {
this.setDataLink()
+ console.log(JSON.stringify(this.chartData))
try {
this.isStack = this.chartInfo.param.stack
} catch (e) {}
diff --git a/nezha-fronted/src/components/chart/chart/legend.vue b/nezha-fronted/src/components/chart/chart/legend.vue
index 0157b04c6..35957f32c 100644
--- a/nezha-fronted/src/components/chart/chart/legend.vue
+++ b/nezha-fronted/src/components/chart/chart/legend.vue
@@ -157,51 +157,27 @@ export default {
this.clickLegendD3(legendName, index, hasGrey, curIsGrey, currentIsTheOnlyOneHighlight)
return
}
-
if (echarts) {
- // 判断timeSeries类型图表 先取消多表联动
- if (this.isTimeSeries && (this.isConnect && this.isConnect !== 'none')) {
- chart.disconnect('timeSeriesGroup')
- }
if (!hasGrey) { // 1.除当前legend外全置灰
- echarts.dispatchAction({
- type: 'legendInverseSelect'
- })
- echarts.dispatchAction({
- type: 'legendSelect',
- name: legendName
+ echarts.series.forEach((seriesItem, sindex) => {
+ if (sindex > 0) {
+ echarts.setSeries(sindex, { show: false, focus: false })
+ }
})
+ echarts.setSeries(index + 1, { show: true, focus: false })
this.isGrey = this.isGrey.map((g, i) => i !== index)
} else if (currentIsTheOnlyOneHighlight) { // 2.全高亮
- echarts.dispatchAction({
- type: 'legendAllSelect'
+ echarts.series.forEach((seriesItem, sindex) => {
+ if (sindex > 0) {
+ echarts.setSeries(sindex, { show: true, focus: false })
+ }
})
this.isGrey = this.isGrey.map(() => false)
} else {
- const type = curIsGrey ? 'legendSelect' : 'legendUnSelect'
- echarts.dispatchAction({
- type: type,
- name: legendName
- })
+ echarts.setSeries(index + 1, { show: true, focus: false })
this.$set(this.isGrey, index, !this.isGrey[index])
}
- if (this.isTimeSeries) {
- this.$parent.legendChange(this.isGrey)
- }
- // 点击后 处理Y轴的刻度边的
- const chartInfo = this.chartInfo
- const series = this.$lodash.cloneDeep(this.series)
- const dataArg = series.filter((seriesItem, seriesIndex) => !this.isGrey[seriesIndex])
- const option = this.renderYAxis(dataArg, chartInfo, 'legend')
- getChart(this.chartId) && getChart(this.chartId).setOption({
- yAxis: [
- ...option.yAxis
- ]
- })
- // 判断timeSeries类型图表 建立多表联动
- if (this.isTimeSeries && (this.isConnect && this.isConnect !== 'none')) {
- chart.connect('timeSeriesGroup')
- }
+ this.$emit('legendChange', this.isGrey)
}
},
clickLegendBar (legendName, index, hasGrey, curIsGrey, currentIsTheOnlyOneHighlight) {
@@ -274,22 +250,12 @@ export default {
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/tools.js b/nezha-fronted/src/components/chart/chart/tools.js
index 7771bd72e..c642dfece 100644
--- a/nezha-fronted/src/components/chart/chart/tools.js
+++ b/nezha-fronted/src/components/chart/chart/tools.js
@@ -203,3 +203,11 @@ export function initColor (colorNum = 20) {
}
return colorList
}
+export function initIncrs () {
+ const arr = []
+ for (let i = 0; i < 53; i++) {
+ arr.push(Math.pow(2, i))
+ }
+ return arr
+}
+export const Incrs = initIncrs()
diff --git a/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeries.vue b/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeries.vue
new file mode 100644
index 000000000..20efc68e7
--- /dev/null
+++ b/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeries.vue
@@ -0,0 +1,614 @@
+<template>
+ <div
+ :class="legendPlacement"
+ ref="timeSeries-chart-box"
+ class="nz-chart__component nz-chart__component--time-series" @mouseenter="mouseEnterChart"
+ @mouseleave="mouseLeaveChart"
+ v-my-loading="chartLoading"
+ >
+ <div class="chart__canvas" style="position:relative" :class="{'chart-cursor-default':cursorDefault}">
+ <div :id="`chart-canvas-${chartId}`"></div>
+ </div>
+ <chart-legend
+ ref="legend"
+ style="flex-shrink: 0"
+ v-if="hasLegend"
+ :chart-data="chartData"
+ :chart-info="chartInfo"
+ :legends="legends"
+ :series="series"
+ :is-fullscreen="isFullscreen"
+ @legendChange="legendChange"
+ ></chart-legend>
+ <!-- toolbox -->
+ <div :id="`chart-toolbox-${chartId}`" class="chart-canvas-tooltip no-style-class chart-toolbox" :style="{left:toolbox.x+'px',top:toolbox.y+'px'}" v-if="toolbox.show" v-clickoutside="clickout">
+ <div v-html="toolbox.tooltipHtml"></div>
+ <!-- dataLink -->
+ <div class="chart-dataLink-list">
+ <!-- 复制表达式 -->
+ <div class="chart-dataLink-item select-series" v-if="chartInfo.datasource==='metrics'||chartInfo.datasource==='logs'" @click="copyExpr">
+ <i class="nz-icon nz-icon-override"></i>
+ <span v-if="chartInfo.datasource==='metrics'">{{$t('overall.copy')}} PromQL</span>
+ <span v-else>{{$t('overall.copy')}} LogQL</span>
+ </div>
+ <!-- 只有一条数据时显示 -->
+ <div class="chart-dataLink-item select-series" v-if="isGrey.filter(value => value === false).length==1" @click="showAllSeries">
+ <i class="nz-icon nz-icon-a-Showallseries"></i>
+ <span>{{$t('dashboard.showAllSeries')}}</span>
+ </div>
+ <!-- 有多条数据时显示 -->
+ <div class="chart-dataLink-item select-series" v-else @click="showSelectedSeries">
+ <i class="nz-icon nz-icon-a-Showseletedseries"></i>
+ <span>{{$t('dashboard.showSelectedSeries')}}</span>
+ </div>
+ <div class="chart-dataLink-item" v-for="(item,index) in dataLink" :title='item.title' :key="index" @click="linkClick(item)">
+ <i class="nz-icon nz-icon-link"></i>
+ <span>{{item.title}}</span>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import legend from '../legend'
+import chartMixin from '@/components/chart/chartMixin'
+import renderChart from '@/components/chart/renderChart'
+import { chartLegendPlacement } from '@/components/common/js/constants'
+import { getChart, setChart, chartCache } from '@/components/common/js/common'
+import { initColor } from '@/components/chart/chart/tools'
+import UPlot from 'uplot'
+import chartTimeSeriesMixin from '@/components/chart/chart/uplot/chartTimeSeriesMixin'
+import chartDataFormat from '@/components/chart/chartDataFormat'
+import getStackedOpts from './stack'
+
+export default {
+ name: 'chartTimeSeries',
+ components: {
+ chartLegend: legend
+ },
+ props: {
+ from: String,
+ multipleTime: {},
+ minusTime: {}
+ },
+ mixins: [chartMixin, renderChart, chartTimeSeriesMixin],
+ data () {
+ return {
+ stackTotalColor: null,
+ stackTotalColorRight: null,
+ isStack: false,
+ hasRightYAxis: false,
+ chartLoading: false,
+ cursorDefault: false,
+ toolbox: {
+ x: 0,
+ y: 0,
+ title: 0,
+ value: 0,
+ mapping: {},
+ show: false,
+ metric: {},
+ activeIndex: undefined,
+ clickIndex: undefined
+ },
+ isGrey: [],
+ seriesData: []
+ }
+ },
+ computed: {
+ lineOption () {
+ return this.nzDefaultConfig.option
+ },
+ hasLegend () {
+ try {
+ return [chartLegendPlacement.bottom, chartLegendPlacement.left, chartLegendPlacement.right].indexOf(this.chartInfo.param.legend.placement) > -1 && this.chartInfo.param.enable.legend
+ } catch (e) {
+ return false
+ }
+ },
+ legendPlacement () {
+ try {
+ switch (this.chartInfo.param.legend.placement) {
+ case 'left':
+ case 'right':
+ case 'bottom': {
+ return `nz-chart__component--${this.chartInfo.param.legend.placement}`
+ }
+ default: return ''
+ }
+ } catch (e) {
+ return ''
+ }
+ },
+ // timeSeries类型图表联动
+ isConnect () {
+ return this.$store.state.panel.isConnect
+ }
+ },
+ watch: {
+ // 监听当前鼠标所在的图表id变化
+ '$store.state.panel.currentMousemove': {
+ handler (n) {
+ if (this.isConnect !== 'crosshair') {
+ return
+ }
+ // 判断是否是当前鼠标所在的图表
+ if (n === this.chartId) {
+ let option = {}
+ for (const key in chartCache) {
+ if (!chartCache[key] || chartCache[key].group !== 'timeSeriesGroup') {
+ continue
+ }
+ if (chartCache[key] === getChart(this.chartId)) {
+ option = {
+ tooltip: {
+ className: 'chart-time-series'
+ }
+ }
+ } else {
+ option = {
+ tooltip: {
+ className: 'chart-time-series hide'
+ }
+ }
+ }
+ chartCache[key].setOption(option)
+ }
+ }
+ }
+ }
+ },
+ methods: {
+ initChart (chartOptions = this.chartOption) {
+ this.setDataLink()
+ try {
+ this.isStack = !!this.chartInfo.param.stack
+ } catch (e) {}
+ const self = this
+ const leftUnit = this.chartInfo.unit
+ const leftUnitCompute = chartDataFormat.getUnit(leftUnit)
+ const rightUnit = this.$lodash.get(this.chartInfo, 'param.rightYAxis.unit', 2)
+ const rightUnitCompute = chartDataFormat.getUnit(rightUnit)
+ const incrs = leftUnitCompute.ascii == 1024 ? this.incrs : undefined
+ const rightIncrs = rightUnitCompute.ascii == 1024 ? this.incrs : undefined
+ const decimals = this.chartInfo.param.decimals || 2
+ const cursLeft = -10
+ const cursTop = -10
+ const { seriesData, seriesAll } = this.initSeriesData(this.chartData)
+ this.isNoData = false
+ if (!seriesData.length || seriesData.length == 1) {
+ this.isNoData = true
+ this.$emit('chartIsNoData', this.isNoData)
+ }
+ if (this.isNoData) {
+ return
+ }
+ // .compute(minusVal, null, -1, decimals)
+ let opts = {
+ id: `chart-canvas-${this.chartId}-uplot`,
+ mode: 1,
+ width: 100,
+ height: 100,
+ cursor: {
+ focus: {
+ prox: 5
+ },
+ drag: {
+ x: true
+ },
+ dataIdx: (self, seriesIdx, hoveredIdx, cursorXVal) => {
+ const seriesData = self.data[seriesIdx]
+ const hoverProximityPx = (self.valToPos(self.data[0][1], 'x') - self.valToPos(self.data[0][0], 'x')) / 2
+ if (seriesData[hoveredIdx] == null) {
+ let nonNullLft = null
+ let nonNullRgt = null
+ let i
+
+ i = hoveredIdx
+ while (nonNullLft == null && i-- > 0) {
+ if (seriesData[i] != null) { nonNullLft = i }
+ }
+
+ i = hoveredIdx
+ while (nonNullRgt == null && i++ < seriesData.length) {
+ if (seriesData[i] != null) { nonNullRgt = i }
+ }
+
+ const xVals = self.data[0]
+
+ const curPos = self.valToPos(cursorXVal, 'x')
+ const rgtPos = nonNullRgt == null ? Infinity : self.valToPos(xVals[nonNullRgt], 'x')
+ const lftPos = nonNullLft == null ? -Infinity : self.valToPos(xVals[nonNullLft], 'x')
+
+ const lftDelta = curPos - lftPos
+ const rgtDelta = rgtPos - curPos
+
+ if (lftDelta <= rgtDelta) {
+ if (lftDelta <= hoverProximityPx) { hoveredIdx = nonNullLft }
+ } else {
+ if (rgtDelta <= hoverProximityPx) { hoveredIdx = nonNullRgt }
+ }
+ }
+ return hoveredIdx
+ },
+ points: {
+ size: 10,
+ width: 5
+ }
+ },
+ plugins: [
+ this.tooltipPlugin({
+ onclick (u, seriesIdx, dataIdx) {
+ console.log(u, seriesIdx, dataIdx, 'nz-tooltipClick')
+ }
+ })
+ ],
+ padding: [15, this.autoPadRight, 15, 15],
+ legend: {
+ show: false
+ },
+ series: [
+ {
+ scale: 'x'
+ }
+ ],
+ tzDate: ts => UPlot.tzDate(new Date(ts * 1e3), localStorage.getItem('nz-sys-timezone')),
+ fmtDate: () => {
+ return self.xAxisLabelFormatter(seriesData[0][0], seriesData[0][seriesData[0].length - 1])
+ },
+ axes: [
+ {
+ scale: 'x',
+ gap: 5,
+ grid: {
+ show: true,
+ stroke: 'rgba(0, 10, 23, 0.09)',
+ width: 1
+ }
+ },
+ {
+ scale: 'left',
+ values: (u, vals, space) => vals.map(v => leftUnitCompute.compute(v, null, -1, decimals)),
+ incrs: incrs,
+ gap: 5,
+ grid: {
+ show: true,
+ stroke: 'rgba(0, 10, 23, 0.09)',
+ width: 1
+ },
+ // space: (self) => {
+ // console.log(self)
+ // return 50
+ // },
+ 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)
+ }
+ },
+ {
+ show: true,
+ side: 1,
+ grid: {
+ show: false,
+ stroke: 'rgba(0, 10, 23, 0.09)',
+ width: 1
+ },
+ scale: 'right',
+ gap: 5,
+ // space: (self) => {
+ // console.log(self)
+ // return 50
+ // },
+ values: (u, vals, space) => vals.map(v => rightUnitCompute.compute(v, null, -1, decimals)),
+ incrs: rightIncrs,
+ ticks: {
+ show: false // true
+ },
+ 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)
+ }
+ }
+ ],
+ scales: {
+ x: {
+ key: 'x',
+ auto: true,
+ ori: 0,
+ dir: 1,
+ time: true
+ },
+ left: {
+ key: 'left',
+ time: false,
+ auto: true,
+ ori: 1,
+ dir: 1,
+ distr: 1
+ },
+ right: {
+ key: 'right',
+ time: false,
+ auto: true,
+ ori: 1,
+ dir: 1,
+ distr: 1
+ }
+ }
+ }
+ if (this.isConnect !== 'none') { // 是否同步光标
+ opts.cursor.sync = {
+ key: 'nz' + this.isFullscreen,
+ setSeries: true,
+ scales: [null, null]
+ }
+ }
+ let data = this.seriesData = seriesData
+ opts.series.push(...seriesAll)
+ if (this.isStack) {
+ const obj = getStackedOpts('', opts, data)
+ opts = obj.opts
+ data = obj.data
+ }
+ this.renderMinMax(opts)
+ if (getChart(this.chartId)) {
+ getChart(this.chartId).destroy()
+ }
+ setTimeout(() => { // 延迟加载 保证legend的高度正常
+ const dom = document.getElementById(`chart-canvas-${this.chartId}`)
+ const width = dom.offsetWidth
+ const height = dom.offsetHeight
+ opts.width = width
+ opts.height = height
+ let chartUplot = ''
+ chartUplot = new UPlot(opts, data, document.getElementById(`chart-canvas-${this.chartId}`))
+ setChart(this.chartId, chartUplot)
+ }, 100)
+ },
+ renderMinMax (opts) {
+ let leftMin = this.$lodash.get(this.chartInfo, 'param.min', undefined)
+ let leftMax = this.$lodash.get(this.chartInfo, 'param.max', undefined)
+ if (leftMin || leftMax) {
+ if (leftMin > leftMax) {
+ const temp = leftMin
+ leftMin = leftMax
+ leftMax = temp
+ }
+ opts.scales.left.range = (self, initMin, initMax, scaleKey) => {
+ if (typeof (leftMin) === 'undefined') {
+ if (initMin > 0) {
+ leftMin = initMin / 2
+ } else {
+ leftMin = initMin * 2
+ }
+ }
+ if (typeof (leftMax) === 'undefined') {
+ if (initMax > 0) {
+ leftMax = initMax * 2
+ } else {
+ leftMax = initMax / 2
+ }
+ }
+ return [leftMin, leftMax]
+ }
+ }
+ const rightYAxisEnable = this.$lodash.get(this.chartInfo, 'param.enable.rightYAxis', false)
+ if (rightYAxisEnable) {
+ let rightMin = this.$lodash.get(this.chartInfo, 'param.rightYAxis.min', undefined)
+ let rightMax = this.$lodash.get(this.chartInfo, 'param.rightYAxis.max', undefined)
+ if (rightMin || rightMax) {
+ if (rightMin > leftMax) {
+ const temp = rightMin
+ rightMin = rightMax
+ rightMax = temp
+ }
+ opts.scales.right.range = (self, initMin, initMax, scaleKey) => {
+ if (typeof (rightMin) === 'undefined') {
+ if (initMin > 0) {
+ rightMin = initMin / 2
+ } else {
+ rightMin = initMin * 2
+ }
+ }
+ if (typeof (rightMax) === 'undefined') {
+ if (initMax > 0) {
+ rightMax = initMax * 2
+ } else {
+ rightMax = initMax / 2
+ }
+ }
+ return [rightMin, rightMax]
+ }
+ }
+ }
+ },
+ 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)
+ },
+ autoPadRight (self, side, sidesWithAxes, cycleNum) {
+ const xAxis = self.axes[0]
+
+ const xVals = xAxis._values
+
+ if (xVals != null) {
+ // bail out, force convergence
+ if (cycleNum > 2) { return self._padding[1] }
+
+ const xSplits = xAxis._splits
+ const rightSplit = xSplits[xSplits.length - 1]
+ const rightSplitCoord = self.valToPos(rightSplit, 'x')
+ const leftPlotEdge = (self.bbox.left / devicePixelRatio)
+ const rightPlotEdge = leftPlotEdge + (self.bbox.width / devicePixelRatio)
+ const rightChartEdge = rightPlotEdge + self._padding[1]
+
+ const pxPerChar = 15
+ const rightVal = xVals[xVals.length - 1] + ''
+ const valHalfWidth = pxPerChar * (rightVal.length / 2)
+
+ const rightValEdge = leftPlotEdge + rightSplitCoord + valHalfWidth
+
+ if (rightValEdge >= rightChartEdge) {
+ return rightValEdge - rightPlotEdge
+ }
+ }
+
+ // default size
+ return 15
+ },
+ clickout () {
+ if (this.toolbox.show) {
+ this.toolbox.show = false
+ }
+ },
+ showAllSeries () {
+ const echarts = getChart(this.chartId)
+ const arr = []
+ if (echarts) {
+ echarts.series.forEach((seriesItem, sindex) => {
+ if (sindex > 0) {
+ echarts.setSeries(sindex, { show: true, focus: false })
+ arr.push(false)
+ }
+ })
+ this.isGrey = arr
+ if (this.$refs.legend) {
+ this.$refs.legend.isGrey = arr
+ }
+ if (this.$refs.legend) {
+ this.$refs.legend.isGrey = this.isGrey = arr
+ }
+ }
+ this.renderYaxis()
+ this.clickout()
+ },
+ showSelectedSeries () {
+ const index = this.toolbox.clickIndex
+ const echarts = getChart(this.chartId)
+ const arr = []
+ if (echarts) {
+ echarts.series.forEach((seriesItem, sindex) => {
+ if (sindex > 0) {
+ echarts.setSeries(sindex, { show: false, focus: false })
+ arr.push(true)
+ }
+ })
+ echarts.setSeries(index + 1, { show: true, focus: false })
+ arr[index] = false
+ this.isGrey = arr
+ if (this.$refs.legend) {
+ this.$refs.legend.isGrey = arr
+ }
+ }
+ this.renderYaxis()
+ this.clickout()
+ },
+ legendChange (isGrey) {
+ this.isGrey = isGrey
+ this.renderYaxis()
+ },
+ resize () {
+ setTimeout(() => {
+ const dom = this.$refs['timeSeries-chart-box']
+ const width = dom.offsetWidth
+ const legendHeight = this.$lodash.get(this.$refs, 'legend.$el.offsetHeight', 40)
+ const height = dom.offsetHeight - legendHeight
+ const u = getChart(this.chartId)
+ if (u) {
+ u.setSize({ width, height })
+ }
+ }, 100)
+ },
+ renderYaxis () {
+ const u = getChart(this.chartId)
+ let leftShow = false
+ let rightShow = false
+ u.series.forEach(item => {
+ if (item.show && item.scale == 'left') {
+ leftShow = true
+ }
+ if (item.show && item.scale == 'right') {
+ rightShow = true
+ }
+ })
+ u.axes[1].show = leftShow
+ u.axes[2].show = rightShow
+ if (!leftShow) {
+ u.axes[2].grid.show = true
+ } else {
+ u.axes[2].grid.show = false
+ }
+ u.redraw(false, true)
+ }
+ },
+ mounted () {
+ 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 () {
+ const chart = getChart(this.chartId)
+ if (chart) {
+ const over = chart.over
+ over.removeEventListener()
+ chart.destroy()
+ }
+ }
+}
+</script>
+
+<style scoped>
+
+</style>
diff --git a/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeriesMixin.js b/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeriesMixin.js
new file mode 100644
index 000000000..9b8a7f935
--- /dev/null
+++ b/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeriesMixin.js
@@ -0,0 +1,665 @@
+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 { formatScientificNotation, getMetricTypeValue } from '@/components/common/js/tools'
+import bus from '@/libs/bus'
+import moment from 'moment-timezone'
+import { getChart } from '@/components/common/js/common'
+import uplot from 'uplot'
+export default {
+ data () {
+ return {
+ seriesColor: initColor(),
+ incrs: Incrs,
+ dataIdx: null,
+ seriesIdx: null,
+ mousePosition: {
+ top: 0,
+ left: 0
+ }
+ }
+ },
+ computed: {
+ // timeSeries类型图表联动
+ isConnect () {
+ return this.$store.state.panel.isConnect
+ },
+ // timeSeries类型图表联动
+ currentMousemove () {
+ return this.$store.state.panel.currentMousemove
+ }
+ },
+ methods: {
+ initSeriesData (chartData) { // 处理数据 以及 series
+ let time = []
+ this.legends = []
+ const nullValueMode = this.chartInfo.param.nullType
+ const seriesData = [] // 返回的数据
+ const seriesAll = [ // 返回的 series
+
+ ]
+ let chartIndex = 0
+ chartData.forEach(series => { // 首先处理时间 对应点没有值(不包括null 则添加undefind)
+ series.forEach(item => {
+ time.push(...item.values.map(value => value[0]))
+ })
+ })
+ const timeSet = new Set(time)
+ time = [...timeSet]
+ time = this.$lodash.sortBy(time, function (o) { return o })
+ const ObjTime = {}
+ time.forEach(item => {
+ ObjTime[item] = undefined
+ })
+ chartData.forEach((series, expressionIndex) => { // 首先处理时间 对应点没有值(不包括null 则添加undefind)
+ series.forEach((item, seriesIndex) => {
+ if (chartIndex >= 20 && !this.showAllData) {
+ return
+ }
+ let seriesObjTime = {}
+ // 若需要统计,处理统计数据
+ const statisticsTypes = this.chartInfo.param.legend ? this.chartInfo.param.legend.values : ''
+ let statistics = []
+ if (!lodash.isEmpty(statisticsTypes)) {
+ statistics = statisticsTypes.map(type => {
+ return { type, value: getMetricTypeValue(item.values, type) }
+ })
+ }
+ item.statistics = statistics
+ item.values.forEach(value => {
+ let itemValue = value[1]
+ if (typeof (itemValue) === 'string') {
+ itemValue = Number(itemValue)
+ }
+ if (itemValue === null && nullValueMode !== 'null') {
+ if (nullValueMode === 'zero') {
+ itemValue = 0
+ } else {
+ itemValue = undefined
+ }
+ }
+ seriesObjTime[value[0]] = itemValue
+ })
+ // 处理统计数据 statistics
+ seriesObjTime = {
+ ...ObjTime,
+ ...seriesObjTime
+ }
+ item.expressionIndex = expressionIndex
+ seriesData.push(Object.keys(seriesObjTime).map(time => seriesObjTime[time]))
+ seriesAll.push(this.renderSeries(item, expressionIndex, seriesIndex, chartIndex))
+ chartIndex++
+ })
+ })
+ seriesData.unshift(time)
+ this.series = seriesAll
+ return {
+ seriesData,
+ seriesAll
+ }
+ },
+ renderSeries (series, expressionIndex, dataIndex, chartIndex) {
+ const leftUnit = this.chartInfo.unit
+ const leftUnitCompute = chartDataFormat.getUnit(leftUnit)
+ const decimals = this.chartInfo.param.decimals || 2
+ if (chartIndex > 19) {
+ this.seriesColor.push(randomcolor())
+ }
+ const legend = this.handleLegend(this.chartInfo, series, expressionIndex, dataIndex, chartIndex)
+ let isRight
+ if (this.chartInfo.param.enable.rightYAxis) {
+ const elementNames = this.$lodash.get(this.chartInfo, 'param.rightYAxis.elementNames', [])
+ isRight = elementNames.indexOf(series.elements.name) !== -1 ? 1 : 0
+ }
+ const name = legend.name
+ const alias = legend.alias
+ const statistics = series.statistics
+ const chartType = this.chartInfo.type
+
+ const obj = {
+ name: name,
+ label: alias,
+ scale: isRight ? 'right' : 'left', // right
+ yAxisIndex: isRight, // right
+ // values: (u, v) => series.elements.name + JSON.stringify(series.metric),
+ stroke: this.seriesColor[chartIndex],
+ width: 1 / devicePixelRatio,
+ expressionIndex: series.expressionIndex,
+ paths (taht, seriesIdx, idx0, idx1, filtIdxs) {
+ return uplot.paths.spline(taht)(taht, seriesIdx, idx0, idx1, filtIdxs)
+ },
+ spanGaps: true
+ }
+ if (chartType === 'area') {
+ obj.fill = this.seriesColor[chartIndex] + '20' // 面积图使用
+ }
+ if (chartType === 'point') {
+ obj.points = {
+ show: true,
+ size: 6,
+ width: 3,
+ fill: this.seriesColor[chartIndex],
+ stroke: this.seriesColor[chartIndex]
+ }
+ obj.width = 0
+ }
+ this.legends.push({ name, alias, statistics, color: this.seriesColor[chartIndex] })
+ return obj
+ },
+ tooltipPlugin ({ onclick, shiftX = 10, shiftY = 10 }) {
+ let tooltipLeftOffset = 0
+ let tooltipTopOffset = 0
+ const self = this
+ const totoalStr = this.$t('dashboard.dashboard.chartTotal')
+ const tooltip = document.createElement('div')
+ tooltip.className = 'nz-uplot-tooltip chart-time-series-tooltip'
+ tooltip.style.display = 'none'
+ let over
+ let isRender = false
+ function setTooltip (u, e) { // 生成tooltip内容
+ tooltip.style.display = 'none'
+ over.style.cursor = null
+ isRender = false
+ const { top } = u.cursor
+ const lft = u.valToPos(u.data[0][self.dataIdx], 'x')
+ const windowWidth = window.innerWidth// 窗口宽度
+ const windowHeight = window.innerHeight// 窗口高度
+ let x = 0
+ let y = 0
+ if (self.mousePosition.left < (windowWidth / 2)) { // 说明鼠标在左边放不下提示框
+ tooltip.style.left = (tooltipLeftOffset + lft + shiftX) + 'px'
+ } else {
+ tooltip.style.left = (tooltipLeftOffset + lft - shiftX) + 'px'
+ x = '-100%'
+ }
+ if (self.mousePosition.top + 50 < windowHeight / 2) { // 说明鼠标上面放不下提示框
+ tooltip.style.top = (tooltipTopOffset + top + shiftY) + 'px'
+ } else {
+ tooltip.style.top = (tooltipTopOffset + top - shiftY) + 'px'
+ y = '-100%'
+ }
+ tooltip.style.transform = `translate(${x},${y})`
+ if (!self.$lodash.get(self.chartInfo, 'param.enable.tooltip', false)) {
+ return
+ }
+ let params = []
+ const tooltipModel = self.$lodash.get(self.chartInfo, 'param.tooltip.mode', 'single')
+ if (self.chartInfo.param && !(tooltipModel == 'single')) {
+ params = u.series.map((s, i) => {
+ if (i == 0) return ''
+ const value = self.seriesData[i][self.dataIdx]
+ return {
+ seriesIndex: i - 1,
+ yAxisIndex: s.yAxisIndex,
+ value: [u.data[0][self.dataIdx], value],
+ seriesName: s.label,
+ show: s.show
+ }
+ })
+ params = params.filter(item => {
+ return item && item.show
+ })
+ } else if (self.seriesIdx) {
+ let obj = self.series[self.seriesIdx - 1]
+ let value
+ if (!obj) {
+ obj = {}
+ } else {
+ value = self.seriesData[self.seriesIdx][self.dataIdx]
+ }
+ params = [{
+ seriesIndex: self.seriesIdx - 1,
+ yAxisIndex: obj.yAxisIndex,
+ value: [u.data[0][self.dataIdx], value],
+ seriesName: obj.label || ''
+ }]
+ }
+ isRender = !!params.length
+ if (!isRender) {
+ tooltip.style.display = 'none'
+ return
+ } else {
+ tooltip.style.display = 'block'
+ }
+ if (self.isConnect == 'crosshair' && self.chartId != self.currentMousemove) {
+ tooltip.style.display = 'none'
+ return
+ }
+ if (tooltipModel == 'single' && self.isConnect !== 'none' && self.chartId != self.currentMousemove) {
+ tooltip.style.display = 'none'
+ return
+ }
+ if (self.seriesIdx) {
+ over.style.cursor = 'pointer'
+ }
+ 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) {
+ if (!arr.length) {
+ return
+ }
+
+ // 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 = typeof (item.value[1]) == 'undefined' ? 0 : formatScientificNotation(item.value[1], paramsDot)
+ const showVal = typeof (item.value[1]) == 'undefined' ? '' : chartDataFormat.getUnit(unit).compute(val, null, -1, decimals)
+ sum += isNaN(self.numberWithEConvent(val)) ? 0 : parseFloat(self.numberWithEConvent(val))
+ let previousDom = ''
+ if (previousItem) {
+ const previousVal = typeof (previousItem.value[1]) == 'undefined' ? 0 : 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="${(self.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>${showVal}</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="${totoalStr}">
+ <span class="${className}" style="background-color: ${color};color: ${color}"></span>
+ <span>${totoalStr}</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: [
+ u => {
+ over = u.over
+ tooltipLeftOffset = parseFloat(over.style.left)
+ tooltipTopOffset = parseFloat(over.style.top)
+ u.root.querySelector('.u-wrap').appendChild(tooltip)
+ over.addEventListener('mouseenter', self.uplotMouseenter)
+ // over.addEventListener('mouseleave', self.uplotMouseleave.bind(self, hideTooltip, over)) 放入mouseenter 减少绑定事件数量
+ // over.addEventListener('mousemove', self.uplotMousemove)
+ // over.addEventListener('mousedown', self.uplotMousedown)
+ // over.addEventListener('mouseup', self.uplotMouseup.bind(self, nodeInfo))
+ }
+ ],
+ setCursor: [
+ u => {
+ const c = u.cursor
+ if (self.dataIdx != c.idx) {
+ self.dataIdx = c.idx
+ setTooltip(u)
+ }
+ }
+ ],
+ setSeries: [
+ (u, sidx) => {
+ if (self.seriesIdx != sidx) {
+ this.seriesIdx = sidx
+ if (self.dataIdx != null) { setTooltip(u) }
+ }
+ }
+ ],
+ drawClear: [
+ () => {
+ self.renderThresholds()
+ }
+ ]
+ }
+ }
+ },
+ xAxisLabelFormatter (minTime, maxTime) {
+ const self = this
+ return function (val, index) {
+ const value = self.momentStrToTimestamp(self.momentTz(val))
+ let offset = localStorage.getItem('nz-sys-timezone')
+ offset = moment.tz(offset).format('Z')
+ offset = Number.parseInt(offset)
+ const localOffset = new Date().getTimezoneOffset() * 60 * 1000 * -1 // 默认 一分钟显示时区偏移的结果
+ // if (window.dataJson) {
+ // offset = new Date().getTimezoneOffset() * -1 / 60
+ // }
+ const tData = new Date(value - localOffset + offset * 60 * 60 * 1000)
+ let hour = tData.getHours()
+ hour = hour > 9 ? hour : '0' + hour // 加0补充为两位数字
+ let minute = tData.getMinutes()
+ minute = minute > 9 ? minute : '0' + minute // 如果分钟小于10,则在前面加0补充为两位数字
+ if (minTime !== null && maxTime !== null) {
+ const diffSec = (maxTime - minTime)
+ const secOneDay = 12 * 60 * 60// 0.5天的秒数
+ const secOneMonth = secOneDay * 30// 30天的秒数
+ const dateFormatStr = self.timeFormatMain.split(' ')[0]
+ let str = ''
+ const month = tData.getMonth() + 1
+ const day = tData.getDate()
+ if (dateFormatStr === 'DD/MM/YYYY') {
+ str += [day, month].join('/')
+ } else if (dateFormatStr === 'MM/DD/YYYY') {
+ str += [month, day].join('/')
+ } else {
+ str += [month, day].join('-')
+ }
+ if (diffSec <= secOneDay - 100) { // 同一天
+ return [hour, minute].join(':')
+ } else if (diffSec < secOneMonth) { // 大于1天,小于30天
+ return str + '\n' + [hour, minute].join(':')
+ } else { // 大于等于30天
+ return str
+ }
+ } else {
+ return [tData.getFullYear(), tData.getMonth() + 1, tData.getDate()].join('/') + '\n' + [hour, minute].join(':')
+ }
+ }
+ },
+ uplotMouseenter () {
+ const chart = getChart(this.chartId)
+ const over = chart.over
+ const root = chart.root.querySelector('.u-wrap')
+ let tooltip = root.getElementsByClassName('nz-uplot-tooltip')
+ if (tooltip.length) {
+ tooltip = tooltip[0]
+ tooltip.style.display = 'block'
+ }
+ over.addEventListener('mouseleave', this.uplotMouseleave)
+ over.addEventListener('mousemove', this.uplotMousemove)
+ over.addEventListener('mousedown', this.uplotMousedown)
+ over.addEventListener('mouseup', this.uplotMouseup)
+ this.$store.commit('setCurrentMousemove', this.chartId)
+ },
+ uplotMouseleave () {
+ const chart = getChart(this.chartId)
+ const over = chart.over
+ const tooltip = document.getElementsByClassName('nz-uplot-tooltip')
+ if (tooltip.length) {
+ tooltip.forEach(item => {
+ item.style.display = 'none'
+ })
+ }
+ over.removeEventListener('mouseleave', this.uplotMouseleave)
+ over.removeEventListener('mousemove', this.uplotMousemove)
+ over.removeEventListener('mousedown', this.uplotMousedown)
+ over.removeEventListener('mouseup', this.uplotMouseup)
+ },
+ uplotMousemove (e) {
+ this.mousePosition = {
+ left: e.pageX,
+ top: e.pageY
+ }
+ },
+ uplotMousedown (e) {
+ this.toolbox.x = e.clientX
+ this.toolbox.y = e.clientY
+ },
+ uplotMouseup (e) {
+ if (e.clientX == this.toolbox.x && e.clientY == this.toolbox.y) {
+ if (this.seriesIdx) {
+ this.toolbox.show = true
+ this.datalinkClick(this.seriesIdx, this.dataIdx)
+ const windowWidth = window.innerWidth// 窗口宽度
+ const windowHeight = window.innerHeight// 窗口高度
+ this.$nextTick(() => {
+ const box = document.getElementById(`chart-toolbox-${this.chartId}`)
+ const left = e.pageX - this.$refs['timeSeries-chart-box'].getBoundingClientRect().left
+ const top = e.pageY - this.$refs['timeSeries-chart-box'].getBoundingClientRect().top
+ if (box) {
+ const boxWidth = box.offsetWidth
+ const boxHeight = box.offsetHeight
+ if (e.pageX < (windowWidth / 2)) { // 说明鼠标在左边放不下提示框
+ this.toolbox.x = left + 15
+ } else {
+ this.toolbox.x = left - boxWidth - 15
+ }
+ if (e.pageY + 50 + boxHeight < windowHeight) { // 说明鼠标上面放不下提示框
+ this.toolbox.y = top + 15
+ } else {
+ this.toolbox.y = top - boxHeight - 10
+ }
+ }
+ })
+ } else {
+ this.toolbox.show = false
+ }
+ }
+ },
+ datalinkClick (seriesIdx, dataIdx, e) { // 处理datalink数据
+ const obj = this.series[seriesIdx - 1]
+ const chart = getChart(this.chartId)
+ const params = {
+ seriesIndex: seriesIdx - 1,
+ yAxisIndex: obj.yAxisIndex,
+ value: [chart.data[0][dataIdx], chart.data[seriesIdx][dataIdx]],
+ seriesName: obj.label
+ }
+ if (!params.seriesName) {
+ return
+ }
+ const nameArr = params.seriesName.split('-')
+ if (nameArr.length > 1) {
+ nameArr.splice(nameArr.length - 1, 1)
+ }
+ const seriesName = nameArr.join('-')
+ if (this.series[params.seriesIndex]) {
+ params.yAxisIndex = this.series[params.seriesIndex].yAxisIndex
+ }
+ const decimals = this.chartInfo.param.decimals || 2
+ let unit = this.chartInfo.unit ? this.chartInfo.unit : 2
+ if (params.yAxisIndex == 1) {
+ unit = lodash.get(this, 'chartInfo.param.rightYAxis.unit', 2)
+ }
+ // title
+ const value = bus.computeTimezone(params.value[0] * 1000)
+ const tData = new Date(value)
+ // value
+ let paramsDot = bus.countDecimals(params.value[1])
+ if (paramsDot < this.chartDot) {
+ paramsDot = this.chartDot
+ } else if (paramsDot > 6) {
+ paramsDot = 6
+ }
+ const val = formatScientificNotation(params.value[1], paramsDot)
+ // 根据左右轴设置图标
+ let className = 'row__color-block'
+ if (params.yAxisIndex == 0) {
+ className = 'yAxis-icon nz-icon nz-icon-zuozongzhou'
+ } else if (params.yAxisIndex == 1) {
+ className = 'yAxis-icon nz-icon nz-icon-youzongzhou'
+ }
+ const color = this.colorList[params.seriesIndex]
+ this.toolbox.tooltipHtml = `
+ <div class="nz-chart__tooltip">
+ <div class="tooltip-title" style="margin-bottom: 5px">${bus.timeFormate(tData)}</div>
+ <div class="tooltip__row">
+ <div class="row__label" :title=">${seriesName}">
+ <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>
+ </div>
+ </div>
+ </div>
+ `
+ this.toolbox.show = true
+ this.toolbox.metric.labels = this.series[params.seriesIndex].labels
+ this.toolbox.metric.expressionIndex = this.series[params.seriesIndex].expressionIndex
+ this.toolbox.clickIndex = params.seriesIndex
+ },
+ renderThresholds () { // 画阈值线
+ const u = getChart(this.chartId)
+ const thresholdsEnable = this.$lodash.get(this.chartInfo, 'param.enable.thresholds', false)
+ if (!thresholdsEnable || !u) {
+ return
+ }
+ const thresholdsArr = this.$lodash.get(this.chartInfo, 'param.thresholds', [])
+ const ctx = u.ctx
+ ctx.save()
+ const xd = u.data[0]
+ const i0 = 0
+ const i1 = xd.length - 1
+ const x0 = u.valToPos(xd[i0], 'x', true)
+ const x1 = u.valToPos(xd[i1], 'x', true)
+ thresholdsArr.forEach(item => {
+ const y0 = u.valToPos(item.value, 'left', true)
+ const y1 = u.valToPos(item.value, 'left', true)
+ ctx.beginPath()
+ ctx.strokeStyle = item.color
+ ctx.setLineDash([5, 5])
+ ctx.moveTo(x0, y0)
+ ctx.lineTo(x1, y1)
+ ctx.stroke()
+ })
+ ctx.restore()
+ }
+ }
+}
diff --git a/nezha-fronted/src/components/chart/chart/uplot/stack.js b/nezha-fronted/src/components/chart/chart/uplot/stack.js
new file mode 100644
index 000000000..7f97d1da9
--- /dev/null
+++ b/nezha-fronted/src/components/chart/chart/uplot/stack.js
@@ -0,0 +1,63 @@
+import uPlot from 'uplot'
+function stack (data, omit) {
+ const data2 = []
+ let bands = []
+ const d0Len = data[0].length
+ const accum = Array(d0Len)
+
+ for (let i = 0; i < d0Len; i++) { accum[i] = 0 }
+
+ for (let i = 1; i < data.length; i++) {
+ data2.push(data[i].map((v, i) => {
+ if (typeof (v) === 'undefined') {
+ return accum[i]
+ }
+ return (accum[i] += +v)
+ }))
+ }
+
+ for (let i = 1; i < data.length; i++) {
+ !omit(i) && bands.push({
+ dir: -1,
+ series: [
+ data.findIndex((s, j) => j > i && !omit(j)),
+ i
+ ]
+ })
+ }
+
+ bands = bands.filter(b => b.series[1] > -1)
+ bands = bands.filter(b => b.series[0] > -1)
+ bands = bands.reverse()
+ return {
+ data: [data[0]].concat(data2),
+ bands
+ }
+}
+
+export default function getStackedOpts (title, opt, data, interp) {
+ const opts = opt
+ const interped = interp ? interp(data) : data
+
+ const stacked = stack(interped, i => false)
+ opts.bands = stacked.bands
+
+ opts.cursor = opts.cursor || {}
+
+ opts.series.forEach(s => {
+ s.value = (u, v, si, i) => data[si][i]
+ })
+ // restack on toggle
+ opts.hooks = {
+ setSeries: [
+ (u, i) => {
+ const stacked = stack(data, i => !u.series[i].show)
+ u.delBand(null)
+ stacked.bands.forEach(b => u.addBand(b))
+ u.setData(stacked.data)
+ }
+ ]
+ }
+
+ return { opts, data: stacked.data }
+}
diff --git a/nezha-fronted/src/components/chart/chart/uplot/testData.js b/nezha-fronted/src/components/chart/chart/uplot/testData.js
new file mode 100644
index 000000000..29012f87c
--- /dev/null
+++ b/nezha-fronted/src/components/chart/chart/uplot/testData.js
@@ -0,0 +1,2 @@
+const data = [[{"metric":{"__name__":"process_resident_memory_bytes","agent_name":"nz-agent-3.9-1","application":"prometheus","datacenter":"JBXXG","instance":"192.168.44.22:3039","nz_agent_id":"44","type":"global"},"values":[[1698284160,"664502272"],[1698284240,"715702272"],[1698284320,"668807168"],[1698284400,"722210816"],[1698284480,"666652672"],[1698284560,"658755584"],[1698284640,"669261824"],[1698284720,"684421120"],[1698284800,"713576448"],[1698284880,"682487808"],[1698284960,"672030720"],[1698285040,"693309440"],[1698285120,"676003840"],[1698285200,"685109248"],[1698285280,"715018240"],[1698285360,"699088896"],[1698285440,"669544448"],[1698285520,"707051520"],[1698285600,"671023104"],[1698285680,"652013568"],[1698285760,"706666496"],[1698285840,"690761728"],[1698285920,"654004224"],[1698286000,"671494144"],[1698286080,"690024448"],[1698286160,"655577088"],[1698286240,"646959104"],[1698286320,"664928256"],[1698286400,"665780224"],[1698286480,"695353344"],[1698286560,"685662208"],[1698286640,"636469248"],[1698286720,"647122944"],[1698286800,"682663936"],[1698286880,"642875392"],[1698286960,"696758272"],[1698287040,"674689024"],[1698287120,"658259968"],[1698287200,"723881984"],[1698287280,"651169792"],[1698287360,"698503168"],[1698287440,"656830464"],[1698287520,"683626496"],[1698287600,"701636608"],[1698287680,"731688960"],[1698287760,"657887232"]],"elements":{"expression":"process_resident_memory_bytes{application=\"prometheus\"}","legend":"{{agent_name}}","name":"A","orderNum":0,"step":80,"state":1,"type":"expert","queryType":1}},{"metric":{"__name__":"process_resident_memory_bytes","agent_name":"nz-agent-3.9-2","application":"prometheus","datacenter":"JBXXG","instance":"192.168.44.23:3039","nz_agent_id":"45","type":"per_datacenter"},"values":[[1698284160,"880721920"],[1698284240,"885305344"],[1698284320,"885305344"],[1698284400,"885305344"],[1698284480,"892063744"],[1698284560,"892063744"],[1698284640,"892063744"],[1698284720,"892063744"],[1698284800,"892063744"],[1698284880,"892063744"],[1698284960,"892334080"],[1698285040,"892334080"],[1698285120,"892334080"],[1698285200,"892334080"],[1698285280,"892334080"],[1698285360,"872742912"],[1698285440,"879517696"],[1698285520,"879517696"],[1698285600,"886005760"],[1698285680,"892489728"],[1698285760,"892489728"],[1698285840,"892489728"],[1698285920,"1034932224"],[1698286000,"905584640"],[1698286080,"918441984"],[1698286160,"931688448"],[1698286240,"902414336"],[1698286320,"848613376"],[1698286400,"864821248"],[1698286480,"850259968"],[1698286560,"851611648"],[1698286640,"860532736"],[1698286720,"861609984"],[1698286800,"868364288"],[1698286880,"869986304"],[1698286960,"871337984"],[1698287040,"871878656"],[1698287120,"878637056"],[1698287200,"878637056"],[1698287280,"867917824"],[1698287360,"867917824"],[1698287440,"870076416"],[1698287520,"881156096"],[1698287600,"881696768"],[1698287680,"881696768"],[1698287760,"868925440"]],"elements":{"expression":"process_resident_memory_bytes{application=\"prometheus\"}","legend":"{{agent_name}}","name":"A","orderNum":0,"step":80,"state":1,"type":"expert","queryType":1}}],[{"metric":{"__name__":"process_resident_memory_bytes","agent_name":"nz-agent-3.9-1","application":"prometheus","datacenter":"JBXXG","instance":"192.168.44.22:3039","nz_agent_id":"44","type":"global"},"values":[[1698284160,"664502272"],[1698284175,"693637120"],[1698284190,"693637120"],[1698284205,"674811904"],[1698284220,"674811904"],[1698284235,"715702272"],[1698284250,"715702272"],[1698284265,"731127808"],[1698284280,"731127808"],[1698284295,"668807168"],[1698284310,"668807168"],[1698284325,"680472576"],[1698284340,"680472576"],[1698284355,"669126656"],[1698284370,"669126656"],[1698284385,"722210816"],[1698284400,"722210816"],[1698284415,"668172288"],[1698284430,"668172288"],[1698284445,"663568384"],[1698284460,"663568384"],[1698284475,"666652672"],[1698284490,"666652672"],[1698284505,"707928064"],[1698284520,"707928064"],[1698284535,"658755584"],[1698284550,"658755584"],[1698284565,"660320256"],[1698284580,"660320256"],[1698284595,"670625792"],[1698284610,"670625792"],[1698284625,"669261824"],[1698284640,"669261824"],[1698284655,"719749120"],[1698284670,"719749120"],[1698284685,"680538112"],[1698284700,"680538112"],[1698284715,"684421120"],[1698284730,"684421120"],[1698284745,"709795840"],[1698284760,"709795840"],[1698284775,"713576448"],[1698284790,"713576448"],[1698284805,"678215680"],[1698284820,"678215680"],[1698284835,"725278720"],[1698284850,"725278720"],[1698284865,"682487808"],[1698284880,"682487808"],[1698284895,"682954752"],[1698284910,"682954752"],[1698284925,"666243072"],[1698284940,"666243072"],[1698284955,"672030720"],[1698284970,"672030720"],[1698284985,"706322432"],[1698285000,"706322432"],[1698285015,"693309440"],[1698285030,"693309440"],[1698285045,"720531456"],[1698285060,"720531456"],[1698285075,"666591232"],[1698285090,"666591232"],[1698285105,"676003840"],[1698285120,"676003840"],[1698285135,"705163264"],[1698285150,"705163264"],[1698285165,"721276928"],[1698285180,"721276928"],[1698285195,"685109248"],[1698285210,"685109248"],[1698285225,"666677248"],[1698285240,"666677248"],[1698285255,"715018240"],[1698285270,"715018240"],[1698285285,"665255936"],[1698285300,"665255936"],[1698285315,"671453184"],[1698285330,"671453184"],[1698285345,"699088896"],[1698285360,"699088896"],[1698285375,"731766784"],[1698285390,"731766784"],[1698285405,"681107456"],[1698285420,"681107456"],[1698285435,"669544448"],[1698285450,"669544448"],[1698285465,"681975808"],[1698285480,"681975808"],[1698285495,"707051520"],[1698285510,"707051520"],[1698285525,"743505920"],[1698285540,"743505920"],[1698285555,"678473728"],[1698285570,"678473728"],[1698285585,"671023104"],[1698285600,"671023104"],[1698285615,"661622784"],[1698285630,"661622784"],[1698285645,"694079488"],[1698285660,"694079488"],[1698285675,"652013568"],[1698285690,"652013568"],[1698285705,"648028160"],[1698285720,"648028160"],[1698285735,"706666496"],[1698285750,"706666496"],[1698285765,"665985024"],[1698285780,"665985024"],[1698285795,"699326464"],[1698285810,"699326464"],[1698285825,"690761728"],[1698285840,"690761728"],[1698285855,"675127296"],[1698285870,"675127296"],[1698285885,"686600192"],[1698285900,"686600192"],[1698285915,"654004224"],[1698285930,"654004224"],[1698285945,"677564416"],[1698285960,"677564416"],[1698285975,"671494144"],[1698285990,"671494144"],[1698286005,"658026496"],[1698286020,"658026496"],[1698286035,"642789376"],[1698286050,"642789376"],[1698286065,"690024448"],[1698286080,"690024448"],[1698286095,"636588032"],[1698286110,"636588032"],[1698286125,"650903552"],[1698286140,"650903552"],[1698286155,"655577088"],[1698286170,"655577088"],[1698286185,"675180544"],[1698286200,"675180544"],[1698286215,"646959104"],[1698286230,"646959104"],[1698286245,"652636160"],[1698286260,"652636160"],[1698286275,"673689600"],[1698286290,"673689600"],[1698286305,"664928256"],[1698286320,"664928256"],[1698286335,"688869376"],[1698286350,"688869376"],[1698286365,"686288896"],[1698286380,"686288896"],[1698286395,"665780224"],[1698286410,"665780224"],[1698286425,"647020544"],[1698286440,"647020544"],[1698286455,"695353344"],[1698286470,"695353344"],[1698286485,"647864320"],[1698286500,"647864320"],[1698286515,"699715584"],[1698286530,"699715584"],[1698286545,"685662208"],[1698286560,"685662208"],[1698286575,"651571200"],[1698286590,"651571200"],[1698286605,"698564608"],[1698286620,"698564608"],[1698286635,"636469248"],[1698286650,"636469248"],[1698286665,"702648320"],[1698286680,"702648320"],[1698286695,"647122944"],[1698286710,"647122944"],[1698286725,"650334208"],[1698286740,"650334208"],[1698286755,"670662656"],[1698286770,"670662656"],[1698286785,"682663936"],[1698286800,"682663936"],[1698286815,"705875968"],[1698286830,"705875968"],[1698286845,"691957760"],[1698286860,"691957760"],[1698286875,"642875392"],[1698286890,"642875392"],[1698286905,"664678400"],[1698286920,"664678400"],[1698286935,"696758272"],[1698286950,"696758272"],[1698286965,"643043328"],[1698286980,"643043328"],[1698286995,"656474112"],[1698287010,"656474112"],[1698287025,"674689024"],[1698287040,"674689024"],[1698287055,"656105472"],[1698287070,"656105472"],[1698287085,"649641984"],[1698287100,"649641984"],[1698287115,"658259968"],[1698287130,"658259968"],[1698287145,"682287104"],[1698287160,"682287104"],[1698287175,"723881984"],[1698287190,"723881984"],[1698287205,"662056960"],[1698287220,"662056960"],[1698287235,"706244608"],[1698287250,"706244608"],[1698287265,"651169792"],[1698287280,"651169792"],[1698287295,"659550208"],[1698287310,"659550208"],[1698287325,"706445312"],[1698287340,"706445312"],[1698287355,"698503168"],[1698287370,"698503168"],[1698287385,"666472448"],[1698287400,"666472448"],[1698287415,"656830464"],[1698287430,"656830464"],[1698287445,"659017728"],[1698287460,"659017728"],[1698287475,"702779392"],[1698287490,"702779392"],[1698287505,"683626496"],[1698287520,"683626496"],[1698287535,"699219968"],[1698287550,"699219968"],[1698287565,"659644416"],[1698287580,"659644416"],[1698287595,"701636608"],[1698287610,"701636608"],[1698287625,"652582912"],[1698287640,"652582912"],[1698287655,"731688960"],[1698287670,"731688960"],[1698287685,"687755264"],[1698287700,"687755264"],[1698287715,"660193280"],[1698287730,"660193280"],[1698287745,"657887232"],[1698287760,"657887232"]],"elements":{"expression":"process_resident_memory_bytes{application=\"prometheus\"}","legend":"{{agent_name}}-B","name":"B","orderNum":1,"id":"","state":1,"type":"expert","queryType":1}},{"metric":{"__name__":"process_resident_memory_bytes","agent_name":"nz-agent-3.9-2","application":"prometheus","datacenter":"JBXXG","instance":"192.168.44.23:3039","nz_agent_id":"45","type":"per_datacenter"},"values":[[1698284160,"880721920"],[1698284175,"880721920"],[1698284190,"882880512"],[1698284205,"882880512"],[1698284220,"884494336"],[1698284235,"884494336"],[1698284250,"885305344"],[1698284265,"885305344"],[1698284280,"885305344"],[1698284295,"885305344"],[1698284310,"885305344"],[1698284325,"885305344"],[1698284340,"885305344"],[1698284355,"885305344"],[1698284370,"885305344"],[1698284385,"885305344"],[1698284400,"885305344"],[1698284415,"885305344"],[1698284430,"885305344"],[1698284445,"885305344"],[1698284460,"892063744"],[1698284475,"892063744"],[1698284490,"892063744"],[1698284505,"892063744"],[1698284520,"892063744"],[1698284535,"892063744"],[1698284550,"892063744"],[1698284565,"892063744"],[1698284580,"892063744"],[1698284595,"892063744"],[1698284610,"892063744"],[1698284625,"892063744"],[1698284640,"892063744"],[1698284655,"892063744"],[1698284670,"892063744"],[1698284685,"892063744"],[1698284700,"892063744"],[1698284715,"892063744"],[1698284730,"892063744"],[1698284745,"892063744"],[1698284760,"892063744"],[1698284775,"892063744"],[1698284790,"892063744"],[1698284805,"892063744"],[1698284820,"892063744"],[1698284835,"892063744"],[1698284850,"892063744"],[1698284865,"892063744"],[1698284880,"892063744"],[1698284895,"892063744"],[1698284910,"892063744"],[1698284925,"892063744"],[1698284940,"892334080"],[1698284955,"892334080"],[1698284970,"892334080"],[1698284985,"892334080"],[1698285000,"892334080"],[1698285015,"892334080"],[1698285030,"892334080"],[1698285045,"892334080"],[1698285060,"892334080"],[1698285075,"892334080"],[1698285090,"892334080"],[1698285105,"892334080"],[1698285120,"892334080"],[1698285135,"892334080"],[1698285150,"892334080"],[1698285165,"892334080"],[1698285180,"892334080"],[1698285195,"892334080"],[1698285210,"892334080"],[1698285225,"892334080"],[1698285240,"892334080"],[1698285255,"892334080"],[1698285270,"892334080"],[1698285285,"892334080"],[1698285300,"892334080"],[1698285315,"892334080"],[1698285330,"870850560"],[1698285345,"870850560"],[1698285360,"872742912"],[1698285375,"872742912"],[1698285390,"879230976"],[1698285405,"879230976"],[1698285420,"885706752"],[1698285435,"885706752"],[1698285450,"879517696"],[1698285465,"879517696"],[1698285480,"879517696"],[1698285495,"879517696"],[1698285510,"879517696"],[1698285525,"879517696"],[1698285540,"886005760"],[1698285555,"886005760"],[1698285570,"886005760"],[1698285585,"886005760"],[1698285600,"886005760"],[1698285615,"886005760"],[1698285630,"886005760"],[1698285645,"886005760"],[1698285660,"892489728"],[1698285675,"892489728"],[1698285690,"892489728"],[1698285705,"892489728"],[1698285720,"892489728"],[1698285735,"892489728"],[1698285750,"892489728"],[1698285765,"892489728"],[1698285780,"892489728"],[1698285795,"892489728"],[1698285810,"892489728"],[1698285825,"892489728"],[1698285840,"892489728"],[1698285855,"892489728"],[1698285870,"892489728"],[1698285885,"892489728"],[1698285900,"892489728"],[1698285915,"892489728"],[1698285930,"1034932224"],[1698285945,"1034932224"],[1698285960,"905314304"],[1698285975,"905314304"],[1698285990,"905584640"],[1698286005,"905584640"],[1698286020,"905584640"],[1698286035,"905584640"],[1698286050,"912343040"],[1698286065,"912343040"],[1698286080,"918441984"],[1698286095,"918441984"],[1698286110,"924930048"],[1698286125,"924930048"],[1698286140,"931688448"],[1698286155,"931688448"],[1698286170,"931688448"],[1698286185,"931688448"],[1698286200,"895926272"],[1698286215,"895926272"],[1698286230,"902414336"],[1698286245,"902414336"],[1698286260,"908902400"],[1698286275,"908902400"],[1698286290,"908902400"],[1698286305,"908902400"],[1698286320,"848613376"],[1698286335,"848613376"],[1698286350,"855097344"],[1698286365,"855097344"],[1698286380,"855097344"],[1698286395,"855097344"],[1698286410,"864821248"],[1698286425,"864821248"],[1698286440,"850259968"],[1698286455,"850259968"],[1698286470,"850259968"],[1698286485,"850259968"],[1698286500,"850530304"],[1698286515,"850530304"],[1698286530,"851611648"],[1698286545,"851611648"],[1698286560,"851611648"],[1698286575,"851611648"],[1698286590,"858099712"],[1698286605,"858099712"],[1698286620,"858099712"],[1698286635,"858099712"],[1698286650,"860532736"],[1698286665,"860532736"],[1698286680,"861343744"],[1698286695,"861343744"],[1698286710,"861609984"],[1698286725,"861609984"],[1698286740,"861609984"],[1698286755,"861609984"],[1698286770,"865390592"],[1698286785,"865390592"],[1698286800,"868364288"],[1698286815,"868364288"],[1698286830,"868364288"],[1698286845,"868364288"],[1698286860,"868634624"],[1698286875,"868634624"],[1698286890,"869986304"],[1698286905,"869986304"],[1698286920,"871337984"],[1698286935,"871337984"],[1698286950,"871337984"],[1698286965,"871337984"],[1698286980,"871337984"],[1698286995,"871337984"],[1698287010,"871878656"],[1698287025,"871878656"],[1698287040,"871878656"],[1698287055,"871878656"],[1698287070,"871878656"],[1698287085,"871878656"],[1698287100,"871878656"],[1698287115,"871878656"],[1698287130,"878637056"],[1698287145,"878637056"],[1698287160,"878637056"],[1698287175,"878637056"],[1698287190,"878637056"],[1698287205,"878637056"],[1698287220,"878637056"],[1698287235,"878637056"],[1698287250,"878637056"],[1698287265,"878637056"],[1698287280,"867917824"],[1698287295,"867917824"],[1698287310,"867917824"],[1698287325,"867917824"],[1698287340,"867917824"],[1698287355,"867917824"],[1698287370,"867917824"],[1698287385,"867917824"],[1698287400,"870076416"],[1698287415,"870076416"],[1698287430,"870076416"],[1698287445,"870076416"],[1698287460,"874397696"],[1698287475,"874397696"],[1698287490,"881156096"],[1698287505,"881156096"],[1698287520,"881156096"],[1698287535,"881156096"],[1698287550,"881156096"],[1698287565,"881156096"],[1698287580,"881156096"],[1698287595,"881156096"],[1698287610,"881696768"],[1698287625,"881696768"],[1698287640,"881696768"],[1698287655,"881696768"],[1698287670,"881696768"],[1698287685,"881696768"],[1698287700,"881696768"],[1698287715,"881696768"],[1698287730,"881967104"],[1698287745,"881967104"],[1698287760,"868925440"]],"elements":{"expression":"process_resident_memory_bytes{application=\"prometheus\"}","legend":"{{agent_name}}-B","name":"B","orderNum":1,"id":"","state":1,"type":"expert","queryType":1}}]]
+export default data
diff --git a/nezha-fronted/src/components/chart/chartMixin.js b/nezha-fronted/src/components/chart/chartMixin.js
index ef546147f..28b5cdeeb 100644
--- a/nezha-fronted/src/components/chart/chartMixin.js
+++ b/nezha-fronted/src/components/chart/chartMixin.js
@@ -250,7 +250,7 @@ export default {
const colorRandom = randomcolor()
this.colorList.push(colorRandom)
}
- this.legends.push({ name, alias, statistics, color: this.colorList[colorIndex] })
+ // this.legends.push({ name, alias, statistics, color: this.colorList[colorIndex] })
return {
name,
alias
@@ -326,15 +326,6 @@ export default {
},
mouseEnterChart () {
const myChart = getChart(this.chartId)
- if (myChart) {
- setTimeout(() => {
- myChart.setOption({
- toolbox: {
- show: true
- }
- })
- }, 300)
- }
},
tooltipPosition (point, params, dom, rect, size) {
if (this.isConnect === 'tooltip' && this.$store.state.panel.currentMousemove != this.chartId) {
@@ -370,15 +361,6 @@ export default {
},
mouseLeaveChart () {
const myChart = getChart(this.chartId)
- if (myChart) {
- setTimeout(() => {
- myChart.setOption({
- toolbox: {
- show: false
- }
- })
- }, 300)
- }
},
getMaxValue (dataArg, chartInfo) {
let maxValue = 0
@@ -445,7 +427,8 @@ export default {
},
resize () {
setTimeout(() => {
- getChart(this.chartId) && getChart(this.chartId).resize()
+ console.log('chartMixin')
+ // getChart(this.chartId) && getChart(this.chartId).resize()
}, 100)
},
// 全局变量替换
diff --git a/nezha-fronted/src/components/common/bottomBox/tabs/alertMessageTabNew.vue b/nezha-fronted/src/components/common/bottomBox/tabs/alertMessageTabNew.vue
index efbd9aefc..d2fc61184 100644
--- a/nezha-fronted/src/components/common/bottomBox/tabs/alertMessageTabNew.vue
+++ b/nezha-fronted/src/components/common/bottomBox/tabs/alertMessageTabNew.vue
@@ -583,7 +583,6 @@ export default {
routePathParams.body.startAt = this.searchTimeHeader[0] ? this.momentStrToTimestamp(this.searchTimeHeader[0]) : ''
routePathParams.body.endAt = this.searchTimeHeader[1] ? this.momentStrToTimestamp(this.searchTimeHeader[1]) : ''
routePathParams.body.timeType = this.searchTimeHeader[2]
- console.log(this.$route, this.$router)
if (!this.searchTimeHeader[2]) {
routePathParams.body.startAt = this.searchTimeHeader[0] ? this.momentStrToTimestamp(this.searchTimeHeader[0]) : ''
routePathParams.body.endAt = this.searchTimeHeader[1] ? this.momentStrToTimestamp(this.searchTimeHeader[1]) : ''
diff --git a/nezha-fronted/src/components/common/bottomBox/tabs/dashboardTab.vue b/nezha-fronted/src/components/common/bottomBox/tabs/dashboardTab.vue
index f0a4b66f6..e8eda2217 100644
--- a/nezha-fronted/src/components/common/bottomBox/tabs/dashboardTab.vue
+++ b/nezha-fronted/src/components/common/bottomBox/tabs/dashboardTab.vue
@@ -324,11 +324,13 @@ export default {
],
intervalList: [
{ value: 0, label: this.$t('dashboard.dashboard.chartForm.lockList.off') },
+ { value: 5, label: '5s' },
+ { value: 10, label: '10s' },
{ value: 30, label: '30s' },
{ value: 60, label: '1m' },
{ value: 300, label: '5m' },
{ value: 900, label: '15m' },
- { value: 1800, label: '30m' }
+ { value: 1800, label: '30m' },
]
}
},
diff --git a/nezha-fronted/src/components/common/mixin/mainMixinFun.js b/nezha-fronted/src/components/common/mixin/mainMixinFun.js
index fe995bb3e..24356f389 100644
--- a/nezha-fronted/src/components/common/mixin/mainMixinFun.js
+++ b/nezha-fronted/src/components/common/mixin/mainMixinFun.js
@@ -223,7 +223,6 @@ export default {
this.nowTimeType = nowType || this.$refs.pickTime.$refs.timePicker.nowTimeType
const type = nowTimeType.type
const val = nowTimeType.value
- console.log(val)
const oneDTimestamp = 24 * 60 * 60 * 1000
if (type === 'relative') {
const now = new Date(bus.computeTimezone(new Date().getTime()))
diff --git a/nezha-fronted/src/components/common/pickTime.vue b/nezha-fronted/src/components/common/pickTime.vue
index 011ac35c8..66179b7f6 100644
--- a/nezha-fronted/src/components/common/pickTime.vue
+++ b/nezha-fronted/src/components/common/pickTime.vue
@@ -121,6 +121,9 @@ export default {
this.getIntervalData(interval)
}
this.intervalTimer = setInterval(() => {
+ if (document.hidden) {
+ return
+ }
this.getIntervalData(this.interval.value)
}, val.value * 1000)
}
diff --git a/nezha-fronted/src/components/common/rightBox/panelBox.vue b/nezha-fronted/src/components/common/rightBox/panelBox.vue
index 2ac703106..3fea53c30 100644
--- a/nezha-fronted/src/components/common/rightBox/panelBox.vue
+++ b/nezha-fronted/src/components/common/rightBox/panelBox.vue
@@ -514,11 +514,13 @@ export default {
],
intervalList: [
{ value: 0, label: this.$t('dashboard.dashboard.chartForm.lockList.off') },
+ { value: 5, label: '5s' },
+ { value: 10, label: '10s' },
{ value: 30, label: '30s' },
{ value: 60, label: '1m' },
{ value: 300, label: '5m' },
{ value: 900, label: '15m' },
- { value: 1800, label: '30m' }
+ { value: 1800, label: '30m' },
]
}
},
diff --git a/nezha-fronted/src/components/common/timePicker.vue b/nezha-fronted/src/components/common/timePicker.vue
index 041f5fb13..5888b59f4 100644
--- a/nezha-fronted/src/components/common/timePicker.vue
+++ b/nezha-fronted/src/components/common/timePicker.vue
@@ -246,7 +246,6 @@ export default {
this.getUtcStr()
this.getRangeHistoryArr()
const timeTemp = this.$lodash.cloneDeep(this.searchTime)
- console.log(this.searchTime)
this.oldSearchTime[0] = timeTemp[0] || ''
this.oldSearchTime[1] = timeTemp[1] || ''
// 监听dateFormat变化 改变日期格式
diff --git a/nezha-fronted/src/components/page/alert/alertMessage.vue b/nezha-fronted/src/components/page/alert/alertMessage.vue
index ec667455f..4183bcc2b 100644
--- a/nezha-fronted/src/components/page/alert/alertMessage.vue
+++ b/nezha-fronted/src/components/page/alert/alertMessage.vue
@@ -937,7 +937,6 @@ export default {
const path = this.fromRoute.alertMessage
const routePathParams = JSON.parse(JSON.stringify(param))
delete routePathParams.statistics
- console.log(this.searchTime[2])
if (!this.searchTime[2]) {
routePathParams.body.startAt = this.searchTime[0] ? this.momentStrToTimestamp(this.searchTime[0]) : ''
routePathParams.body.endAt = this.searchTime[1] ? this.momentStrToTimestamp(this.searchTime[1]) : ''
@@ -952,7 +951,6 @@ export default {
...this.searchLabel,
body: encodeURIComponent(JSON.stringify(this.searchLabel.body))
}
- console.log(this.searchLabel.body)
this.$get('/alert/message/query', { ...queryParams }).then(response => {
this.tools.loading = false
if (response.code == 200) {
diff --git a/nezha-fronted/src/components/page/dashboard/dashboard.vue b/nezha-fronted/src/components/page/dashboard/dashboard.vue
index e72f6a9a0..0661e445a 100644
--- a/nezha-fronted/src/components/page/dashboard/dashboard.vue
+++ b/nezha-fronted/src/components/page/dashboard/dashboard.vue
@@ -354,11 +354,13 @@ export default {
],
intervalList: [
{ value: 0, label: this.$t('dashboard.dashboard.chartForm.lockList.off') },
+ { value: 5, label: '5s' },
+ { value: 10, label: '10s' },
{ value: 30, label: '30s' },
{ value: 60, label: '1m' },
{ value: 300, label: '5m' },
{ value: 900, label: '15m' },
- { value: 1800, label: '30m' }
+ { value: 1800, label: '30m' },
],
playListControls: false, // 显示隐藏轮播按钮
playlistObj: {} // 轮播仪表盘配置
diff --git a/nezha-fronted/src/components/page/dashboard/explore/exploreItem.vue b/nezha-fronted/src/components/page/dashboard/explore/exploreItem.vue
index ecba8cb5d..f510986b6 100644
--- a/nezha-fronted/src/components/page/dashboard/explore/exploreItem.vue
+++ b/nezha-fronted/src/components/page/dashboard/explore/exploreItem.vue
@@ -3898,7 +3898,6 @@ export default {
this.saveDisabled = false
}
axios.all(requestArr).then(res => {
- console.log(res)
this.chartLoading = false
const errorRowIndex = []
res.forEach((r, i) => {
@@ -4593,7 +4592,6 @@ export default {
}
})
postArr = postArr.filter(item => item.queryValue)
- console.log(postArr)
this.$post('/sys/user/queryHistory', postArr).then(res => {
this.lastHistory = this.$lodash.cloneDeep(postArr)
})
diff --git a/nezha-fronted/src/components/page/dashboard/explore/histoyrComponent/exploreHistory.vue b/nezha-fronted/src/components/page/dashboard/explore/histoyrComponent/exploreHistory.vue
index 835c342a5..0e841a599 100644
--- a/nezha-fronted/src/components/page/dashboard/explore/histoyrComponent/exploreHistory.vue
+++ b/nezha-fronted/src/components/page/dashboard/explore/histoyrComponent/exploreHistory.vue
@@ -133,7 +133,7 @@ export default {
})
},
deleteHistoryItem (item) {
- this.$delete('/sys/user/queryHistory?ids=' + item.id).then(res => {
+ this.$delete('/sys/user/queryHistory?ids=' + item.id + '&queryHash=' + item.queryHash).then(res => {
if (res.code === 200) {
this.$message.success(this.$t('tip.deleteSuccess'))
this.firstLoading = true
diff --git a/nezha-fronted/src/components/page/dashboard/explore/queryPrompt/queryPrompt.vue b/nezha-fronted/src/components/page/dashboard/explore/queryPrompt/queryPrompt.vue
index 720421f60..fb49dbfc2 100644
--- a/nezha-fronted/src/components/page/dashboard/explore/queryPrompt/queryPrompt.vue
+++ b/nezha-fronted/src/components/page/dashboard/explore/queryPrompt/queryPrompt.vue
@@ -301,7 +301,9 @@ export default {
}
str += ','
})
- str = str.slice(0, -1)
+ if (str.length !== 1) {
+ str = str.slice(0, -1)
+ }
str += '}'
this.logFinalStr = str
},
diff --git a/nezha-fronted/src/entrance/app/main.js b/nezha-fronted/src/entrance/app/main.js
index 1cdaa28cf..0d9f5d4f7 100644
--- a/nezha-fronted/src/entrance/app/main.js
+++ b/nezha-fronted/src/entrance/app/main.js
@@ -5,6 +5,7 @@ import '@/assets/css/main.scss'
import '@/assets/css/animate.css'
import '@/assets/css/font/iconfont.js'
import 'intro.js/introjs.css'
+import 'uplot/dist/uPlot.min.css'
import Pace from 'pace-js'
import ElementUI from 'element-ui'
import i18n from '@/components/common/i18n'
diff --git a/nezha-fronted/src/entrance/exportHtml/exportHtml.js b/nezha-fronted/src/entrance/exportHtml/exportHtml.js
index ae6fe9615..050ff2881 100644
--- a/nezha-fronted/src/entrance/exportHtml/exportHtml.js
+++ b/nezha-fronted/src/entrance/exportHtml/exportHtml.js
@@ -5,6 +5,7 @@ import '@/assets/css/main.scss'
import '@/assets/css/font/iconfont.js'
import ElementUI from 'element-ui'
import i18n from '@/components/common/i18n'
+import 'uplot/dist/uPlot.min.css'
import Vue from 'vue'
import Vuex from 'vuex'