使用antV-G6在angualr中画树形关系图

 使用antV-G6在angualr中画树形关系图(流量追踪图)

公司有个需求就是既要呈现出每个节点之间的关系(图里面需要带箭头,为了表现出流向关系),又要排版呈现出树状结构,也就是说是具备层次关系的,这种图呢就相当于既不完全是树图,形状呢又不是关系图,我算是苦思冥想了。而且又是在angualr中,angualr中支持的第三方插件特别少,本来想采用echarts的树状图,但是发现,树图的每个节点不能有两个父节点,也就是说两个节点不能同时指向一个节点,后来就放弃了,接着我想采用echarts里面的关系图,但是发现关系图需要自己去定义每一个节点的坐标,这对于我们公司的需求有很多节点的情况下,是完全不可能实现的,后来引用了antV的G6,加上自己本身的一些构思,实现了以下效果:

 在angualr的你需要放入该图的组件的ts文件中的开头,需要加上以下两句话,insertCss可以先不写,这个是为了后面显示提示框而导入的,如果需要的话就安装(npm install insert-css)并导入,不需要可以省略。

import G6 from '@antv/g6';  // npm install --save @antv/g6  先安装后引入啊!!!
import insertCss from 'insert-css';  //npm install insert-css  先安装后引入啊!!!

首先定义一个全局变量的data,用于存放流程图的节点和边

 data = {
    // 点集
    nodes: [],
    // 边集
    edges: [],
  };

然后是html结构

<div class="tracing_right">
    <div id="mountNode" style="width: 98%;height:100%;margin: 0 auto;overflow-x: scroll;overflow-y: scroll"></div>
</div>

 然后需要定义一个render函数,当然可以随意取函数的名称,这里面的代码大多是参考G6里面的示例代码https://g6.antv.vision/zh/examples/net/dagreFlow#lrDagre,参数说明如下:

render(){
//这个是用于定义我图中的提示框,就是气泡的样式
    insertCss(`
      .g6-tooltip {
        border: 1px solid #8962FD;
        border-radius: 4px;
        font-size: 12px;
        color: #8962FD;
        background-color: rgba(255, 255, 255, 0.8);
        padding: 10px 8px;
        box-shadow: rgb(219, 208, 254) 0px 0px 10px;
        width:180px;
        height:60px;
        position:absolute;
        left:-100px;
        top:100px
      }
    `);


    const width = document.getElementById('mountNode').scrollWidth;
    const height = document.getElementById('mountNode').scrollHeight || 500;
    const graph = new G6.Graph({
      container: 'mountNode',
      width,
      height,
      fitView: true, //设置是否将图充满整个画布
      modes: {
        //这个是设置默认节点和默认边的地方,'zoom-canvas'这个参数的作用是可以对图进行鼠标滚动放大缩小,根据需求添加
        default: ['drag-canvas', 'drag-node','zoom-canvas',
//下面这个对象是设置提示框的显示内容,我用的是模板字符串显示的
        {
          type: 'tooltip',
//formatText这个函数的参数model代表的就是传入的每个节点的信息,包括名称之类的信息,在模板字符串中可以通过${model.参数名}去访问每个节点的信息,从而在提示框中显示
          formatText: function formatText(model) {
            const text =`
            <p style="width:180px;height:30px;float:left;line-height:30px;border-bottom:2px dashed rgba(219, 208, 254)">存活个数/总个数:${model.label}</p>
            `+'</br>'+`
            <p style="width:180px;height:30px;float:left;line-height:30px;">请求次数:${model.label}</p>
            `+'</br>';
            
            return text;
          },
         
        },],
      },
      layout: {
        type: 'dagre',
        rankdir: 'LR',
        align: 'DL',
        nodesepFunc: () => 3, //这个就是节点与节点之间的距离,可以说是纵向拉伸高度
        ranksepFunc: () => 30,//这个参数设置的是你的箭头距离节点的距离,值越大,图横向拉伸的越宽
      },
      defaultNode: {
        size: [30, 20],//节点的大小设置,宽高
        type: 'rect', //节点类型,rect就是长方形,还有圆形,菱形等,官网里有,也可以自定义
      },
      defaultEdge: {
        size: 1,    
        // type: 'line-growth',这个是自定义了边的动画,但是我没使用
        color: '#e2e2e2',     //边的颜色
        style: {
          endArrow: {         //设置边的末端箭头的样式,如果不需要箭头,不设置即可
            path: 'M 0,0 L 8,4 L 8,-4 Z',
            fill: '#e2e2e2'
          },
        },
        labelCfg: {
          autoRotate: true,  //设置边上面的标签的样式
          refY: 8,         //边标签的文字与边的距离
          style: {    
            fontSize:10,   //设置边标签的字体大小
            
          },
        },
      },
      
    });
    graph.clear(); //后面三行照常复制粘贴即可

    graph.data(this.data);
    graph.render();
    
  }
// 第一次加载获取结构图,这个是我设置的点击事件,我们公司需求就是点击按钮触发流程图的加载
  getStructureData=(minServiceName)=>{
    var self = this
    var m = 300
    var n = 300
    
    self.data = {nodes:[],edges :[]}
    self.pingArr = []
    console.log(self.data)
    
     self.ajax.getAjax("/management/kiali/graph","post",{"namespace":minServiceName},function(data){  //这个是我调用的接口,你们可以直接按照官网上的案例,在开头定义死数据,进行测试,我对接口里面数据的处理,你们可以不看
      console.log(data)
      for(var i=0;i<data.length;i++){
        self.pingData = {}
        self.pingData["id"] = data[i].data.id
        self.pingData["parentId"] = data[i].data.parentId
        self.pingData["name"] = data[i].data.name
        self.pingData["color"] = data[i].data.color
        self.pingData["nodeType"] = data[i].data.nodeType
        self.pingData["responseTime"] = data[i].data.responseTime
        self.pingArr.push(self.pingData)
      }
      console.log(self.pingArr)
//下面就是我掉完接口之后拿到的数据进行遍历,然后往直前定义的节点和边的数组中塞
      for(var i=0;i<self.pingArr.length;i++){
        if(self.pingArr[i].nodeType == "version"){ //我是对节点类型进行了判断,不同类型的节点,设置节点的颜色不一样,就如图中两种节点
          self.data.nodes.push(
            {
              id: self.pingArr[i]["id"],
              label: self.pingArr[i]["name"],
              description: 'This is node-1.',
              style:{ //这个style就是专门设置节点的样式的
                width: 48,
                height: 18,
                radius: 10,
                stroke: '#8962FD', //节点边框颜色
                fill: '#8962FD',   //节点背景色
                lineWidth:5,       //边框宽度
                strokeOpacity:0.3, //边框透明度
              },
              labelCfg: {   //这个就是节点里面文字的样式设置
                style: {
                  fill: '#fff',
                  fontSize: 10,
                },
                position: 'center',
              },
            },
          )
        }else if(self.pingArr[i].nodeType == "service"){ 
                                    //这里如上,如果不区分节点的话可以忽略
          self.data.nodes.push(
            {
              id: self.pingArr[i]["id"],
              label: self.pingArr[i]["name"],
              description: 'This is node-1.',
              style: {
                width: 60,
                height: 25,
                radius: 10,
                stroke: '#8962FD',
                fill: '#fff',
                lineWidth:1.5,
                strokeOpacity:0.6
              },
              labelCfg: {
                style: {
                  fill: '#8962FD',
                  fontSize: 10,
                },
                position: 'center',
              },
            },
          )
        }

        //下面是我放入边的循环结构
        if(self.pingArr[i]["parentId"].length>=1){
          for(var j=0;j<self.pingArr[i]["parentId"].length;j++){
            self.data.edges.push(
              {
                source: self.pingArr[i]["parentId"][j],
                target: self.pingArr[i]["id"],
                // label:  self.pingArr[i]["responseTime"],
                label:  '30ms',  //这个就是边上面显示的标签的内容,我写死的
                color:  self.pingArr[i]["color"], //设置边的颜色
                style: {    //设置边的箭头的样式,如果不需要箭头,这个endArrow可以不写
                  endArrow: {
                    path: 'M 0,0 L 8,4 L 8,-4 Z',
                    fill: self.pingArr[i]["color"],
                  },
                },
              },
            )

          }
        }
      }
      setTimeout( ()=>{
        self.render()
      },100) //这里就是调用之前定义好的render渲染函数,上面掉接口之后放入数据之后,必须要重新调用render函数去渲染画布的,不然不显示,这里我延时了100ms再调用render函数的原因就是防止加载的时候出现dom无定义的情况,必须要加上延时器。
    })
  }

 这两天写关系图,对antv的G6有了不少的了解,但是我百度搜索一些关于G6的东西的时候,发现几乎没有,可能还是用的少吧,因此,我写了这个博客,欢迎大家参考G6的使用方法,它还是挺好用的!!!!

还有一种是节点可增删改的树形结构图,vue写的,可参考一下:

https://blog.csdn.net/qq_41579104/article/details/113388616

效果是这样:

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

suoh's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值