封装echarts成vue component
封装echarts成vue component EChartsLineComponent
文章目录
- 封装echarts成vue component EChartsLineComponent
- 封装说明
- 重写重点
- EChartsLineComponent的源码
- 使用说明
- 调用EChartsLineComponent示例源码
封装说明
为了减少一些公共代码和方便使用echarts的line图形,有限制条件的封装echats中的line类型的图,该Component名称为EChartsLineComponent
。
重写重点
-
以
dateset
属性中的source
来判断图形是否包含数据,意味着需要通过dataset
,source
的方式配置数据。初始化option
是要定义datasource
,source
属性,否则不能正常使用该EChartsLineComponent
。option:{ dataset: { // 第一行为表头,第一个元素为X轴,其后为Y轴元素 // 第二行为具体数据点 source: [] } }
同时,在定义的
option
中需要先确认数据每条线显示的效果,即配置series
属性。option:{ series: [ { type: 'line', smooth: true, }, { type: 'line', smooth: true, } ] }
-
定义了空数据的展示效果,舍弃了有数据状态下的
grid
属性。
-
增加了窗口自适应写法,并确定初始化图标高度为
400px
,宽度100%
。
EChartsLineComponent的源码
<template>
<div :id="chartId" :style="{ width: width, height: height }"></div>
</template>
<script>
import * as echarts from 'echarts';
export default {
name: 'EChartsLineComponent',
props: {
chartId: {
type: String,
required: true
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '400px'
},
option: {
type: Object,
required: true
},
},
data() {
return {
chartInstance: null,
noDataOption: {
title: {
show: true,
text: '暂无数据',
left: 'center', // 水平居中
top: 'center', // 垂直居中
},
xAxis: {
show: false,
},
yAxis: {
show: false,
},
grid: {
show: true,
shadowColor: 'rgba(0, 0, 0, 0.5)',
shadowBlur: 10
}
},
};
},
watch: {
option: {
handler(newOption, oldOption) {
if (this.chartInstance) {
// todo 需要细化明确数据变成空的定义 变化中
if (newOption.dataset.source.length === 0) {
this.updateAxisShow(newOption, false)
this.chartInstance.clear();
this.noDataOption.title.show = true
this.noDataOption.grid.show = true
this.chartInstance.setOption(this.noDataOption);
} else {
newOption.title = {show: false}
newOption.grid = {show: false}
this.updateAxisShow(newOption, true)
this.chartInstance.setOption(newOption);
}
} else {
this.init()
}
},
deep: true
}
},
mounted() {
this.init()
// todo 需要细化明确数据变成空的定义 -- 初始化时
if (this.chartInstance.getOption().dataset[0].source.length === 0) {
this.updateAxisShow(this.chartInstance.getOption(), false);
this.chartInstance.clear();
this.chartInstance.setOption(this.noDataOption);
}
window.addEventListener('resize', this.handleResize);
},
beforeDestroy() {
window.removeEventListener('resize', this.handleResize);
if (this.chartInstance) {
this.chartInstance.dispose();
}
},
methods: {
init() {
this.chartInstance = echarts.init(document.getElementById(this.chartId), {renderer: 'svg'});
this.chartInstance.setOption(this.option);
window.addEventListener('resize', this.handleResize);
},
handleResize() {
if (this.chartInstance) {
this.chartInstance.resize();
}
},
updateAxisShow(newOption, value) {
if (newOption.yAxis.length) {
this.noDataOption.yAxis = []
for (let i = 0; i < newOption.yAxis.length; i++) {
this.noDataOption.yAxis.push({"show": value})
newOption.yAxis[i].show = value
}
} else {
this.noDataOption.yAxis = {"show": value}
newOption.yAxis.show = value
}
if (newOption.xAxis.length) {
this.noDataOption.xAxis = []
for (let i = 0; i < newOption.xAxis.length; i++) {
this.noDataOption.xAxis.push({"show": value})
newOption.xAxis[i].show = value
}
} else {
this.noDataOption.xAxis = {"show": value}
newOption.xAxis.show = value
}
},
}
};
</script>
使用说明
调用EChartsLineComponent示例源码
<template>
<sn-page>
<sd-search-pane ref="searchPane"
:model="searchModel"
:options="searchOptions"
:rules="searchRules"
:span="3"
:hide-cancel="true"
@handle-query="handleQuery"/>
<div>
<div class="title">CPU内核情况</div>
<EChartsComponent chart-id="CPUUsedChart" :option="CPUUsedChartOption"></EChartsComponent>
<div class="title">内存情况</div>
<EChartsComponent chart-id="MemoryUsedChart" :option="MemoryUsedChartOption"></EChartsComponent>
<div class="title">资源pending情况</div>
<EChartsComponent chart-id="PendingChart" :option="PendingChartOption"></EChartsComponent>
<div class="title">APP情况</div>
<EChartsComponent chart-id="APPChart" :option="APPChartChartOption"></EChartsComponent>
<div class="title">Container情况</div>
<EChartsComponent chart-id="ContainerUsedChart" :option="ContainerUsedChartOption"></EChartsComponent>
</div>
</sn-page>
</template>
<script>
export default {
data(vm) {
return {
searchModel: {
clusterName: "",
queueName: "",
time: []
},
searchOptions: {
clusterName: {
label: "集群",
type: "select",
span: 6,
props: {
clearable: true,
filterable: true
},
on: {
change(val) {
val && vm.getQueue()
},
clear() {
vm.clearQueue()
}
},
children: []
},
queueName: {
label: "队列",
type: "select",
span: 6,
props: {
clearable: true,
filterable: true
},
children: []
},
time: {
label: "时间",
type: "date-picker",
span: 9,
props: {
clearable: true,
type: "datetimerange",
rangeSeparator: "到",
format: "yyyy-MM-dd HH:mm",
"value-format": "yyyy-MM-dd HH:mm",
pickerOptions: {
shortcuts: [{
text: '最近3小时',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 3);
picker.$emit('pick', [start, end]);
}
}, {
text: '最近1天',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24);
picker.$emit('pick', [start, end]);
}
}, {
text: '最近3天',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 3);
picker.$emit('pick', [start, end]);
}
}]
}
}
}
},
searchRules: {
clusterName: [
{
required: true,
message: "请选择集群",
trigger: "change"
}
],
queueName: [
{
required: true,
message: "请选择队列",
trigger: "change"
}
],
time: [
{
required: true,
message: "请选择时间",
trigger: "change"
}
]
},
CPUUsedChartOption: {
legend: {
top: "bottom",
},
tooltip: {
trigger: 'axis',
},
toolbox: {
show: true,
feature: {
saveAsImage: {show: true}
}
},
dataset: {
// 第一行为表头,第一个元素为X轴,其后为Y轴元素
// 第二行为具体数据点
source: []
},
xAxis: {
show: true,
type: 'category',
boundaryGap: false,
},
yAxis: {
type: "value",
name: "数量",
splitLine: {
show: true
},
axisLabel: {
show: true,
fontSize: 16,
}
},
series: [
{
type: 'line',
lineStyle: {
width: 3, // 设置线条宽度为4
type: 'dashed', // 设置为虚线
},
smoothMonotone: "x",
smooth: true,
},
{
type: 'line',
smoothMonotone: "x",
smooth: true,
},
{
type: 'line',
lineStyle: {
width: 3, // 设置线条宽度为4
type: 'dashed', // 设置为虚线
},
smoothMonotone: "x",
smooth: true,
}
]
},
MemoryUsedChartOption: {
legend: {
top: "bottom",
},
tooltip: {
trigger: 'axis',
},
toolbox: {
show: true,
feature: {
saveAsImage: {show: true}
}
},
dataset: {
// 第一行为表头,第一个元素为X轴,其后为Y轴元素
// 第二行为具体数据点
source: []
},
xAxis: {
show: true,
type: 'category',
boundaryGap: false,
},
yAxis: {
type: "value",
name: "大小",
splitLine: {
show: true
},
axisLabel: {
show: true,
fontSize: 16,
}
},
series: [
{
type: 'line',
lineStyle: {
width: 3, // 设置线条宽度为4
type: 'dashed', // 设置为虚线
},
smoothMonotone: "x",
smooth: true,
},
{
type: 'line',
smoothMonotone: "x",
smooth: true,
},
{
type: 'line',
lineStyle: {
width: 3, // 设置线条宽度为4
type: 'dashed', // 设置为虚线
},
smoothMonotone: "x",
smooth: true,
}
]
},
PendingChartOption: {
legend: {
top: "bottom",
},
tooltip: {
trigger: 'axis',
},
toolbox: {
show: true,
feature: {
saveAsImage: {show: true}
}
},
dataset: {
// 第一行为表头,第一个元素为X轴,其后为Y轴元素
// 第二行为具体数据点
source: []
},
xAxis: {
show: true,
type: 'category',
boundaryGap: false,
},
yAxis: [
{
type: "value",
name: "大小",
splitLine: {
show: true
},
axisLabel: {
show: true,
fontSize: 16,
}
},
{
type: "value",
name: "数量",
splitLine: {
show: true
},
axisLabel: {
show: true,
fontSize: 16,
}
}
],
series: [
{
type: 'line',
yAxisIndex: 0,
smooth: true,
},
{
type: 'line',
yAxisIndex: 1,
smooth: true,
},
]
},
APPChartChartOption: {
legend: {
top: "bottom",
},
tooltip: {
trigger: 'axis',
},
toolbox: {
show: true,
feature: {
saveAsImage: {show: true}
}
},
dataset: {
// 第一行为表头,第一个元素为X轴,其后为Y轴元素
// 第二行为具体数据点
source: []
},
xAxis: {
show: true,
type: 'category',
boundaryGap: false,
},
yAxis: {
type: "value",
name: "数量",
splitLine: {
show: true
},
axisLabel: {
show: true,
fontSize: 16,
}
},
series: [
{
type: 'line',
lineStyle: {
width: 3, // 设置线条宽度为4
type: 'dashed', // 设置为虚线
},
smooth: true,
},
{
type: 'line',
smooth: true,
},
{
type: 'line',
smooth: true,
},
{
type: 'line',
smooth: true,
},
{
type: 'line',
smooth: true,
},
{
type: 'line',
smooth: true,
},
{
type: 'line',
smooth: true,
},
{
type: 'line',
smooth: true,
},
]
},
ContainerUsedChartOption: {
legend: {
top: "bottom",
},
tooltip: {
trigger: 'axis',
},
toolbox: {
show: true,
feature: {
saveAsImage: {show: true}
}
},
dataset: {
// 第一行为表头,第一个元素为X轴,其后为Y轴元素
// 第二行为具体数据点
source: []
},
xAxis: {
show: true,
type: 'category',
boundaryGap: false,
},
yAxis: {
type: "value",
name: "数量",
splitLine: {
show: true
},
axisLabel: {
show: true, fontSize: 16,
}
},
series: [
{
type: 'line',
smoothMonotone: "x",
smooth: true,
},
{
type: 'line',
smoothMonotone: "x",
smooth: true,
},
]
}
};
},
methods: {
handleRes(res, title) {
if (res.code === 0) {
this.$message({
type: 'success',
message: title + res.msg
})
} else {
this.$message({
type: 'error',
message: title + res.msg
})
}
},
getCPUUsed() {
this.$get({
api: 'api/v2/manager/yarn/metric/getQueueMetricMaxValue',
params: {
metrics: "AllocatedVCores,MaxShareVCores,MinShareVCores",
clusterName: this.searchModel.clusterName,
queueName: this.searchModel.queueName,
startTime: this.searchModel.time[0],
endTime: this.searchModel.time[1]
}
}, res => {
this.handleRes(res,"CPU内核情况")
this.CPUUsedChartOption.dataset.source = res.data
})
},
getMemoryUsed() {
this.$get({
api: 'api/v2/manager/yarn/metric/getQueueMetricMaxValue',
params: {
clusterName: this.searchModel.clusterName,
queueName: this.searchModel.queueName,
metrics: "AllocatedMB,MaxShareMB,MinShareMB",
startTime: this.searchModel.time[0],
endTime: this.searchModel.time[1]
}
}, res => {
this.handleRes(res,"内存情况")
this.MemoryUsedChartOption.dataset.source = res.data
})
},
getPending() {
this.$get({
api: 'api/v2/manager/yarn/metric/getQueueMetricMaxValue',
params: {
clusterName: this.searchModel.clusterName,
queueName: this.searchModel.queueName,
metrics: "PendingMB,PendingVCores",
startTime: this.searchModel.time[0],
endTime: this.searchModel.time[1]
}
}, res => {
this.handleRes(res,"资源pending情况")
this.PendingChartOption.dataset.source = res.data
})
},
getAPP() {
this.$get({
api: 'api/v2/manager/yarn/metric/getQueueMetricMaxValue',
params: {
clusterName: this.searchModel.clusterName,
queueName: this.searchModel.queueName,
metrics: "MaxApps,AppsSubmitted,AppsRunning,AppsPending,AppsCompleted,AppsKilled,AppsFailed",
startTime: this.searchModel.time[0],
endTime: this.searchModel.time[1]
}
}, res => {
this.handleRes(res,"APP情况")
this.APPChartChartOption.dataset.source = res.data
})
},
getContainerUsed() {
this.$get({
api: 'api/v2/manager/yarn/metric/getQueueMetricMaxValue',
params: {
clusterName: this.searchModel.clusterName,
queueName: this.searchModel.queueName,
metrics: "AllocatedContainers,PendingContainers",
startTime: this.searchModel.time[0],
endTime: this.searchModel.time[1]
}
}, res => {
this.handleRes(res,"Container情况")
this.ContainerUsedChartOption.dataset.source = res.data
})
},
handleQuery() {
this.$refs.searchPane.validate(valid => {
if (valid) {
// 几张图就几个请求
this.getCPUUsed();
this.getMemoryUsed();
this.getPending();
this.getAPP();
this.getContainerUsed();
}
});
},
getQueue() {
this.$get({
api: 'api/v2/manager/yarn/monitor/listYarnQueue',
params: {yarnCluster: this.searchModel.clusterName}
}, res => {
this.searchOptions.queueName.children = res.data.map(item => {
return {label: item, value: item}
})
})
},
},
mounted() {
},
created() {
this.$get({
api: 'api/v2/manager/yarn/monitor/listYarnCluster'
}, res => {
this.searchOptions.clusterName.children = res.data.map(item => {
return {label: item, value: item}
})
})
this.CPUUsedChartOption.dataset.source = [
['metricDate', 'AllocatedVCores', 'MaxShareVCores', 'MinShareVCores'],
['2024-12-5', 50, 100, 1900],
['2024-12-6', 50, 100, 1900],
['2024-12-7', 50, 100, 1900],
['2024-12-8', 50, 100, 1900],
['2024-12-9', 50, 100, 1900],
['2024-12-10', 50, 100, 1900]
];
this.MemoryUsedChartOption.dataset.source = [
['metricDate', 'AllocatedMB', 'MaxShareMB', 'MinShareMB'],
['2024-12-5', 50, 100, 1900],
['2024-12-6', 50, 100, 1900],
['2024-12-7', 50, 100, 1900],
['2024-12-8', 50, 100, 1900],
['2024-12-9', 50, 100, 1900],
['2024-12-10', 50, 100, 1900]
];
this.APPChartChartOption.dataset.source = [
['metricDate', 'MaxApps', 'AppsSubmitted', 'AppsRunning', 'AppsPending', 'AppsCompleted', 'AppsKilled', 'AppsFailed'],
['2024-12-5', 2000, 100, 1900, 50, 200, 1600, 1],
['2024-12-6', 2000, 100, 1900, 50, 200, 1600, 0],
['2024-12-7', 2000, 100, 1900, 50, 200, 1700, 0],
['2024-12-8', 2000, 100, 1900, 50, 200, 1800, 0],
['2024-12-9', 2000, 100, 1900, 50, 200, 2200, 0],
['2024-12-10', 2000, 100, 1900, 50, 200, 1800, 0]
];
this.PendingChartOption.dataset.source = [
['metricDate', 'PendingMB', 'PendingVCores'],
['2024-12-5', 50, 0],
['2024-12-6', 50, 100],
['2024-12-7', 0, 100],
['2024-12-8', 10, 60],
['2024-12-9', 50, 100],
['2024-12-10', 0, 0]
];
this.ContainerUsedChartOption.dataset.source = [
['metricDate', 'AllocatedContainers', 'PendingContainers'],
['2024-12-5', 50, 100],
['2024-12-6', 50, 100],
['2024-12-7', 50, 100],
['2024-12-8', 50, 10000],
['2024-12-9', 50, 1000],
['2024-12-10', 50, 100900]
];
},
beforeDestroy() {
}
};
</script>
<style>
.title {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
font-size: 20px;
font-weight: bold;
margin-top: 20px;
}
</style>