WIP: 绘制监控图表

This commit is contained in:
Xu Zhimeng 2023-06-13 18:20:14 +08:00
parent 12f010ecb8
commit 20aad9d71d
4 changed files with 206 additions and 123 deletions

View File

@ -59,6 +59,9 @@ export default {
if (val) {
this.innerFullscreen = false
}
},
innerFullscreen(val) {
this.$emit('fullscreen', val)
}
},
methods: {

View File

@ -57,9 +57,6 @@ import CustomModal from '@/components/CustomModal'
import CustomDatePicker from '@/components/CustomDatePicker'
import CustomMonthPicker from '@/components/CustomMonthPicker'
import CustomEmpty from '@/components/CustomEmpty'
import CustomChart from '@/components/CustomChart'
console.log('%c [ CustomChart ]-61', 'font-size:13px; background:pink; color:#bf2c9f;', CustomChart)
Vue.prototype.rules = rules
Vue.config.productionTip = false
@ -81,7 +78,6 @@ Vue.component('custom-modal', CustomModal)
Vue.component('custom-date-picker', CustomDatePicker)
Vue.component('custom-month-picker', CustomMonthPicker)
Vue.component('custom-empty', CustomEmpty)
Vue.component('custom-chart', CustomChart)
SSO.init(() => {
main()

View File

@ -127,6 +127,7 @@
title="Data Recevice status Monitoring"
:width="1230"
:showFooter="false"
@fullscreen="onModalFullScreen"
>
<div class="data-receive-status">
<!-- 左侧配置栏 -->
@ -184,7 +185,20 @@
<!-- 右侧图表展示栏 -->
<div class="data-receive-status-chart" :class="{ 'on-screen': !leftPaneShow }">
<custom-chart :option="option"></custom-chart>
<!-- 图例 -->
<div class="legend">
<div class="legend-item" v-for="(legend, index) in legendList" :key="index">
<span class="legend-item-color" :style="{ backgroundColor: legend.color }"></span>
<span>{{ legend.title }}</span>
</div>
</div>
<!-- 图例结束 -->
<template v-if="showChart">
<template v-for="(item, index) in statusList">
<RealTimeDataChart :legendList="legendList" :title="item.title" :key="index" />
<a-divider :key="index + '_divider'" v-if="index !== statusList.length - 1"></a-divider>
</template>
</template>
</div>
<!-- 右侧图表展示栏结束 -->
</div>
@ -196,7 +210,7 @@
import CustomModal from '@/components/CustomModal/index.vue'
import FilterImage from './filterImage'
import CustomTree from '@/components/CustomTree/index.vue'
import * as echarts from 'echarts'
import RealTimeDataChart from './RealTimeDataChart.vue'
// Filter
const filterList = [
@ -339,122 +353,39 @@ const dataSource = [
}
]
var data = []
var dataCount = 10
var startTime = +new Date()
var categories = ['categoryA', 'categoryB', 'categoryC']
var types = [
{ name: 'JS Heap', color: '#7b9ce1' },
{ name: 'Documents', color: '#bd6d6c' },
{ name: 'Nodes', color: '#75d874' },
{ name: 'Listeners', color: '#e0bc78' },
{ name: 'GPU Memory', color: '#dc77dc' },
{ name: 'GPU', color: '#72b362' }
const legendList = [
{
title: 'SPHDPREL',
color: '#17a840'
},
{
title: 'SPHDF',
color: '#0cbfb0'
},
{
title: 'QC',
color: '#1c82eb'
},
{
title: 'GASBKPHDPREL',
color: '#d3ad16'
},
{
title: 'GASBKPHDF',
color: '#db6423'
},
{
title: 'SOH/MET',
color: '#8852da'
}
]
// Generate mock data
categories.forEach(function(category, index) {
var baseTime = startTime
for (var i = 0; i < dataCount; i++) {
var typeItem = types[Math.round(Math.random() * (types.length - 1))]
var duration = Math.round(Math.random() * 10000)
data.push({
name: typeItem.name,
value: [index, baseTime, (baseTime += duration), duration],
itemStyle: {
normal: {
color: typeItem.color
}
}
})
baseTime += Math.round(Math.random() * 2000)
}
})
const statusList = [{
title: 'JPX38 23803',
function renderItem(params, api) {
var categoryIndex = api.value(0)
var start = api.coord([api.value(1), categoryIndex])
var end = api.coord([api.value(2), categoryIndex])
var height = api.size([0, 1])[1] * 0.6
var rectShape = echarts.graphic.clipRectByRect(
{
x: start[0],
y: start[1] - height / 2,
width: end[0] - start[0],
height: height
},
{
x: params.coordSys.x,
y: params.coordSys.y,
width: params.coordSys.width,
height: params.coordSys.height
}
)
return (
rectShape && {
type: 'rect',
transition: ['shape'],
shape: rectShape,
style: api.style()
}
)
}
const option = {
tooltip: {
formatter: function(params) {
return params.marker + params.name + ': ' + params.value[3] + ' ms'
}
},
title: {
text: '2021-9-10 性能分析',
left: 'center'
},
dataZoom: [
{
type: 'slider',
filterMode: 'weakFilter',
showDataShadow: false,
top: 10,
labelFormatter: ''
},
{
type: 'inside',
filterMode: 'weakFilter'
}
],
grid: {
height: 300
},
xAxis: {
min: startTime,
scale: true,
axisLabel: {
formatter: function(val) {
return Math.max(0, val - startTime) + 'ms'
}
}
},
yAxis: {
data: categories
},
series: [
{
type: 'custom',
renderItem: renderItem,
itemStyle: {
opacity: 0.8
},
encode: {
x: [1, 2],
y: 0
},
data: data
}
]
}
}, {
title: 'JPX38 23804'
}]
export default {
props: {
@ -469,7 +400,8 @@ export default {
},
components: {
CustomModal,
CustomTree
CustomTree,
RealTimeDataChart
},
data() {
this.columns = columns
@ -489,14 +421,16 @@ export default {
leftPaneShow: true, //
option // echarts
legendList, //
statusList,
showChart: true
}
},
created() {
this.initParentProps()
this.initParentMapProps()
},
methods: {
initParentProps() {
initParentMapProps() {
const { getZoom, setZoom, maxZoom, minZoom } = this.$parent
this.getZoom = getZoom
this.setZoom = setZoom
@ -545,6 +479,13 @@ export default {
if (zoom > this.minZoom) {
this.setZoom(zoom - 1)
}
},
onModalFullScreen() {
this.showChart = false
this.$nextTick(() => {
this.showChart = true
})
}
},
computed: {
@ -920,12 +861,42 @@ export default {
right: 15px;
width: calc(100% - 270px);
height: 100%;
overflow: auto;
padding: 0 15px 10px;
border: 1px solid @borderColor;
transition: width 0.3s cubic-bezier(0.075, 0.82, 0.165, 1);
&.on-screen {
width: calc(100% - 30px);
}
.ant-divider {
margin: 34px 0 40px;
background-color: rgba(65, 111, 127, 0.5);
}
}
.legend {
margin: 32px 0;
display: flex;
justify-content: center;
&-item {
color: #ade6ee;
line-height: 12px;
&:not(:last-child) {
margin-right: 30px;
}
&-color {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 4px;
margin-right: 6px;
}
}
}
}

View File

@ -0,0 +1,113 @@
<template>
<v-chart :force-fit="true" :height="height" :data="dataSource" :padding="[0, 0, 40, 60]">
<v-axis
data-key="name"
:title="{ text: title, textStyle: { fill: '#5b9cba', fontSize: 14 }, offset: 45 }"
:label="{ textStyle: { fill: '#ade6ee' } }"
:grid="{ lineStyle: { stroke: '#406979', strokeOpacity: 0.2, lineDash: [0, 0] } }"
:line="{ stroke: '#406979', strokeOpacity: 0.5 }"
/>
<v-axis
data-key="time"
:label="{ textStyle: { fill: '#ade6ee' }, offset: 25 }"
:grid="{ lineStyle: { stroke: '#406979', strokeOpacity: 0.2, lineDash: [0, 0] }, hideLastLine: true }"
:line="{ stroke: '#406979', strokeOpacity: 0.5 }"
:tick-line="null"
/>
<v-polygon position="time*name" shape="custom" :v-style="{ lineWidth: 0 }" />
</v-chart>
</template>
<script>
import { registerShape } from 'viser-vue'
registerShape('polygon', 'custom', {
draw: function(cfg, container) {
const color = cfg.origin._origin.color // ,datasourcecolor
//
return color
? container.addShape('rect', {
attrs: {
x: cfg.x - 32,
y: cfg.y - 10,
width: 32,
height: 20,
fill: color,
stroke: color
}
})
: null
}
})
const timeList = [
'08:00\n04/06',
'10:00\n04/06',
'12:00\n04/06',
'14:00\n04/06',
'16:00\n04/06',
'18:00\n04/06',
'20:00\n04/06',
'22:00\n04/06',
'00:00\n04/07',
'02:00\n04/07',
'04:00\n04/07',
'06:00\n04/07',
// '08:00\n04/07'
]
const typeList = ['MET', 'SOH', 'QC', 'PHD']
export default {
props: {
legendList: {
type: Array
},
height: {
type: Number,
default: 250
},
title: {
type: String
}
},
data() {
return {
dataSource: []
}
},
created() {
const dataSource = typeList.reduce((prev, type) => {
return prev.concat(
timeList.map(time => {
return {
name: type,
color: '',
time
}
})
)
}, [])
dataSource[36].color = '#d3ad16'
dataSource[37].color = '#d3ad16'
dataSource[38].color = '#d3ad16'
dataSource[39].color = '#d3ad16'
dataSource[40].color = '#db6423'
dataSource[41].color = '#17a840'
dataSource[42].color = '#17a840'
dataSource[43].color = '#17a840'
dataSource[44].color = '#17a840'
dataSource[45].color = '#17a840'
dataSource[46].color = '#8c6513'
dataSource[47].color = '#d3ad16'
dataSource[28].color = '#1c82eb'
dataSource[34].color = '#1c82eb'
this.dataSource = dataSource
}
}
</script>
<style></style>