blob: 9125b9a231f2605ccb7c40eb0fdadd9fdef3cc4a [file] [log] [blame]
<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-->
<template>
<div style="width: 100%; height: 100%; position: relative;">
<div class="configBar">
<label for="refreshPeriod">{{ $t("clusterState.configBar.refreshPeriodLabel") }}:</label>
<el-switch
v-model="autoRefreshFlag"
active-color="#13ce66"
inactive-color="#ff4949">
</el-switch>
<select v-model="refreshInterval" name="refreshPeriod">
<option v-for="(item,index) of refreshOptions" :value="item.millis" :key="index">{{ item.name }}</option>
</select>
</div>
<div id="myChart" class="echarts"></div>
</div>
</template>
<script>
import echarts from 'echarts'
import Vue from 'vue'
Vue.prototype.$echarts = echarts
import 'echarts-liquidfill'
import API from '../api'
export default {
name: 'ClusterState',
data() {
return {
allData: {},
instanceData: {},
proxy: [],
datasource: [],
categories: [],
linesData: [],
links: [],
option: {},
state: {
ONLINE: '#01acca',
OFFLINE: '#FF0A14',
DISABLED: '#A9A9A9',
UNKNOWN: '#ffb402'
},
myChart: {},
timer: {},
refreshOptions: [
{ name: '30s', millis: 30000 },
{ name: '60s', millis: 60000 },
{ name: '2min', millis: 120000 },
{ name: '5min', millis: 300000 },
{ name: '30min', millis: 1800000 }
],
prevRefreshMillis: 0,
autoRefreshFlag: true,
refreshInterval: 60000
}
},
mounted() {
this.initChart()
this.loadAllInstanceStates()
},
activated() {
this.myChart && this.myChart.resize()
},
destroyed() {
this.close()
},
methods: {
refresh() {
this.loadAllInstanceStates()
},
tryAutoRefresh() {
const curMillis = new Date().getTime()
if (!this.autoRefreshFlag) {
return
} else if (!this.prevRefreshMillis) {
this.prevRefreshMillis = curMillis
return
} else if (curMillis - this.prevRefreshMillis < this.refreshInterval) {
return
}
this.prevRefreshMillis = curMillis
this.refresh()
},
loadAllInstanceStates() {
API.loadInstanceStates().then(res => {
const data = res.model
this.allData = data
this.instanceData = data.instanceStates
this.createChart()
})
},
initChart() {
this.initCategories()
this.myChart = this.$echarts.init(document.getElementById('myChart'))
this.myChart.setOption(this.getOption(), true)
window.addEventListener("resize", () => { this.myChart.resize() })
this.startTimer()
},
createChart() {
this.initProxy()
this.initDatasource()
this.initLines()
this.setChartData()
this.myChart.setOption(this.option)
},
startTimer() {
this.timer = setInterval(this.tryAutoRefresh, 1)
},
initProxy() {
this.proxy = []
let x = 20
for (const key in this.allData.instanceStates) {
this.proxy.push({
name: key,
value: [x, 130],
category: this.getCategory(this.allData.instanceStates[key]),
symbolSize: 100,
label: {
position: 'top'
}
})
x += 50
}
},
initDatasource() {
this.datasource = []
let x = 0
for (const key in this.allData.dataSourceStates) {
this.datasource.push({
name: key,
category: this.getCategory(this.allData.dataSourceStates[key]),
state: this.allData.dataSourceStates[key].state,
speed: '',
value: [x, 20]
})
x += 20
}
},
initLines() {
this.links = []
this.linesData = []
this.datasource.slice().forEach((ds) => {
this.proxy.slice().forEach((p) => {
if (p.category === 2) {
this.links.push({
source: p.name,
target: ds.name,
speed: ds.speed,
lineStyle: {
normal: {
color: this.state.DISABLED,
curveness: 0
}
}
})
} else {
const ids = this.instanceData[p.name].dataSources[ds.name]
if (ids) {
if (ids.state === 'ONLINE') {
this.linesData.push([{
coord: p.value
}, {
coord: ds.value
}])
}
this.links.push({
source: p.name,
target: ds.name,
speed: ds.speed,
lineStyle: {
normal: {
color: this.state[ids.state],
curveness: 0
}
}
})
}
}
})
})
},
initCategories() {
this.categories = [{
name: this.$t('clusterState').legendLabel.onLine,
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [{
offset: 0,
color: '#01acca'
}, {
offset: 1,
color: '#5adbe7'
}])
}
},
label: {
normal: {
fontSize: '14'
}
}
}, {
name: this.$t('clusterState').legendLabel.offLine,
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [{
offset: 0,
color: '#FF0A14'
}, {
offset: 1,
color: '#FF9387'
}])
}
},
label: {
normal: {
fontSize: '14'
}
}
}, {
name: this.$t('clusterState').legendLabel.disabled,
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [{
offset: 0,
color: '#FF199D'
}, {
offset: 1,
color: '#FF8EE6'
}])
}
},
label: {
normal: {
fontSize: '14'
}
}
}, {
name: this.$t('clusterState').legendLabel.unknown,
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [{
offset: 0,
color: '#ffb402'
}, {
offset: 1,
color: '#ffdc84'
}])
}
},
label: {
normal: {
fontSize: '14'
}
}
}]
},
getCategory(nodeState) {
if (nodeState.state === 'ONLINE') {
return 0
} else if (nodeState.state === 'OFFLINE') {
return 1
} else if (nodeState.state === 'DISABLED') {
return 2
}
return 3
},
setChartData() {
this.option.series[0].data = this.proxy.concat(this.datasource)
this.option.series[1].data = this.linesData
this.option.series[0].links = this.links
},
getOption() {
this.option = {
legend: [{
formatter: function(name) {
return echarts.format.truncateText(name, 100, '14px Microsoft Yahei', '…');
},
tooltip: {
show: true
},
textStyle: {
color: '#999'
},
selectedMode: false,
right: 0,
data: this.categories.map(function(c) {
return c.name
})
}],
xAxis: {
show: false,
type: 'value'
},
yAxis: {
show: false,
type: 'value'
},
series: [{
type: 'graph',
layout: 'none',
roam: 'scale',
coordinateSystem: 'cartesian2d',
symbolSize: 60,
z: 3,
edgeLabel: {
normal: {
show: true,
textStyle: {
fontSize: 14
},
formatter: function(params) {
let txt = ''
if (params.data.speed !== undefined) {
txt = params.data.speed
}
return txt
},
}
},
label: {
normal: {
show: true,
position: 'bottom',
color: '#5e5e5e'
}
},
itemStyle: {
normal: {
shadowColor: 'none'
},
emphasis: {
}
},
lineStyle: {
normal: {
width: 2,
shadowColor: 'none'
},
},
edgeSymbol: ['none', 'arrow'],
edgeSymbolSize: 8,
data: [],
links: [],
categories: this.categories
}, {
name: 'A',
type: 'lines',
coordinateSystem: 'cartesian2d',
z: 1,
effect: {
show: true,
smooth: false,
trailLength: 0,
symbol: "arrow",
color: 'rgba(55,155,255,0.5)',
symbolSize: 12
},
lineStyle: {
normal: {
curveness: 0
}
},
data: []
}]
}
return this.option
},
close() {
clearTimeout(this.timer)
}
}
}
</script>
<style lang='scss' scoped>
.btn-group {
margin-bottom: 20px;
}
.pagination {
float: right;
margin: 10px -10px 10px 0;
}
.echarts {
height: 100%;
width: 100%;
padding-top: 10px;
}
.configBar {
z-index: 100;
position: absolute;
top: 10px;
left: 10px;
font-size: 14px;
font-weight: 500;
}
</style>