NEZ-2528 feat:dashboard时序图表支持双Y轴 页面开发

This commit is contained in:
zyh
2023-02-08 13:49:50 +08:00
parent 642d3a78e3
commit acc5263092
18 changed files with 657 additions and 260 deletions

View File

@@ -458,6 +458,12 @@ td .nz-icon-gear:before {
visibility: hidden; visibility: hidden;
position: absolute; position: absolute;
} }
.yAxis-icon{
margin-right: 4px;
background: transparent !important;
}
.loading-hide { .loading-hide {
display: none; display: none;
} }

View File

@@ -378,6 +378,10 @@
.legend-shape { .legend-shape {
background-color: $--background-color-1 !important; background-color: $--background-color-1 !important;
} }
.nz-icon{
color: $--background-color-1 !important;
}
} }
} }
@@ -425,6 +429,7 @@
text-overflow: ellipsis; text-overflow: ellipsis;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center;
min-width: 150px; min-width: 150px;
max-width: 600px; max-width: 600px;
line-height: 18px; line-height: 18px;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -5,6 +5,34 @@
"css_prefix_text": "nz-icon-", "css_prefix_text": "nz-icon-",
"description": "", "description": "",
"glyphs": [ "glyphs": [
{
"icon_id": "33998082",
"name": "右纵轴",
"font_class": "youzongzhou",
"unicode": "e7ce",
"unicode_decimal": 59342
},
{
"icon_id": "33998083",
"name": "左纵轴",
"font_class": "zuozongzhou",
"unicode": "e7cf",
"unicode_decimal": 59343
},
{
"icon_id": "33991102",
"name": "全部收起",
"font_class": "quanbushouqi",
"unicode": "e7cc",
"unicode_decimal": 59340
},
{
"icon_id": "33991103",
"name": "全部展开",
"font_class": "quanbuzhankai",
"unicode": "e7cd",
"unicode_decimal": 59341
},
{ {
"icon_id": "33693407", "icon_id": "33693407",
"name": "普通文件", "name": "普通文件",

File diff suppressed because one or more lines are too long

View File

@@ -4,7 +4,13 @@
class="nz-chart__component nz-chart__component--time-series" @mouseenter="mouseEnterChart" class="nz-chart__component nz-chart__component--time-series" @mouseenter="mouseEnterChart"
@mouseleave="mouseLeaveChart" @mouseleave="mouseLeaveChart"
> >
<div :id="`chart-canvas-${chartId}`" class="chart__canvas"></div> <div class="chart__canvas" style="position:relative">
<div :id="`chart-canvas-${chartId}`"></div>
<!-- 右y轴name -->
<p class="rightYAxis-name" v-if="hasRightYAxis">
<span>{{chartInfo.param.rightYAxis.label}}</span>
</p>
</div>
<chart-legend <chart-legend
v-if="hasLegend" v-if="hasLegend"
:chart-data="chartData" :chart-data="chartData"
@@ -43,7 +49,9 @@ export default {
data () { data () {
return { return {
stackTotalColor: null, stackTotalColor: null,
isStack: false stackTotalColorRight: null,
isStack: false,
hasRightYAxis: false
} }
}, },
computed: { computed: {
@@ -136,21 +144,25 @@ export default {
chartOption.tooltip.appendToBody = false chartOption.tooltip.appendToBody = false
delete chartOption.tooltip.position delete chartOption.tooltip.position
} }
chartOption.yAxis.axisLabel.formatter = this.yAxisLabelFormatter(minValue, maxValue, copies, unit, decimals) // 左y轴
chartOption.yAxis[0].axisLabel.formatter = this.yAxisLabelFormatter(minValue, maxValue, copies, unit, decimals)
if (!this.chartInfo.param.min && !this.chartInfo.param.max) { chartOption.yAxis[0].min = this.chartInfo.param.min ? this.chartInfo.param.min : undefined
chartOption.yAxis.minInterval = chartDataFormat.Interval(maxValue, copies, unit.type, 'min') chartOption.yAxis[0].max = this.chartInfo.param.max ? this.chartInfo.param.max : undefined
chartOption.yAxis.maxInterval = chartDataFormat.Interval(maxValue, copies, unit.type, 'max') * Math.ceil(chartOption.series.length / 5)
if (this.chartInfo.param.stack) { // 右y轴
chartOption.yAxis.maxInterval = chartOption.yAxis.maxInterval * (Math.ceil(chartOption.series.length / 5) + 1) if (this.chartInfo.param.enable.rightYAxis) {
} // 如果全都为右y轴数据 则右y轴显示网格
if (unit.type === 'Time' || unit.type === 'Date & Time') { const allRight = this.series.every(item => item.yAxisIndex == 1)
delete chartOption.yAxis.minInterval chartOption.yAxis[1].splitLine.show = allRight
delete chartOption.yAxis.maxInterval
} const unit = chartDataFormat.getUnit(lodash.get(this, 'chartInfo.param.rightYAxis.unit', 2))
} else { chartOption.yAxis[1].axisLabel.formatter = this.yAxisLabelFormatter(undefined, undefined, undefined, unit, decimals)
chartOption.yAxis.min = this.chartInfo.param.min ? this.chartInfo.param.min : undefined chartOption.yAxis[1].min = this.chartInfo.param.rightYAxis.min ? this.chartInfo.param.rightYAxis.min : undefined
chartOption.yAxis.max = this.chartInfo.param.max ? this.chartInfo.param.max : undefined chartOption.yAxis[1].max = this.chartInfo.param.rightYAxis.max ? this.chartInfo.param.rightYAxis.max : undefined
// 有右y轴数据则显示name
this.hasRightYAxis = this.series.some(item => item.yAxisIndex == 1)
} }
if (chartOption.toolbox.feature) { if (chartOption.toolbox.feature) {
@@ -166,7 +178,6 @@ export default {
myChart.clear() myChart.clear()
myChart.setOption(chartOption) myChart.setOption(chartOption)
this.isInit && setChart(this.chartId, myChart) // 缓存不使用vue的data是为避免整个chart被监听导致卡顿 this.isInit && setChart(this.chartId, myChart) // 缓存不使用vue的data是为避免整个chart被监听导致卡顿
this.$store.commit('setCurrentMousemove', 0) this.$store.commit('setCurrentMousemove', 0)
if (this.isInit && !this.isFullscreen) { if (this.isInit && !this.isFullscreen) {
// timeSeries类型图表设置group 用于多表联动 // timeSeries类型图表设置group 用于多表联动
@@ -181,72 +192,6 @@ export default {
} }
}) })
} }
const self = this
getChart(this.chartId).off('dataZoom')
getChart(this.chartId).on('dataZoom', function (params) {
if (this.chartInfo.param.min || this.chartInfo.param.max) {
return
}
if (params.batch[0].startValue) {
const chartInfo = self.chartInfo
const dataArg = self.$loadsh.cloneDeep(self.series)
dataArg.forEach(item => {
item.data = item.data.filter(value => value[0] > params.batch[0].startValue && value[0] < params.batch[0].endValue)
})
const maxValueCopies = self.getMaxValue(dataArg, chartInfo)
const maxValue = maxValueCopies.maxValue
const copies = maxValueCopies.copies
const unit = maxValueCopies.unit
const option = {
yAxis: {
minInterval: chartDataFormat.Interval(maxValue, copies, unit.type, 'min'),
maxInterval: chartDataFormat.Interval(maxValue, copies, unit.type, 'max') * Math.ceil(dataArg.length / 5)
}
}
if (!maxValueCopies.copies) {
option.yAxis.min = 0
option.yAxis.max = 1
} else {
option.yAxis.max = undefined
}
if (unit.type == 'Time' || option.yAxis.maxInterval === 1) {
delete option.yAxis.maxInterval
}
getChart(self.chartId) && getChart(self.chartId).setOption({
yAxis: {
...option.yAxis
}
})
} else {
// 处理点击后的 Y轴
const chartInfo = self.chartInfo
const dataArg = self.series
const maxValueCopies = self.getMaxValue(dataArg, chartInfo)
const maxValue = maxValueCopies.maxValue
const copies = maxValueCopies.copies
const unit = maxValueCopies.unit
const option = {
yAxis: {
minInterval: chartDataFormat.Interval(maxValue, copies, unit.type, 'min'),
maxInterval: chartDataFormat.Interval(maxValue, copies, unit.type, 'max') * Math.ceil(dataArg.length / 5)
}
}
if (!maxValueCopies.copies) {
option.yAxis.min = 0
option.yAxis.max = 1
} else {
option.yAxis.max = undefined
}
if (unit.type == 'Time' || option.yAxis.maxInterval === 1) {
delete option.yAxis.maxInterval
}
getChart(self.chartId) && getChart(self.chartId).setOption({
yAxis: {
...option.yAxis
}
})
}
})
this.isInit = false this.isInit = false
}, 200) }, 200)
}, },
@@ -369,32 +314,74 @@ export default {
return function (params) { return function (params) {
const decimals = self.chartInfo.param.decimals || 2 const decimals = self.chartInfo.param.decimals || 2
let str = '<div class="nz-chart__tooltip">' let str = '<div class="nz-chart__tooltip">'
// 区分左y轴右y轴
params.forEach(item => {
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
}
let sum = 0 let sum = 0
let flag = true let flag = true
params.forEach((item, i) => { 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('-') const nameArr = item.seriesName.split('-')
if (nameArr.length > 1) { if (nameArr.length > 1) {
nameArr.splice(nameArr.length - 1, 1) nameArr.splice(nameArr.length - 1, 1)
} }
const seriesName = nameArr.join('-') const seriesName = nameArr.join('-')
if (i === 0 && item.seriesName.indexOf('Previous') === -1) { if (i === 0 && item.seriesName.indexOf('Previous') === -1 && type == 'left') {
const value = bus.computeTimezone(item.data[0] * 1000) const value = bus.computeTimezone(item.data[0] * 1000)
const tData = new Date(value) const tData = new Date(value)
str += '<div class="tooltip-title" style="margin-bottom: 5px">' str += '<div class="tooltip-title" style="margin-bottom: 5px">'
str += bus.timeFormate(tData) str += bus.timeFormate(tData)
str += '</div>' 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.data[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) { if (flag && item.seriesName.indexOf('Previous') !== -1) {
flag = false flag = false
const value = bus.computeTimezone(item.data[0] * 1000 - self.minusTime) const value = bus.computeTimezone(item.data[0] * 1000 - self.minusTime)
const tData = new Date(value) const tData = new Date(value)
str += '<div style="border: 1px solid #EEEEEE"></div>' str += '<div class="tooltip-title" style="margin-bottom: 5px">'
str += '<div class="tooltip-title" style="margin-top: 5px;margin-bottom: 5px">'
str += bus.timeFormate(tData) str += bus.timeFormate(tData)
str += '</div>' str += '</div>'
} }
const color = self.colorList[item.seriesIndex] const color = self.colorList[item.seriesIndex]
const previousItem = params.find((series) => ('Previous ' + item.seriesName) === series.seriesName) const previousItem = arr.find((series) => ('Previous ' + item.seriesName) === series.seriesName)
let paramsDot = bus.countDecimals(item.data[1]) let paramsDot = bus.countDecimals(item.data[1])
if (paramsDot < self.chartDot) { if (paramsDot < self.chartDot) {
paramsDot = self.chartDot paramsDot = self.chartDot
@@ -416,40 +403,67 @@ export default {
operator = '-' operator = '-'
} }
previousDom = ` previousDom = `
<span>${operator}${chartDataFormat.getUnit(self.chartInfo.unit ? self.chartInfo.unit : 2).compute(minusVal, null, -1, decimals)}</span> <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'
}
str += ` str += `
<div class="tooltip__row"> <div class="tooltip__row">
<div class="row__label"> <div class="row__label">
<span class="row__color-block" style="background-color: ${color}"></span> <span class="${className}" style="background-color: ${color};color: ${color}"></span>
<span>${seriesName}</span> <span>${seriesName}</span>
</div> </div>
<div class="row__value"> <div class="row__value">
<span>${chartDataFormat.getUnit(self.chartInfo.unit ? self.chartInfo.unit : 2).compute(val, null, -1, decimals)}</span> <span>${chartDataFormat.getUnit(unit).compute(val, null, -1, decimals)}</span>
${previousDom} ${previousDom}
</div> </div>
</div> </div>
` `
}) })
// 显示total
if (hasTotal) { 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) { if (!self.stackTotalColor) {
self.stackTotalColor = randomcolor() self.stackTotalColor = randomcolor()
} }
sum = parseFloat(Number(sum).toFixed(2)) 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 += ` str += `
<div class="tooltip__row"> <div class="tooltip__row">
<div class="row__label"> <div class="row__label">
<span class="row__color-block" style="background-color: ${self.stackTotalColor}"></span> <span class="${className}" style="background-color: ${color};color: ${color}"></span>
<span>${self.$t('dashboard.panel.chartTotal')}</span> <span>${self.$t('dashboard.panel.chartTotal')}</span>
</div> </div>
<div class="row__value"> <div class="row__value">
<span>${chartDataFormat.getUnit(self.chartInfo.unit ? self.chartInfo.unit : 2).compute(sum, null, decimals)}</span> <span>${chartDataFormat.getUnit(unit).compute(sum, null, decimals)}</span>
</div> </div>
</div> </div>
` `
} }
}
str += '</div>' str += '</div>'
return str return str
@@ -473,18 +487,11 @@ export default {
option.toolbox[0].feature.myStack.iconStyle.borderColor = self.isStack ? self.toolboxIconColor.inactive : self.toolboxIconColor.active option.toolbox[0].feature.myStack.iconStyle.borderColor = self.isStack ? self.toolboxIconColor.inactive : self.toolboxIconColor.active
// 切换stack状态 // 切换stack状态
option.series.forEach((s, i) => { option.series.forEach((s, i) => {
self.isStack ? (s.stack = i) : (s.stack = 'Total') self.isStack ? (s.stack = i) : (s.stack = 'Total' + s.yAxisIndex)
}) })
self.isStack = !self.isStack self.isStack = !self.isStack
// 改变tooltip // 改变tooltip
option.tooltip[0].formatter = self.tooltipFormatter(self.isStack) option.tooltip[0].formatter = self.tooltipFormatter(self.isStack)
if (!self.chartInfo.param.min && !self.chartInfo.param.max) {
if (!self.chartInfo.param.stack) {
option.yAxis.maxInterval = option.yAxis.maxInterval / (Math.ceil(option.series.length / 5) + 1)
} else {
option.yAxis.maxInterval = option.yAxis.maxInterval * (Math.ceil(option.series.length / 5) + 1)
}
}
myChart.setOption(option) myChart.setOption(option)
} }
}, },
@@ -492,6 +499,22 @@ export default {
setTimeout(() => { setTimeout(() => {
getChart(this.chartId) && getChart(this.chartId).resize() getChart(this.chartId) && getChart(this.chartId).resize()
}, 100) }, 100)
},
legendChange (isGrey) {
let flag = false
// 点击legend 如果右y轴数据有一个不是灰色 则显示右y轴name
isGrey.forEach((item, index) => {
if (this.series[index].yAxisIndex == 1 && item == false) {
flag = true
}
})
this.hasRightYAxis = flag
const myChart = getChart(this.chartId)
const option = myChart.getOption()
if (option.yAxis[1].min && option.yAxis[1].max) {
this.hasRightYAxis = true
}
} }
}, },
mounted () { mounted () {
@@ -504,3 +527,25 @@ export default {
} }
} }
</script> </script>
<style lang="scss" scoped>
.rightYAxis-name{
position: absolute;
top: 0;
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
line-height: 100%;
margin-left: calc(50% - 18px);
font-size: 12px;
color:#666666;
pointer-events:none;
span{
transform: rotate(90deg);
font-family: sans-serif;
}
}
</style>

View File

@@ -10,30 +10,110 @@
<span v-else>--</span> <span v-else>--</span>
</div> </div>
</div> </div>
<div v-for="(item, index) in legends" <!-- 左y轴legend -->
<div
v-for="(item, index) in legends"
:key="index" :key="index"
v-show="series[index].yAxisIndex!=1"
:class="{'row--inactive': isGrey[index]}" :class="{'row--inactive': isGrey[index]}"
class="legend--table-row" class="legend--table-row"
@click="clickLegend(item.name, index)" @click="clickLegend(item.name, index)"
> >
<div :title="item.alias ? item.alias : item.name" class="legend--table-cell"> <div :title="item.alias ? item.alias : item.name" class="legend--table-cell">
<span :style="{background: item.color}" class="legend-shape"></span>{{item.alias ? item.alias : item.name}} <i v-if="series[index].yAxisIndex==0" :style="{color: item.color}" class="yAxis-icon nz-icon nz-icon-zuozongzhou"></i>
<span v-else :style="{background: item.color}" class="legend-shape"></span>
<span>{{item.alias ? item.alias : item.name}}</span>
</div>
<div v-for="(statistics, index) in item.statistics" :key="index" :class="{'legend-item--inactive': isGrey[index]}" class="legend--table-cell">{{(keepTwoDecimalFull(statistics.value))}}</div>
</div>
<!-- 右y轴legend -->
<div
v-for="(item, index) in legends"
:key="index+'right'"
v-show="series[index].yAxisIndex==1"
:class="{'row--inactive': isGrey[index]}"
class="legend--table-row"
@click="clickLegend(item.name, index)"
>
<div :title="item.alias ? item.alias : item.name" class="legend--table-cell">
<i v-if="series[index].yAxisIndex==1" :style="{color: item.color}" class="yAxis-icon nz-icon nz-icon-youzongzhou"></i>
<span v-else :style="{background: item.color}" class="legend-shape"></span>
<span>{{item.alias ? item.alias : item.name}}</span>
</div> </div>
<div v-for="(statistics, index) in item.statistics" :key="index" :class="{'legend-item--inactive': isGrey[index]}" class="legend--table-cell">{{(keepTwoDecimalFull(statistics.value))}}</div> <div v-for="(statistics, index) in item.statistics" :key="index" :class="{'legend-item--inactive': isGrey[index]}" class="legend--table-cell">{{(keepTwoDecimalFull(statistics.value))}}</div>
</div> </div>
</div> </div>
</template> </template>
<!-- 否则是普通形式 --> <!-- placement=bottom -->
<template v-else> <template v-else-if="chartInfo.param.legend.placement=='bottom'">
<div <div class="legend-box">
<div style="display:flex">
<!-- 左y轴legend -->
<ul>
<li
v-for="(item, index) in legends" v-for="(item, index) in legends"
:key="index" :key="index"
v-show="series[index].yAxisIndex!=1"
:class="{'legend-item--inactive': isGrey[index]}" :class="{'legend-item--inactive': isGrey[index]}"
:title="item.alias ? item.alias : item.name" :title="item.alias ? item.alias : item.name"
class="legend-item" class="legend-item"
@click="clickLegend(item.name, index)" @click="clickLegend(item.name, index)"
> >
<span :style="{background: item.color}" class="legend-shape"></span>{{item.alias ? item.alias : item.name.split('-')[0]}} <i v-if="series[index].yAxisIndex==0" :style="{color: item.color}" class="yAxis-icon nz-icon nz-icon-zuozongzhou"></i>
<span v-else :style="{background: item.color}" class="legend-shape"></span>
<span>{{item.alias ? item.alias : item.name.split('-')[0]}}</span>
</li>
</ul>
</div>
<!-- 右y轴legend -->
<div class="rightYAxis">
<ul>
<li
v-for="(item, index) in legends"
:key="index+'right'"
v-show="series[index].yAxisIndex==1"
:class="{'legend-item--inactive': isGrey[index]}"
:title="item.alias ? item.alias : item.name"
class="legend-item"
@click="clickLegend(item.name, index)"
>
<i v-if="series[index].yAxisIndex==1" :style="{color: item.color}" class="yAxis-icon nz-icon nz-icon-youzongzhou"></i>
<span v-else :style="{background: item.color}" class="legend-shape"></span>
<span>{{item.alias ? item.alias : item.name.split('-')[0]}}</span>
</li>
</ul>
</div>
</div>
</template>
<!-- 否则是普通形式 -->
<template v-else>
<!-- 左y轴legend -->
<div
v-for="(item, index) in legends"
:key="index"
v-show="series[index].yAxisIndex!=1"
:class="{'legend-item--inactive': isGrey[index]}"
:title="item.alias ? item.alias : item.name"
class="legend-item"
@click="clickLegend(item.name, index)"
>
<i v-if="series[index].yAxisIndex==0" :style="{color: item.color}" class="yAxis-icon nz-icon nz-icon-zuozongzhou"></i>
<span v-else :style="{background: item.color}" class="legend-shape"></span>
<span>{{item.alias ? item.alias : item.name.split('-')[0]}}</span>
</div>
<!-- 右y轴legend -->
<div
v-for="(item, index) in legends"
:key="index+'right'"
v-show="series[index].yAxisIndex==1"
:class="{'legend-item--inactive': isGrey[index]}"
:title="item.alias ? item.alias : item.name"
class="legend-item"
@click="clickLegend(item.name, index)"
>
<i v-if="series[index].yAxisIndex==1" :style="{color: item.color}" class="yAxis-icon nz-icon nz-icon-youzongzhou"></i>
<span v-else :style="{background: item.color}" class="legend-shape"></span>
<span>{{item.alias ? item.alias : item.name.split('-')[0]}}</span>
</div> </div>
</template> </template>
</div> </div>
@@ -126,43 +206,13 @@ export default {
}) })
this.$set(this.isGrey, index, !this.isGrey[index]) this.$set(this.isGrey, index, !this.isGrey[index])
} }
if (isTimeSeries(this.chartInfo.type)) {
this.$parent.legendChange(this.isGrey)
}
// 判断timeSeries类型图表 建立多表联动 // 判断timeSeries类型图表 建立多表联动
if (isTimeSeries(this.chartInfo.type) && (this.isConnect && this.isConnect !== 'none')) { if (isTimeSeries(this.chartInfo.type) && (this.isConnect && this.isConnect !== 'none')) {
chart.connect('timeSeriesGroup') chart.connect('timeSeriesGroup')
} }
if (this.chartInfo.type == 'line' || this.chartInfo.type == 'area' || this.chartInfo.type == 'point') {
if (this.chartInfo.param.min || this.chartInfo.param.max) {
return
}
// 处理点击后的 Y轴
const chartInfo = this.chartInfo
const dataArg = this.series.filter((seriesItem, seriesIndex) => !this.isGrey[seriesIndex])
const maxValueCopies = this.getMaxValue(dataArg, chartInfo)
const maxValue = maxValueCopies.maxValue
const copies = maxValueCopies.copies
const unit = maxValueCopies.unit
const option = {
yAxis: {
minInterval: chartDataFormat.Interval(maxValue, copies, unit.type, 'min'),
maxInterval: chartDataFormat.Interval(maxValue, copies, unit.type, 'max') * Math.ceil(dataArg.length / 5)
}
}
if (!maxValueCopies.copies) {
option.yAxis.min = 0
option.yAxis.max = 1
} else {
option.yAxis.max = undefined
}
if (unit.type == 'Time' || option.yAxis.maxInterval === 1) {
delete option.yAxis.maxInterval
}
getChart(this.chartId) && getChart(this.chartId).setOption({
yAxis: {
...option.yAxis
}
})
}
} }
}, },
clickLegendBar (legendName, index, hasGrey, curIsGrey, currentIsTheOnlyOneHighlight) { clickLegendBar (legendName, index, hasGrey, curIsGrey, currentIsTheOnlyOneHighlight) {
@@ -302,5 +352,15 @@ export default {
</script> </script>
<style scoped> <style scoped>
.legend-box{
width: 100%;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
.rightYAxis{
display: flex;
justify-content: flex-end;
flex-grow: 1;
}
</style> </style>

View File

@@ -85,7 +85,9 @@ export const chartTimeSeriesLineOption = {
show: false show: false
} }
}, },
yAxis: { yAxis: [
{
name: '',
type: 'value', type: 'value',
splitLine: { splitLine: {
show: true, show: true,
@@ -108,6 +110,31 @@ export const chartTimeSeriesLineOption = {
// formatter: 动态生成 // formatter: 动态生成
} }
}, },
{
name: '',
type: 'value',
splitLine: {
show: false,
lineStyle: {
color: '#d9d9d9',
opacity: 0.8,
width: 1
}
},
// 去掉y轴
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
show: true,
fontSize: 10
// formatter: 动态生成
}
}
],
series: [{ series: [{
name: '', name: '',
type: 'line', type: 'line',

View File

@@ -72,6 +72,17 @@ export default {
} }
this.isNoData = false this.isNoData = false
const s = lodash.cloneDeep(seriesTemplate) const s = lodash.cloneDeep(seriesTemplate)
// 设置右y轴
if (chartInfo.param.enable.rightYAxis) {
s.yAxisIndex = 0
chartInfo.param.rightYAxis && chartInfo.param.rightYAxis.elementNames.forEach(item => {
if (data.elements.name == item) {
s.yAxisIndex = 1
}
})
}
if (s.param && s.param.nullType) { if (s.param && s.param.nullType) {
s.connectNulls = s.param.nullType !== 'null' s.connectNulls = s.param.nullType !== 'null'
} else { } else {
@@ -81,13 +92,15 @@ export default {
s.data = data.values s.data = data.values
s.name = this.handleLegend(chartInfo, data, expressionIndex, dataIndex, colorIndex).name s.name = this.handleLegend(chartInfo, data, expressionIndex, dataIndex, colorIndex).name
if (chartInfo.param.stack) { // 堆叠 if (chartInfo.param.stack) { // 堆叠
s.stack = 'Total' s.stack = 'Total' + s.yAxisIndex
} }
if (chartInfo.param.enable && chartInfo.param.enable.thresholds && !lodash.isEmpty(chartInfo.param.thresholds) && chartInfo.param.thresholds.length) { // 阈值 if (chartInfo.param.enable && chartInfo.param.enable.thresholds && !lodash.isEmpty(chartInfo.param.thresholds) && chartInfo.param.thresholds.length) { // 阈值
s.markLine = { s.markLine = {
symbol: 'circle', symbol: 'circle',
symbolSize: 5 symbolSize: 5
} }
// Thresholds 只对左Y轴有效
if (s.yAxisIndex != 1) {
s.markLine.data = chartInfo.param.thresholds.map(threshold => { s.markLine.data = chartInfo.param.thresholds.map(threshold => {
return { return {
yAxis: threshold.value || 0, yAxis: threshold.value || 0,
@@ -99,6 +112,7 @@ export default {
} }
}) })
} }
}
// 判断如果是面积图 颜色设为渐变色 // 判断如果是面积图 颜色设为渐变色
if (s.areaStyle && this.colorList.length) { if (s.areaStyle && this.colorList.length) {
s.areaStyle = { s.areaStyle = {

View File

@@ -306,6 +306,7 @@ export default {
} else { } else {
if (r.status === 'success') { if (r.status === 'success') {
r.data.result.forEach(item => { r.data.result.forEach(item => {
item.elements = elements[rIndex - elements.length]
this.allDataLength++ this.allDataLength++
item.values.forEach(values => { item.values.forEach(values => {
values[0] = values[0] + this.minusTime / 1000 values[0] = values[0] + this.minusTime / 1000

View File

@@ -42,11 +42,12 @@
}"> }">
<i class="nz-icon nz-icon-arrow-down" :class="expressionsShow[index-1].show?'':'is-active'" @click.stop="showExpression(index)"></i> <i class="nz-icon nz-icon-arrow-down" :class="expressionsShow[index-1].show?'':'is-active'" @click.stop="showExpression(index)"></i>
<el-input <el-input
style="width: 120px"
@mousedown.stop @mousedown.stop
v-model="expressionName[index-1]" v-model="expressionName[index-1]"
size="small" size="small"
@input="(val)=>{expressionNameInput(val,index-1)}" @input="(val)=>{expressionNameInput(val,index-1)}"
@change="expressionNameChange(index-1)" style="width: 120px" @change="expressionNameChange(index-1)"
@focus.stop="showInput(index-1,false)" @focus.stop="showInput(index-1,false)"
@blur="showInput(index-1,true)" @blur="showInput(index-1,true)"
/> />
@@ -136,8 +137,7 @@
<el-option <el-option
v-for="item in chartTypeList" v-for="item in chartTypeList"
:key="item.id" :key="item.id"
:disabled=" :disabled="item.id==='group' && chartConfig.isGroup"
item.id==='group' && chartConfig.isGroup"
:label="item.name" :label="item.name"
:value="item.id"> :value="item.id">
<span class="panel-dropdown-label-txt" >{{item.name}}</span> <span class="panel-dropdown-label-txt" >{{item.name}}</span>
@@ -411,6 +411,133 @@
</el-form-item> </el-form-item>
</div> </div>
<!-- Right Y Axis -->
<div v-if="isShowRightYAxis(chartConfig.type)">
<div class="form__sub-title">
<span>{{$t('dashboard.panel.chartForm.rightYAxis')}}</span>
<el-switch
v-model="chartConfig.param.enable.rightYAxis"
size="small"
@change="change"
></el-switch>
</div>
<transition name="el-zoom-in-top">
<div
v-if="chartConfig.param.enable.rightYAxis"
class="form-items--half-width-group"
>
<!-- Data Source -->
<el-form-item
:label="$t('dashboard.panel.chartForm.datasource')"
class="form-item--half-width"
prop="param.rightYAxis.elementNames"
:rules="{ required: true, message: $t('validate.required'), trigger: 'change'}"
>
<el-select
v-model="chartConfig.param.rightYAxis.elementNames"
multiple
collapse-tags
placeholder=""
popper-class="right-box-select-top prevent-clickoutside"
size="small"
@change="change"
>
<el-option
v-for="item in chartConfig.elements"
:key="item.name"
:label="item.name"
:value="item.name"
>
</el-option>
</el-select>
</el-form-item>
<!-- type -->
<el-form-item
:label="$t('overall.type')"
class="form-item--half-width"
prop="param.rightYAxis.style"
>
<el-select
v-model="chartConfig.param.rightYAxis.style"
placeholder=""
popper-class="right-box-select-top prevent-clickoutside"
size="small"
@change="change"
>
<el-option
v-for="item in timeSeriesTypeList"
:key="item.value"
:label="$t(item.name)"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<!-- unit -->
<el-form-item
:label="$t('dashboard.panel.chartForm.unit')"
class="form-item--half-width"
prop="param.rightYAxis.unit"
>
<el-cascader
v-model="chartConfig.param.rightYAxis.unit"
:options="unitOptions"
:props="{ expandTrigger: 'hover',emitPath:false }"
:show-all-levels="false"
filterable
popper-class="dc-dropdown right-box-select-top right-public-box-dropdown-top prevent-clickoutside chart-box-unit"
size="small"
style="width: 100%"
@change="unitSelected"
>
</el-cascader>
</el-form-item>
<!-- label -->
<el-form-item
:label="$t('alert.list.labels')"
class="form-item--half-width"
prop="param.rightYAxis.label"
>
<el-input
size="small"
v-model="chartConfig.param.rightYAxis.label"
placeholder=""
@change="change"
></el-input>
</el-form-item>
<!--min-->
<el-form-item
:label="$t('dashboard.panel.chartForm.min')"
class="form-item--half-width"
prop="param.rightYAxis.min"
>
<el-input-number
size="small"
style="margin-top: 2px"
:controls="false"
@change="change"
show-word-limit
:placeholder="chartConfig.param.rightYAxis.min?'':'Auto'"
v-model="chartConfig.param.rightYAxis.min"/>
</el-form-item>
<!--max-->
<el-form-item
:label="$t('dashboard.panel.chartForm.max')"
class="form-item--half-width"
prop="param.rightYAxis.max"
>
<el-input-number
size="small"
style="margin-top: 2px"
:controls="false"
@change="change"
show-word-limit
:placeholder="chartConfig.param.rightYAxis.max?'':'Auto'"
v-model="chartConfig.param.rightYAxis.max"/>
</el-form-item>
</div>
</transition>
</div>
<div v-if="isShowLegend(chartConfig.type)"> <div v-if="isShowLegend(chartConfig.type)">
<!--legendConfig--> <!--legendConfig-->
<div class="form__sub-title"> <div class="form__sub-title">
@@ -1041,7 +1168,8 @@ export default {
legend: true, legend: true,
valueMapping: false, valueMapping: false,
thresholds: false, thresholds: false,
visibility: false visibility: false,
rightYAxis: false
}, },
showHeader: this.chartConfig.param.showHeader, showHeader: this.chartConfig.param.showHeader,
visibility: { visibility: {
@@ -1049,6 +1177,14 @@ export default {
operator: 'equal', operator: 'equal',
varValue: '', varValue: '',
result: 'show' result: 'show'
},
rightYAxis: {
elementNames: [],
style: 'line',
unit: 2,
label: '',
min: undefined,
max: undefined
} }
} }
this.$nextTick(() => { this.$nextTick(() => {

View File

@@ -222,6 +222,15 @@ export default {
return true return true
default: return false default: return false
} }
},
isShowRightYAxis (type) {
switch (type) {
case 'line':
case 'area':
case 'point':
return true
default: return false
}
} }
} }
} }

View File

@@ -338,7 +338,6 @@ export default {
id: 'table', id: 'table',
name: this.$t('dashboard.panel.chartForm.typeVal.table.label') name: this.$t('dashboard.panel.chartForm.typeVal.table.label')
} }
], ],
textList: [ textList: [
{ {
@@ -365,6 +364,20 @@ export default {
label: this.$t('dashboard.panel.chartForm.typeVal.server') label: this.$t('dashboard.panel.chartForm.typeVal.server')
} }
], ],
timeSeriesTypeList: [
{
id: 'line',
name: this.$t('dashboard.panel.chartForm.typeVal.line.label')
},
{
id: 'area',
name: this.$t('dashboard.panel.chartForm.typeVal.stackArea.label')
},
{
id: 'point',
name: this.$t('dashboard.panel.chartForm.typeVal.point.label')
}
],
isChoose: [] isChoose: []
} }
}, },
@@ -424,6 +437,11 @@ export default {
} else if (!this.expressionName[index]) { } else if (!this.expressionName[index]) {
this.expressionName[index] = this.expressionsShow[index].oldName this.expressionName[index] = this.expressionsShow[index].oldName
} else { } else {
this.chartConfig.param.rightYAxis && this.chartConfig.param.rightYAxis.elementNames.forEach((item, index) => {
if (item == this.expressionsShow[index].oldName) {
this.chartConfig.param.rightYAxis.elementNames[index] = this.expressionName[index]
}
})
this.expressionsShow[index].oldName = this.expressionName[index] this.expressionsShow[index].oldName = this.expressionName[index]
} }
this.$refs.chartForm.clearValidate('elements.' + (index - 1) + '.expression') this.$refs.chartForm.clearValidate('elements.' + (index - 1) + '.expression')
@@ -481,8 +499,7 @@ export default {
} else { } else {
this.expressions.push(item.expression) this.expressions.push(item.expression)
this.expressionName.push(item.name) this.expressionName.push(item.name)
this.expressionsShow.push( this.expressionsShow.push({
{
show: true, show: true,
hideInput: true, hideInput: true,
oldName: item.name, oldName: item.name,
@@ -490,8 +507,7 @@ export default {
elementId: item.id, elementId: item.id,
legend: item.legend, legend: item.legend,
state: item.state state: item.state
} })
)
} }
}, },
copyExpression (index) { copyExpression (index) {
@@ -510,16 +526,20 @@ export default {
) )
this.$nextTick(() => { this.$nextTick(() => {
this.expressions.forEach((ex, index) => { this.expressions.forEach((ex, index) => {
if (ex) {
this.$refs[`promql-${index}`][0].metricChange(ex) this.$refs[`promql-${index}`][0].metricChange(ex)
this.$refs[`promql-${index}`][0].promqlInputChange(ex) this.$refs[`promql-${index}`][0].promqlInputChange(ex)
}
}) })
}) })
this.expressionChange() this.expressionChange()
}, },
removeExpression (index) { removeExpression (index) {
if (this.expressionsShow.length > 1) { if (this.expressionsShow.length > 1) {
this.chartConfig.param.rightYAxis && this.chartConfig.param.rightYAxis.elementNames.forEach((elementName, subIndex) => {
if (elementName == this.expressionName[index]) {
this.chartConfig.param.rightYAxis.elementNames.splice(subIndex, 1)
}
})
this.expressions.splice(index, 1) this.expressions.splice(index, 1)
this.expressionName.splice(index, 1) this.expressionName.splice(index, 1)
this.expressionsShow.splice(index, 1) this.expressionsShow.splice(index, 1)
@@ -528,10 +548,8 @@ export default {
}) })
this.$nextTick(() => { this.$nextTick(() => {
this.expressions.forEach((ex, index) => { this.expressions.forEach((ex, index) => {
if (ex) {
this.$refs[`promql-${index}`][0].metricChange(ex) this.$refs[`promql-${index}`][0].metricChange(ex)
this.$refs[`promql-${index}`][0].promqlInputChange(ex) this.$refs[`promql-${index}`][0].promqlInputChange(ex)
}
}) })
}) })
this.expressionChange() this.expressionChange()

View File

@@ -248,7 +248,8 @@ export default {
legend: true, legend: true,
valueMapping: false, valueMapping: false,
thresholds: false, thresholds: false,
visibility: false visibility: false,
rightYAxis: false
}, },
thresholdShow: true, thresholdShow: true,
thresholds: [{ value: undefined, color: randomcolor() }], thresholds: [{ value: undefined, color: randomcolor() }],
@@ -258,6 +259,14 @@ export default {
operator: 'equal', operator: 'equal',
varValue: '', varValue: '',
result: 'show' result: 'show'
},
rightYAxis: {
elementNames: [],
style: 'line',
unit: 2,
label: '',
min: undefined,
max: undefined
} }
}, },
elements: [{ expression: '', legend: '', type: 'expert', id: '', name: 'A', state: 1, orderNum: 0 }], elements: [{ expression: '', legend: '', type: 'expert', id: '', name: 'A', state: 1, orderNum: 0 }],
@@ -269,7 +278,7 @@ export default {
}, },
pageObj: { pageObj: {
pageNo: 1, pageNo: 1,
pageSize: -1, // 此处获取所有数据,所以设置一个较大的值 pageSize: -1, // 此处获取所有数据
total: 0 total: 0
}, },
blankChartTemp: { blankChartTemp: {
@@ -602,7 +611,16 @@ export default {
} else { } else {
this.chart.param = {} this.chart.param = {}
} }
if (!this.chart.param.rightYAxis) {
this.chart.param.rightYAxis = {
elementNames: [],
style: 'line',
unit: 2,
label: '',
min: undefined,
max: undefined
}
}
if (!this.chart.groupId || this.chart.groupId == -1) { if (!this.chart.groupId || this.chart.groupId == -1) {
this.chart.groupId = '' this.chart.groupId = ''
} }