如何用Echarts+vue可视化动态基线分析结果demo

如何用Echart+vue可视化后台分析的数据结果

​ echarts在运维可视化中是最常见的一个可视化工具,这里介绍如何去对后台分析的结果进行可视化。
同时此页面基于vue并且使用了iview插件库,框架使用vue-cli3.0(iview-admin)。实际上不用管这些,非必须,简单来说就是vue+echarts来对后台返回的分析结果数据进行可视化。

应用场景

​ 这里做了一个动态基线的demo,也就是说对服务器的运维状态进行一个分析,然后产生一个结果数据来对当前服务器的状态信息进行比较提供参考。
整体思路如下,通过数据抽取把历史数据进行抽取并且提供给后台进行分析,然后后台将结果存储下来,可视化页面去调用后台的接口获得对应实体的基线数据。

数据接口

​ demo提供三个接口:1.baseline?job_id=10&ip=10.x.x.x 可以获取任务号为10、ip为10.x.x.x的基线值。2.baseline?job_id=10 不指定ip可以获取所有ip的分时间点的基线值。3.baseline/ips 可以获取所有有基线值的ip列表。数据示例:

{
     
    "code": 1,
    "data": [
        {
     
            "date": "2020-04-27",
            "id": 29,
            "ip": "10.238.0.12",
            "job_id": 10,
            "value": 34.25
        },
        {
     
            "date": "2020-04-26",
            "id": 33,
            "ip": "10.238.0.12",
            "job_id": 10,
            "value": 15.5
        },
        {
     
            "date": "2020-04-25",
            "id": 37,
            "ip": "10.238.0.12",
            "job_id": 10,
            "value": 18.5
        },
        {
     
            "date": "2020-04-24",
            "id": 41,
            "ip": "10.238.0.12",
            "job_id": 10,
            "value": 4.5
        },
        {
     
            "date": "2020-04-23",
            "id": 45,
            "ip": "10.238.0.12",
            "job_id": 10,
            "value": 31.75
        },
        {
     
            "date": "2020-04-22",
            "id": 49,
            "ip": "10.238.0.12",
            "job_id": 10,
            "value": 19.25
        },
        {
     
            "date": "2020-04-21",
            "id": 53,
            "ip": "10.238.0.12",
            "job_id": 10,
            "value": 23.75
        }
    ],
    "message": "获取数据成功"
}
//所有数据
{
     "code":1,"data":[{
     "date":"2020-04-27","id":29,"ip":"10.238.0.12","job_id":10,"value":34.25},{
     "date":"2020-04-27","id":30,"ip":"10.238.0.134","job_id":10,"value":26.75},{
     "date":"2020-04-27","id":31,"ip":"10.238.0.17","job_id":10,"value":30.25},{
     "date":"2020-04-27","id":32,"ip":"10.238.0.215","job_id":10,"value":26.0},{
     "date":"2020-04-26","id":33,"ip":"10.238.0.12","job_id":10,"value":15.5},{
     "date":"2020-04-26","id":34,"ip":"10.238.0.134","job_id":10,"value":15.5},{
     "date":"2020-04-26","id":35,"ip":"10.238.0.17","job_id":10,"value":23.0},{
     "date":"2020-04-26","id":36,"ip":"10.238.0.215","job_id":10,"value":17.25},{
     "date":"2020-04-25","id":37,"ip":"10.238.0.12","job_id":10,"value":18.5},{
     "date":"2020-04-25","id":38,"ip":"10.238.0.134","job_id":10,"value":18.5},{
     "date":"2020-04-25","id":39,"ip":"10.238.0.17","job_id":10,"value":18.75},{
     "date":"2020-04-25","id":40,"ip":"10.238.0.215","job_id":10,"value":50.5},{
     "date":"2020-04-24","id":41,"ip":"10.238.0.12","job_id":10,"value":4.5},{
     "date":"2020-04-24","id":42,"ip":"10.238.0.134","job_id":10,"value":4.5},{
     "date":"2020-04-24","id":43,"ip":"10.238.0.17","job_id":10,"value":17.5},{
     "date":"2020-04-24","id":44,"ip":"10.238.0.215","job_id":10,"value":4.25},{
     "date":"2020-04-23","id":45,"ip":"10.238.0.12","job_id":10,"value":31.75},{
     "date":"2020-04-23","id":46,"ip":"10.238.0.134","job_id":10,"value":44.75},{
     "date":"2020-04-23","id":47,"ip":"10.238.0.17","job_id":10,"value":32.25},{
     "date":"2020-04-23","id":48,"ip":"10.238.0.215","job_id":10,"value":32.25},{
     "date":"2020-04-22","id":49,"ip":"10.238.0.12","job_id":10,"value":19.25},{
     "date":"2020-04-22","id":50,"ip":"10.238.0.134","job_id":10,"value":19.25},{
     "date":"2020-04-22","id":51,"ip":"10.238.0.17","job_id":10,"value":34.75},{
     "date":"2020-04-22","id":52,"ip":"10.238.0.215","job_id":10,"value":28.75},{
     "date":"2020-04-21","id":53,"ip":"10.238.0.12","job_id":10,"value":23.75},{
     "date":"2020-04-21","id":54,"ip":"10.238.0.134","job_id":10,"value":23.75},{
     "date":"2020-04-21","id":55,"ip":"10.238.0.17","job_id":10,"value":23.75},{
     "date":"2020-04-21","id":56,"ip":"10.238.0.215","job_id":10,"value":23.75}],"message":"\u83b7\u53d6\u6570\u636e\u6210\u529f"}

echarts图表选型

​ 查看Echarts官网的示例,初步选定堆叠折线图来实现。echarts图件生成参考:五分钟上手Echarts(https://echarts.apache.org/zh/tutorial.html#5%20%E5%88%86%E9%92%9F%E4%B8%8A%E6%89%8B%20ECharts)。
​ 以下图件可以很好地对这个应用场景进行一个展示

如何用Echarts+vue可视化动态基线分析结果demo_第1张图片

​ echarts的图件生成最关键的就是对于option的设置。比如最基本的折线图能够通过下面的option设置来完成:

option = {
     
    xAxis: {
     
        type: 'category',
        data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
    },
    yAxis: {
     
        type: 'value'
    },
    series: [{
     
        data: [820, 932, 901, 934, 1290, 1330, 1320],
        type: 'line'
    }]
};

如何用Echarts+vue可视化动态基线分析结果demo_第2张图片

对于本demo中最简单的实现可以通过以下代码来完成。

<template>
  <div>
    <row>
      <i-Col span="24">
        <div ref="lineChart" style="height:400px;"></div>
      </i-Col>
    </row>
  </div>
</template>
<script>
import echarts from 'echarts'
 //利用绑定事件来对浏览器窗口的变化进行响应。
import {
      on, off } from '@/libs/tools'
import axios from 'axios'
export default {
     
  name: 'demo',
  components: {
     
    ChartBar,
  },
  data() {
     
    return {
     
      lineChartDom : null,
      text:"动态基线展示",
      subtext:"单点展示",
      dataset: {
     
        source: [
          {
     "date":"2020-04-27","id":29,"ip":"10.238.0.12","job_id":10,"value":34.25},
          {
     "date":"2020-04-26","id":33,"ip":"10.238.0.12","job_id":10,"value":15.5},
          {
     "date":"2020-04-25","id":37,"ip":"10.238.0.12","job_id":10,"value":18.5},
          {
     "date":"2020-04-24","id":41,"ip":"10.238.0.12","job_id":10,"value":4.5},
          {
     "date":"2020-04-23","id":45,"ip":"10.238.0.12","job_id":10,"value":31.75},
          {
     "date":"2020-04-22","id":49,"ip":"10.238.0.12","job_id":10,"value":19.25},
          {
     "date":"2020-04-21","id":53,"ip":"10.238.0.12","job_id":10,"value":23.75}
        ]
      },
      ips: [],
      thisIp:null,
      chartOption:{
     
      },
    }
  },
  methods: {
     
    //可以参考echats的resize函数。
    resize(){
     
      this.lineChartDom.resize()
    },
    chartInit(){
     
    this.$nextTick(() => {
     
      let option = {
     
        dataset: this.dataset,
        title: {
     
          text: this.text,
          subtext: this.subtext,
          x: 'center'
        },
        xAxis: {
     
          type: 'category',
          //强制显示所有横坐标不建议使用
          // axisLabel:{
     
          //  interval: 0
          // }
        },
        yAxis: {
     
          type: 'value',
        },
        series: [{
     

          type: 'line',
          encode: {
     
            x: 'date',
            y: 'value'
          }
        }]
      }
      this.lineChartDom = echarts.init(this.$refs.lineChart)
      this.chartOption=option;
      this.lineChartDom.setOption(this.chartOption)
      //将echarts的resize和浏览器的窗口resize进行绑定。
      on(window, 'resize', this.resize)
      })
    },
    
   
  },
  mounted(){
     
    this.chartInit();
  },
  beforeDestroy () {
     
    off(window, 'resize', this.resize)
  }
}

</script>

​ 在iview-admin项目中自带的/libs/中的js文件,tools.js。如果不使用该框架,也可以通过以下代码自行实现echarts和浏览器的resize,关键词resize,浏览器绑定。

/**
 * @description 绑定事件 on(element, event, handler)
 */
export const on = (function () {
     
  if (document.addEventListener) {
     
    return function (element, event, handler) {
     
      if (element && event && handler) {
     
        element.addEventListener(event, handler, false)
      }
    }
  } else {
     
    return function (element, event, handler) {
     
      if (element && event && handler) {
     
        element.attachEvent('on' + event, handler)
      }
    }
  }
})()

/**
 * @description 解绑事件 off(element, event, handler)
 */
export const off = (function () {
     
  if (document.removeEventListener) {
     
    return function (element, event, handler) {
     
      if (element && event) {
     
        element.removeEventListener(event, handler, false)
      }
    }
  } else {
     
    return function (element, event, handler) {
     
      if (element && event) {
     
        element.detachEvent('on' + event, handler)
      }
    }
  }
})()

如何用Echarts+vue可视化动态基线分析结果demo_第3张图片

​ 这里将后台的数据写死了,那么通过添加axio来进行异步请求获取特定ip对应数据就能够获取到真实数据来进行单一的折线图展现了(需要引入axio):

 getDataset(tip){
     
        const that = this
        const param = {
     
          job_id:10,
          ip:tip
      }
      axios({
     
        method: 'get',
        url: "AIOPS-ALGORITHMS/service/baseline",
        withCredentials: true,
        params: param
      }).then(function(response) {
     
        const data1 = response.data
        if (data1['code'] == 1) {
     
          if(tip==null||tip==undefined){
     
            //待补充,堆叠折线图展现
          }
          else{
     
            //单一折线图展现
            that.dataset.source=data1.data;
            that.chartOption.dataset.source=data1.data;
            that.lineChartDom.setOption(that.chartOption)
            //console.log(that.dataset.source)
          }

        } else {
     
          that.$Modal.error({
     
            title: '失败',
            content: '服务器端参数可能出错,请检查!'
          })
        }
        })
    },

demo雏形

​ 上面提到了,后台提供了三个接口分别是获取所有实体的ip列表;获取某个ip的基线数据;获取所有ip对应的基线数据。那么这里要做出一个动态基线结果展示的demo可以考虑到的功能点有:

1.选择对应ip,来对该ip的基线数据进行展示

2.对现阶段所有实体进行展示

​ 解决方案:添加一个搜索框能够对对应ip进行选择,当不选择的时候把单一的折线图变为堆叠折线图。

1.搜索框的及备选内容的实现

​ 通过iview的搜索框组件实现,需要在对应的data部分预留好ips数组,thisIp来对选择框的备选以及内容进行声明:

    <row>
      <i-Col span="12">
        <Select v-model="thisIp" clearable style="width:200px" placeholder="选择对应实体ip" @on-select="selectTheme" @on-clear="clearSelectTheme">
          <Option v-for="item in ips" :value="item.value" :key="item.id">{
    { item.value }}Option>
        Select>
      i-Col>
    row>
  ips: [],
  thisIp:null,

​ 这里通过后台的获取所有ip列表接口来对备选数据进行获取:

  ipInit(){
     
      const that = this
    axios({
     
      method: 'get',
      url: "AIOPS-ALGORITHMS/service/baseline/ips",
      withCredentials: true,
      params: {
     }
    }).then(function(response) {
     
        const data1 = response.data
        //{"code":1,"data":["10.238.0.12","10.238.0.134","10.238.0.17","10.238.0.215"],"message":"\u83b7\u53d6\u6570\u636e\u6210\u529f"}
        if (data1['code'] == 1) {
     
          //传统方法
          // let tip=[];
          // for(var j = 0; j < data1.data.length; j++) {
     
          //   tip.push({
     
          //     value:data1.data[j],
          //     label:data1.data[j]
          //   })
          // }
          //vue的内置方法,mapfilter等等可以方便地对数据进行处理
          let nip=data1.data.map((item,i)=>{
     
              return {
     
                value:item,
                label:item
              }
          })
            that.ips=nip;
      } else {
     
          that.$Modal.error({
     
          title: '失败',
          content: '服务器端获取可能出错,请检查!'
          })
        }
      })
    },

2.对选择框选择事件进行响应

​ iview组件对选择事件以及取消选择事件预留了接口on-select和on -clear。对应代码:

    selectIp (value) {
     
      
    },
    clearSelectIp(){
     

    },

3.数据的处理

​ 后台传过来的数据有两种,某一个ip的所有基线值,所有ip的所有基线值:

{
     "code":1,"data":[{
     "date":"2020-04-27","id":29,"ip":"10.238.0.12","job_id":10,"value":34.25},{
     "date":"2020-04-27","id":30,"ip":"10.238.0.134","job_id":10,"value":26.75},{
     "date":"2020-04-27","id":31,"ip":"10.238.0.17","job_id":10,"value":30.25},{
     "date":"2020-04-27","id":32,"ip":"10.238.0.215","job_id":10,"value":26.0},{
     "date":"2020-04-26","id":33,"ip":"10.238.0.12","job_id":10,"value":15.5},{
     "date":"2020-04-26","id":34,"ip":"10.238.0.134","job_id":10,"value":15.5},{
     "date":"2020-04-26","id":35,"ip":"10.238.0.17","job_id":10,"value":23.0},{
     "date":"2020-04-26","id":36,"ip":"10.238.0.215","job_id":10,"value":17.25},{
     "date":"2020-04-25","id":37,"ip":"10.238.0.12","job_id":10,"value":18.5},{
     "date":"2020-04-25","id":38,"ip":"10.238.0.134","job_id":10,"value":18.5},{
     "date":"2020-04-25","id":39,"ip":"10.238.0.17","job_id":10,"value":18.75},{
     "date":"2020-04-25","id":40,"ip":"10.238.0.215","job_id":10,"value":50.5},{
     "date":"2020-04-24","id":41,"ip":"10.238.0.12","job_id":10,"value":4.5},{
     "date":"2020-04-24","id":42,"ip":"10.238.0.134","job_id":10,"value":4.5},{
     "date":"2020-04-24","id":43,"ip":"10.238.0.17","job_id":10,"value":17.5},{
     "date":"2020-04-24","id":44,"ip":"10.238.0.215","job_id":10,"value":4.25},{
     "date":"2020-04-23","id":45,"ip":"10.238.0.12","job_id":10,"value":31.75},{
     "date":"2020-04-23","id":46,"ip":"10.238.0.134","job_id":10,"value":44.75},{
     "date":"2020-04-23","id":47,"ip":"10.238.0.17","job_id":10,"value":32.25},{
     "date":"2020-04-23","id":48,"ip":"10.238.0.215","job_id":10,"value":32.25},{
     "date":"2020-04-22","id":49,"ip":"10.238.0.12","job_id":10,"value":19.25},{
     "date":"2020-04-22","id":50,"ip":"10.238.0.134","job_id":10,"value":19.25},{
     "date":"2020-04-22","id":51,"ip":"10.238.0.17","job_id":10,"value":34.75},{
     "date":"2020-04-22","id":52,"ip":"10.238.0.215","job_id":10,"value":28.75},{
     "date":"2020-04-21","id":53,"ip":"10.238.0.12","job_id":10,"value":23.75},{
     "date":"2020-04-21","id":54,"ip":"10.238.0.134","job_id":10,"value":23.75},{
     "date":"2020-04-21","id":55,"ip":"10.238.0.17","job_id":10,"value":23.75},{
     "date":"2020-04-21","id":56,"ip":"10.238.0.215","job_id":10,"value":23.75}],"message":"\u83b7\u53d6\u6570\u636e\u6210\u529f"}

​ 要想实现堆叠折线图效果,可以继续通过对ip分别进行请求,然后得到多个dataset,然后再option里面通过encode进行对应series的指定,但是这样涉及到多个异步请求并不合理。

​ 这里通过对所有ip数据进行一个本地的处理,再通过encode对多个dataset的支持(echarts3的数据设置方式series.data也可以)来对数据进行指定。堆叠折线图的示例option如下:

option = {
     
    title: {
     
        text: '折线图堆叠'
    },
    tooltip: {
     
        trigger: 'axis'
    },
    legend: {
     
        data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
    },
    grid: {
     
        left: '3%',
        right: '4%',
        bottom: '3%',
        containLabel: true
    },
    toolbox: {
     
        feature: {
     
            saveAsImage: {
     }
        }
    },
    xAxis: {
     
        type: 'category',
        boundaryGap: false,
        data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
    },
    yAxis: {
     
        type: 'value'
    },
    series: [
        {
     
            name: '邮件营销',
            type: 'line',
            stack: '总量',
            data: [120, 132, 101, 134, 90, 230, 210]
        },
        {
     
            name: '联盟广告',
            type: 'line',
            stack: '总量',
            data: [220, 182, 191, 234, 290, 330, 310]
        },
        {
     
            name: '视频广告',
            type: 'line',
            stack: '总量',
            data: [150, 232, 201, 154, 190, 330, 410]
        },
        {
     
            name: '直接访问',
            type: 'line',
            stack: '总量',
            data: [320, 332, 301, 334, 390, 330, 320]
        },
        {
     
            name: '搜索引擎',
            type: 'line',
            stack: '总量',
            data: [820, 932, 901, 934, 1290, 1330, 1320]
        }
    ]
};

​ 由于Echarts支持同时定义多个 dataset。系列可以通过 series.datasetIndex 来指定引用哪个 dataset。接下来需要处理所有ip数据生成多个dateset:

4.Stuck数据的重新组织,使用对象来存储多个键值对数组。

​ 按照设想的通过ip作为键值来分别对各个ip对应的基线值数据进行索引,那么普通的二维数组就不能够很方便的完成,这里使用一个对象 let StuckData = {};作为第一层来对各个数组提供存储空间,接下来通过以下代码就可以得到一个StuckData对象:

    let StuckData = {
     };
            let tips=data1.data;
            //生成二维数组空间
            for(var i=0;i<tips.length;i++){
     
              let ip=tips[i];
              //这样才能将变量作为一个对象的key,push进一个数组。
              StuckData[ip]=[]
            }
            //将所有ip的基线数据分别push进对应的ip数组中
            for(var i=0;i<that.allipdata.length;i++){
     
              let item=that.allipdata[i];
              let key=item.ip
              StuckData[key].push({
     
                ip:item.ip,
                date:item.date,
                id:item.id,
                job_id:item.job_id,
                value:item.value
              })
            }

5.各个ip数组的分别排序

这里需要注意的是关于键值对数组的排序,可以先看个例子:

<div id="app">
   <ul>
    <li v-for="(stu,index) in students1">{
     {
     stu}}</li>
   </ul>
  </div>
  <script type="text/javascript">
   new Vue({
     
    el:"#app",
    data:{
     
     students:[
      {
     name:"小a",age:20},
      {
     name:"小b",age:21},
      {
     name:"小c",age:18},
      {
     name:"小d",age:19},
      {
     name:"小f",age:18}
     ]
    },
    computed:{
     
     students1:function(){
     
      return sortKey(this.students,'age')
     }
    }
   })
   function sortKey(array,key){
     
    return array.sort(function(a,b){
     
     var x = a[key];
     var y = b[key];
     return ((x<y)?-1:(x>y)?1:0)
    })
   }
  </script>

​ 这里用到的是数组的sort方法,这个方法有一个需要注意的地方,就是不传参数的话,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。这并不是我们想要的排序方法,所以必须要传参。

​ sort方法的参数是一个函数,这个函数提供了一个比较方法,要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。

  1. 若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。
  2. 若 a 等于 b,则返回 0。
  3. 若 a 大于 b,则返回一个大于 0 的值。

​ 这里根据这个demo的实际情况进行一些处理:

  //处理堆叠数据
    makeStuckData(){
     
      var that = this;
      axios({
     
        method: 'get',
        url: "AIOPS-ALGORITHMS/service/baseline/ips",
        withCredentials: true,
        params: {
     }
      }).then(function(response) {
     
          const data1 = response.data
          if (data1['code'] == 1) {
     
            //数组是一个特殊的对象,这里使用对象来存储多个数组
            let StuckData = {
     };
            let tips=data1.data;
            //生成二维数组空间
            for(var i=0;i<tips.length;i++){
     
              let ip=tips[i];
              //这样才能将变量作为一个对象的key,push进一个数组。
              StuckData[ip]=[]
            }
            //将所有ip的基线数据分别push进对应的ip数组中
            for(var i=0;i<that.allipdata.length;i++){
     
              let item=that.allipdata[i];
              let key=item.ip
              StuckData[key].push({
     
                ip:item.ip,
                date:item.date,
                id:item.id,
                job_id:item.job_id,
                value:item.value
              })
            }
            //将对应ip数组中的数据根据date排序方便展示。
            //使用let i in能够获得对应键值
            for(let i in StuckData){
     
              StuckData[i].sort(that.sortDate('date'))
            }
            //获取结果
            console.log(StuckData)

        } else {
     
            that.$Modal.error({
     
            title: '失败',
            content: '服务器端获取可能出错,请检查!'
            })
          }
        })

    },
    //数组的时间sort方法
    sortDate(key){
     
      var that=this;
      return function(a,b){
     
        var key1 = a[key];
        var key2 = b[key];
        var t1=that.strDateForDate(key1);
        var t2=that.strDateForDate(key2);
        if(t1>t2){
     
          return 1;
        }
        else {
     
          return -1;
        }
      }
    },
    //时间字符串转为时间格式方便比较:2020-04-23
    strDateForDate(str){
     
    var strDate = str.split(" ");
    var strDatepart = strDate[0].split("-");
    var dtDate = new Date(strDatepart[0],strDatepart[1]-1,strDatepart[2]);
    return dtDate;
    },

6.图件的最终生成

​ 当获取到了对应的dataset后,那么可以生成对应的option并且进行渲染。

  //处理堆叠数据
    makeStuckData(){
     
      var that = this;
      axios({
     
        method: 'get',
        url: "AIOPS-ALGORITHMS/service/baseline/ips",
        withCredentials: true,
        params: {
     }
      }).then(function(response) {
     
          const data1 = response.data
          if (data1['code'] == 1) {
     
            //数组是一个特殊的对象,这里使用对象来存储多个数组
            let StuckData = {
     };
            let tips=data1.data;
            //生成二维数组空间
            for(var i=0;i<tips.length;i++){
     
              let ip=tips[i];
              //这样才能将变量作为一个对象的key,push进一个数组。
              StuckData[ip]=[]
            }
            //将所有ip的基线数据分别push进对应的ip数组中
            for(var i=0;i<that.allipdata.length;i++){
     
              let item=that.allipdata[i];
              let key=item.ip
              StuckData[key].push({
     
                ip:item.ip,
                date:item.date,
                id:item.id,
                job_id:item.job_id,
                value:item.value
              })
            }
            //将对应ip数组中的数据根据date排序方便展示。
            //使用let i in能够获得对应键值
            for(let i in StuckData){
     
              StuckData[i].sort(that.sortDate('date'))
            }
            //获取结果
            //console.log(StuckData)
            //将得到的数据放入dataset准备使用
            that.dataset=[];
            for(let i in StuckData){
     
              that.dataset.push({
     
                source:StuckData[i]
              })
            }
            //console.log(that.dataset)
            //准备堆叠图对应的options
            that.chartOption.series=[];
            for(let i=0;i<that.dataset.length;i++){
     
              that.chartOption.series.push({
     
                type: 'line',
                datasetIndex:i,
                encode: {
     
                  x: 'date',
                  y: 'value'
                }
              })
            }
            that.chartOption.dataset=that.dataset;
            that.lineChartDom.setOption(that.chartOption)


        } else {
     
            that.$Modal.error({
     
            title: '失败',
            content: '服务器端获取可能出错,请检查!'
            })
          }
        })

    },

效果图:

如何用Echarts+vue可视化动态基线分析结果demo_第4张图片

如何用Echarts+vue可视化动态基线分析结果demo_第5张图片

​ 优化一些细节,去掉不必要的代码,为图件加入标签等等,完整代码:

<template>
  <div>
    <row>
      <i-Col span="24">
        <div ref="lineChart" style="height:400px;"></div>
      </i-Col>
    </row>
    <row>
      <i-Col span="12" offset="2">
        <Select v-model="thisIp" clearable style="width:200px" placeholder="选择对应实体ip" @on-select="selectIp" @on-clear="clearSelectIp">
          <Option v-for="item in ips" :value="item.value" :key="item.id">{
     {
      item.value }}</Option>
        </Select>
        <Input placeholder="搜索对应实体" style="width: auto; margin: 10px 10px;" v-model="searchModel" :search=true @on-search="searchIp">
          <Icon type="ios-search" slot="suffix" />
        </Input>
        <Button style="margin: 10px 10px;" type="primary" @click="searchIp">搜索</Button>
      </i-Col>
    </row>
  </div>

</template>
<script>
import echarts from 'echarts'
import {
      on, off } from '@/libs/tools'
import axios from 'axios'
export default {
     
  name: 'demo',
  components: {
     

  },
  data() {
     
    return {
     
      lineChartDom : null,
      text:"动态基线展示",
      subtext:"分组展示",
      ips: [],
      thisIp:null,
      allipdata:[],
      searchModel:null,
      chartOption:{
     
        dataset: {
     
          source: [
            {
     "date":"2020-04-27","id":29,"ip":"10.238.0.12","job_id":10,"value":34.25},
            {
     "date":"2020-04-26","id":33,"ip":"10.238.0.12","job_id":10,"value":15.5},
            {
     "date":"2020-04-25","id":37,"ip":"10.238.0.12","job_id":10,"value":18.5},
            {
     "date":"2020-04-24","id":41,"ip":"10.238.0.12","job_id":10,"value":4.5},
            {
     "date":"2020-04-23","id":45,"ip":"10.238.0.12","job_id":10,"value":31.75},
            {
     "date":"2020-04-22","id":49,"ip":"10.238.0.12","job_id":10,"value":19.25},
            {
     "date":"2020-04-21","id":53,"ip":"10.238.0.12","job_id":10,"value":23.75}
          ]
        },
        tooltip: {
     
          trigger: 'axis'
        },
        title: {
     
          text: "动态基线Demo展示",
          subtext: "分组展示",
          x: 'center'
        },
        xAxis: {
     
          type: 'category',
          //强制显示所有横坐标不建议使用
          // axisLabel:{
     
          //  interval: 0
          // }
        },
        yAxis: {
     
          type: 'value',
        },
        series: [{
     

          type: 'line',
          encode: {
     
            x: 'date',
            y: 'value'
          }
        }]
      },
    }
  },
  methods: {
     
    resize(){
     
      this.lineChartDom.resize()
    },
    ipInit(){
     
      const that = this
    axios({
     
      method: 'get',
      url: "AIOPS-ALGORITHMS/service/baseline/ips",
      withCredentials: true,
      params: {
     }
    }).then(function(response) {
     
        const data1 = response.data
        if (data1['code'] == 1) {
     
          //传统方法
          // let tip=[];
          // for(var j = 0; j < data1.data.length; j++) {
     
          //   tip.push({
     
          //     value:data1.data[j],
          //     label:data1.data[j]
          //   })
          // }
          //vue的内置方法,mapfilter等等可以方便地对数据进行处理
          let nip=data1.data.map((item,i)=>{
     
              return {
     
                value:item,
                label:item
              }
          })
            that.ips=nip;
      } else {
     
          that.$Modal.error({
     
          title: '失败',
          content: '服务器端获取可能出错,请检查!'
          })
        }
      })
    },
    getDataset(tip){
     
      this.lineChartDom = echarts.init(this.$refs.lineChart)
      this.lineChartDom.setOption(this.chartOption)
      on(window, 'resize', this.resize)
        const that = this
        const param = {
     
          job_id:10,
          ip:tip
      }
      axios({
     
        method: 'get',
        url: "AIOPS-ALGORITHMS/service/baseline",
        withCredentials: true,
        params: param
      }).then(function(response) {
     
        const data1 = response.data
        if (data1['code'] == 1) {
     
          if(tip==null||tip==undefined){
     
            that.allipdata=data1.data
            that.makeStuckData();
          }
          else{
     
            if(data1.data.length>0){
     
              let dataset_order=data1.data.sort(that.sortDate('date'))
              that.chartOption.dataset=[{
     
                source:dataset_order
              }];
              that.chartOption.series=[{
     
                type: 'line',
                encode: {
     
                  x: 'date',
                  y: 'value'
                }
              }];
              that.chartOption.title.subtext="单点ip"
              //这里图件未刷新,可以看到对应的变化,meige参数为true触发图件刷新
              that.lineChartDom.setOption(that.chartOption,true)
            }
            else{
     
              that.$Modal.error({
     
                title: '失败',
                content: '该实体当前并没有基线数据,请检查参数'
              })
            }

          }

        } else {
     
          that.$Modal.error({
     
            title: '失败',
            content: '服务器端参数可能出错,请检查!'
          })
        }
        })
    },
    //处理堆叠数据
    makeStuckData(){
     
      var that = this;
      axios({
     
        method: 'get',
        url: "AIOPS-ALGORITHMS/service/baseline/ips",
        withCredentials: true,
        params: {
     }
      }).then(function(response) {
     
          const data1 = response.data
          if (data1['code'] == 1) {
     
            //数组是一个特殊的对象,这里使用对象来存储多个数组
            let StuckData = {
     };
            let tips=data1.data;
            //生成二维数组空间
            for(var i=0;i<tips.length;i++){
     
              let ip=tips[i];
              //这样才能将变量作为一个对象的key,push进一个数组。
              StuckData[ip]=[]
            }
            //将所有ip的基线数据分别push进对应的ip数组中
            for(var i=0;i<that.allipdata.length;i++){
     
              let item=that.allipdata[i];
              let key=item.ip
              StuckData[key].push({
     
                ip:item.ip,
                date:item.date,
                id:item.id,
                job_id:item.job_id,
                value:item.value
              })
            }
            //将对应ip数组中的数据根据date排序方便展示。
            //使用let i in能够获得对应键值
            for(let i in StuckData){
     
              StuckData[i].sort(that.sortDate('date'))
            }
            //获取结果
            //console.log(StuckData)
            //将得到的数据放入dataset准备使用
            that.chartOption.dataset=[];
            for(let i in StuckData){
     
              that.chartOption.dataset.push({
     
                source:StuckData[i]
              })
            }
            //准备堆叠图对应的options
            that.chartOption.series=[];
            console.log(that.chartOption.dataset[0].source[0].ip)
            for(let i=0;i<that.chartOption.dataset.length;i++){
     
              that.chartOption.series.push({
     
                name:that.chartOption.dataset[i].source[0].ip,
                type: 'line',
                datasetIndex:i,
                encode: {
     
                  x: 'date',
                  y: 'value'
                }
              })
            }
            that.chartOption.title.subtext="分组展示"
            that.lineChartDom.setOption(that.chartOption)


        } else {
     
            that.$Modal.error({
     
            title: '失败',
            content: '服务器端获取可能出错,请检查!'
            })
          }
        })

    },
    //数组的时间sort方法
    sortDate(key){
     
      var that=this;
      return function(a,b){
     
        var key1 = a[key];
        var key2 = b[key];
        var t1=that.strDateForDate(key1);
        var t2=that.strDateForDate(key2);
        if(t1>t2){
     
          return 1;
        }
        else {
     
          return -1;
        }
      }
    },
    //时间字符串转为时间格式方便比较:2020-04-23
    strDateForDate(str){
     
    var strDate = str.split(" ");
    var strDatepart = strDate[0].split("-");
    var dtDate = new Date(strDatepart[0],strDatepart[1]-1,strDatepart[2]);
    return dtDate;
    },
    selectIp (value) {
     
      this.getDataset(value)
    },
    clearSelectIp(){
     
      this.getDataset()
    },
    searchIp(value){
     
      this.thisIp=null;
      this.getDataset(this.searchModel)
    }
  },
  mounted(){
     
    this.ipInit();
    this.getDataset();
  },
  beforeDestroy () {
     
    off(window, 'resize', this.resize)
  }
}

</script>


最终效果:

如何用Echarts+vue可视化动态基线分析结果demo_第6张图片

你可能感兴趣的:(学习记录,可视化,vue,js,vue.js)