fix:添加曲线平滑 以及选中的圆点加粗

This commit is contained in:
zhangyu
2023-11-09 17:49:27 +08:00
parent 1396310b29
commit a91d866fce
4 changed files with 143 additions and 35 deletions

View File

@@ -162,7 +162,6 @@ export default {
methods: { methods: {
initChart (chartOptions = this.chartOption) { initChart (chartOptions = this.chartOption) {
this.setDataLink() this.setDataLink()
console.log(this.chartInfo.param)
try { try {
this.isStack = !!this.chartInfo.param.stack this.isStack = !!this.chartInfo.param.stack
} catch (e) {} } catch (e) {}
@@ -177,9 +176,18 @@ export default {
const cursLeft = -10 const cursLeft = -10
const cursTop = -10 const cursTop = -10
const { seriesData, seriesAll } = this.initSeriesData(this.chartData) 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) // .compute(minusVal, null, -1, decimals)
const opts = { let opts = {
id: `chart-canvas-${this.chartId}-uplot`, id: `chart-canvas-${this.chartId}-uplot`,
mode: 1,
width: 100, width: 100,
height: 100, height: 100,
cursor: { cursor: {
@@ -188,6 +196,45 @@ export default {
}, },
drag: { drag: {
x: true 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: [ plugins: [
@@ -202,18 +249,34 @@ export default {
show: false show: false
}, },
series: [ series: [
{} {
scale: 'x'
}
], ],
tzDate: ts => UPlot.tzDate(new Date(ts * 1e3), localStorage.getItem('nz-sys-timezone')), tzDate: ts => UPlot.tzDate(new Date(ts * 1e3), localStorage.getItem('nz-sys-timezone')),
fmtDate: () => { fmtDate: () => {
return self.xAxisLabelFormatter(seriesData[0][0], seriesData[0][seriesData[0].length - 1]) return self.xAxisLabelFormatter(seriesData[0][0], seriesData[0][seriesData[0].length - 1])
}, },
axes: [ axes: [
{}, {
scale: 'x',
gap: 5,
grid: {
show: true,
stroke: 'rgba(0, 10, 23, 0.09)',
width: 1
}
},
{ {
scale: 'left', scale: 'left',
values: (u, vals, space) => vals.map(v => leftUnitCompute.compute(v, null, -1, decimals)), values: (u, vals, space) => vals.map(v => leftUnitCompute.compute(v, null, -1, decimals)),
incrs: incrs, incrs: incrs,
gap: 5,
grid: {
show: true,
stroke: 'rgba(0, 10, 23, 0.09)',
width: 1
},
// space: (self) => { // space: (self) => {
// console.log(self) // console.log(self)
// return 50 // return 50
@@ -242,8 +305,13 @@ export default {
{ {
show: true, show: true,
side: 1, side: 1,
grid: { show: false }, grid: {
show: false,
stroke: 'rgba(0, 10, 23, 0.09)',
width: 1
},
scale: 'right', scale: 'right',
gap: 5,
// space: (self) => { // space: (self) => {
// console.log(self) // console.log(self)
// return 50 // return 50
@@ -252,17 +320,52 @@ export default {
incrs: rightIncrs, incrs: rightIncrs,
ticks: { ticks: {
show: false // true 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: { scales: {
x: {
key: 'x',
auto: true,
ori: 0,
dir: 1,
time: true
},
left: { left: {
key: 'left', key: 'left',
time: false time: false,
auto: true,
ori: 1,
dir: 1,
distr: 1
}, },
right: { right: {
key: 'right', key: 'right',
time: false time: false,
auto: true,
ori: 1,
dir: 1,
distr: 1
} }
} }
} }
@@ -273,10 +376,12 @@ export default {
scales: [null, null] scales: [null, null]
} }
} }
const data = this.seriesData = seriesData let data = this.seriesData = seriesData
opts.series.push(...seriesAll) opts.series.push(...seriesAll)
if (this.isStack) { if (this.isStack) {
getStackedOpts('', opts, data) const obj = getStackedOpts('', opts, data)
opts = obj.opts
data = obj.data
} }
this.renderMinMax(opts) this.renderMinMax(opts)
if (getChart(this.chartId)) { if (getChart(this.chartId)) {
@@ -294,7 +399,6 @@ export default {
}, 100) }, 100)
}, },
renderMinMax (opts) { renderMinMax (opts) {
console.log(opts)
let leftMin = this.$lodash.get(this.chartInfo, 'param.min', undefined) let leftMin = this.$lodash.get(this.chartInfo, 'param.min', undefined)
let leftMax = this.$lodash.get(this.chartInfo, 'param.max', undefined) let leftMax = this.$lodash.get(this.chartInfo, 'param.max', undefined)
if (leftMin || leftMax) { if (leftMin || leftMax) {
@@ -454,7 +558,6 @@ export default {
}, },
resize () { resize () {
setTimeout(() => { setTimeout(() => {
console.log('chartMixinnz')
const dom = this.$refs['timeSeries-chart-box'] const dom = this.$refs['timeSeries-chart-box']
const width = dom.offsetWidth const width = dom.offsetWidth
const legendHeight = this.$lodash.get(this.$refs, 'legend.$el.offsetHeight', 40) const legendHeight = this.$lodash.get(this.$refs, 'legend.$el.offsetHeight', 40)

View File

@@ -6,6 +6,7 @@ import { formatScientificNotation, getMetricTypeValue } from '@/components/commo
import bus from '@/libs/bus' import bus from '@/libs/bus'
import moment from 'moment-timezone' import moment from 'moment-timezone'
import { getChart } from '@/components/common/js/common' import { getChart } from '@/components/common/js/common'
import uplot from 'uplot'
export default { export default {
data () { data () {
return { return {
@@ -68,6 +69,9 @@ export default {
item.statistics = statistics item.statistics = statistics
item.values.forEach(value => { item.values.forEach(value => {
let itemValue = value[1] let itemValue = value[1]
if (!isNaN(itemValue)) {
itemValue = Number(itemValue)
}
if (itemValue === null && nullValueMode !== 'null') { if (itemValue === null && nullValueMode !== 'null') {
if (nullValueMode === 'zero') { if (nullValueMode === 'zero') {
itemValue = 0 itemValue = 0
@@ -103,24 +107,28 @@ export default {
this.seriesColor.push(randomcolor()) this.seriesColor.push(randomcolor())
} }
const legend = this.handleLegend(this.chartInfo, series, expressionIndex, dataIndex, chartIndex) const legend = this.handleLegend(this.chartInfo, series, expressionIndex, dataIndex, chartIndex)
let isRight = false let isRight
if (this.chartInfo.param.enable.rightYAxis) { if (this.chartInfo.param.enable.rightYAxis) {
const elementNames = this.$lodash.get(this.chartInfo, 'param.rightYAxis.elementNames', []) const elementNames = this.$lodash.get(this.chartInfo, 'param.rightYAxis.elementNames', [])
isRight = elementNames.indexOf(series.elements.name) !== -1 isRight = elementNames.indexOf(series.elements.name) !== -1 ? 1 : 0
} }
const name = legend.name const name = legend.name
const alias = legend.alias const alias = legend.alias
const statistics = series.statistics const statistics = series.statistics
const chartType = this.chartInfo.type const chartType = this.chartInfo.type
const obj = { const obj = {
name: name, name: name,
label: alias, label: alias,
scale: isRight ? 'right' : 'left', // right scale: isRight ? 'right' : 'left', // right
yAxisIndex: isRight ? 1 : 0, // right yAxisIndex: isRight, // right
values: (u, v) => series.elements.name + JSON.stringify(series.metric), // values: (u, v) => series.elements.name + JSON.stringify(series.metric),
stroke: this.seriesColor[chartIndex], stroke: this.seriesColor[chartIndex],
width: 1 / devicePixelRatio, width: 1 / devicePixelRatio,
expressionIndex: series.expressionIndex expressionIndex: series.expressionIndex,
paths (taht, seriesIdx, idx0, idx1, filtIdxs) {
return uplot.paths.spline(taht)(taht, seriesIdx, idx0, idx1, filtIdxs)
}
} }
if (chartType === 'area') { if (chartType === 'area') {
obj.fill = this.seriesColor[chartIndex] + '20' // 面积图使用 obj.fill = this.seriesColor[chartIndex] + '20' // 面积图使用
@@ -128,7 +136,10 @@ export default {
if (chartType === 'point') { if (chartType === 'point') {
obj.points = { obj.points = {
show: true, show: true,
width: 2 size: 6,
width: 3,
fill: this.seriesColor[chartIndex],
stroke: this.seriesColor[chartIndex]
} }
obj.width = 0 obj.width = 0
} }

View File

@@ -7,10 +7,18 @@ function stack (data, omit) {
for (let i = 0; i < d0Len; i++) { accum[i] = 0 } for (let i = 0; i < d0Len; i++) { accum[i] = 0 }
for (let i = 1; i < data.length; i++) { data2.push(omit(i) ? data[i] : data[i].map((v, i) => (accum[i] += +v))) } 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++) { for (let i = 1; i < data.length; i++) {
!omit(i) && bands.push({ !omit(i) && bands.push({
dir: -1,
series: [ series: [
data.findIndex((s, j) => j > i && !omit(j)), data.findIndex((s, j) => j > i && !omit(j)),
i i
@@ -19,7 +27,8 @@ function stack (data, omit) {
} }
bands = bands.filter(b => b.series[1] > -1) bands = bands.filter(b => b.series[1] > -1)
bands = bands.filter(b => b.series[0] > -1)
bands = bands.reverse()
return { return {
data: [data[0]].concat(data2), data: [data[0]].concat(data2),
bands bands
@@ -34,25 +43,9 @@ export default function getStackedOpts (title, opt, data, interp) {
opts.bands = stacked.bands opts.bands = stacked.bands
opts.cursor = opts.cursor || {} opts.cursor = opts.cursor || {}
opts.cursor.dataIdx = (u, seriesIdx, closestIdx, xValue) => {
return data[seriesIdx][closestIdx] == null ? null : closestIdx
}
opts.series.forEach(s => { opts.series.forEach(s => {
s.value = (u, v, si, i) => data[si][i] s.value = (u, v, si, i) => data[si][i]
s.points = s.points || {}
// scan raw unstacked data to return only real points
s.points.filter = (u, seriesIdx, show, gaps) => {
if (show) {
const pts = []
data[seriesIdx].forEach((v, i) => {
v != null && pts.push(i)
})
return pts
}
}
}) })
// restack on toggle // restack on toggle
opts.hooks = { opts.hooks = {

View File

@@ -5,6 +5,7 @@ import '@/assets/css/main.scss'
import '@/assets/css/font/iconfont.js' import '@/assets/css/font/iconfont.js'
import ElementUI from 'element-ui' import ElementUI from 'element-ui'
import i18n from '@/components/common/i18n' import i18n from '@/components/common/i18n'
import 'uplot/dist/uPlot.min.css'
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'