antv/g6绘制数据流向图

antv/g6绘制数据流向图

  • 前言
    • 接口模拟数据
    • html
    • ts
    • 页面效果

前言

在业务开发中需要绘制数据流向图,由于echarts关系图的限制以及需求的特殊要求,转而使用antv/g6实现,本文以代码的方式实现数据流向需求以及节点分组,版本"@antv/g6": “^4.8.24”,

本文主要列出关键性的代码,并非全部代码

接口模拟数据

getCenterFlowG6ApiV2(data = {}) {
    return new Promise((resolve) => {
      let nodes: any = []
      for (let i = 1; i <= 14; i++) {
        let node: any = { id: "node-" + i, label: "node-" + i }
        if (i % 3 === 0) {
          node.class = "c0"
        } else if (i % 3 === 1) {
          node.class = "c1"
        } else if (i % 3 === 2) {
          node.class = "c2"
        }
        nodes.push(node)
      }

      const res = {
        "resultStat": "0",
        "failCode": null,
        "mess": "获取流向成功",
        "callBack": null,
        "data": {
          nodes: [
            {
              id: "4",
              label: "业务数据库A",
              comboId:"group0",
              imgType:"14",
              "pointNodeDetail": {
                "nodeName": "武汉关",
                "nodeTypeName": "应用安全域",
                "areaName": "武汉关",
                "areaIpScope": "160.1.1.1-255.255.255.255",
                "areaBelong": "tanzhi",
                "areaType": "办公网接入域"
              },
            }, {
              id: "8",
              label: "业务数据库B",
              comboId:"group1",
              imgType:"10"
            },{
              id: "10",
              label: "主机166.10.1.1",
              comboId:"group2"
            },{
              id: "12",
              label: "主机161.19.1.4",
              comboId:"group4"
            }, {
              id: "14",
              label: "业务数据库B",
              comboId:"group3"
            }
          ],
          edges: [
            {
              eid: "4-8",
              source: "4",
              target: "8",
            },{
              eid: "8-4",
              source: "8",
              target: "4",
            },{
              eid: "10-4",
              source: "10",
              target: "4",
            },{
              eid: "10-8",
              source: "10",
              target: "8",
            },{
              eid: "12-8",
              source: "12",
              target: "8",
              style:{
                stroke: 'red', // 线的颜色
              }
            },{
              eid: "4-14",
              source: "4",
              target: "14",
            }
          ],
          combos: [
            {
              id:'group0',
              label:'信息中心',
              collapsed: true,// 初始时,收起,不展示内部节点
              style:{
                fill: "r(0.5,0.5,0.9) 0.6:#f8fcff 1:#3b97f1",
                opacity: 0.2
              }
            },
            {
              id:'group1',
              label:'数据分析中心',
              parentId:'group0',
              collapsed: true,
              style:{
                fill:"#FCCBAE"
              }
            },
            {
              id:'group2',
              label:'数据采集',
              collapsed: true,
              style:{
                fill:"#ECF7CF"
              }
            },
            {
              id:'group3',
              label:'业务办公区',
              parentId:'group0',
              collapsed: true,
              style:{
                fill:"#CECFD1"
              }
            },
            {
              id:'group4',
              label:'某地海关',
              collapsed: true,
              style:{
                fill:"#D1E9FF"
              }
            }
          ]
        },
        "redirectURL": null,
        "total": null
      }
      resolve(res)
    })
  }

html

<div class="echart-box">
    <div class="chart1" id="charts1" *ngIf="chartData.data != null && !pageLoading" ></div>
</div>  

ts


import G6 from "@antv/g6"

import equipment from "../../../../assets/equipment.png"
import equipmentE from "../../../../assets/equipmentE.png"
import equipmentY from "../../../../assets/equipmentY.png"
import application from "../../../../assets/application.png"
import assetsE from "../../../../assets/assetsE.png"
import assetsY from "../../../../assets/assetsY.png"
import assets from "../../../../assets/assets.png"
import domain from "../../../../assets/domain.png"
import domainE from "../../../../assets/domainE.png"
import domainY from "../../../../assets/domainY.png"
import warning from "../../../../assets/warning.png"
import warningY from "../../../../assets/warningY.png"

import clusterAsset from "../../../../assets/clusterAsset.png"
import clusterAssetY from "../../../../assets/clusterAssetY.png"
import clusterAssetR from "../../../../assets/clusterAssetR.png"
import belongCenterY from "../../../../assets/belongCenterY.png"
import belongCenter from "../../../../assets/belongCenter.png"
import belongCenterR from "../../../../assets/belongCenterR.png"
import netDomain from "../../../../assets/netDomain.png"
import netDomainR from "../../../../assets/netDomainR.png"
import netDomainY from "../../../../assets/netDomainY.png"
import groupIcon from "../../../../assets/chart/img/g6/群组_02.png";

/**
     * 加载流向图
     */
    getDataFlow() {
        this.pageLoading = true
        this.apiService.getCenterFlowG6ApiV2(removeNullProperty({
            ...this.q
        })).then((res: resType) => {
            console.log(res);
            if (res.resultStat === "0") {
                this.chartData.data = this.transformData(res.data)
                console.log(this.chartData.data);

                setTimeout(() => {
                    this.initG6DataFlow(this.chartData.data)
                }, 300);

            }
            this.pageLoading = false
        }).catch(err => {
            this.pageLoading = false
        })
    }
    
    initG6DataFlow(data) {
        let rectWidth = 800
        let rectHeight = 600
        const eContainer = document.getElementById("charts1")
        if (eContainer) {
            if (data.nodes.length < 100) {
                eContainer.style.height = '100%'  // 600px
                eContainer.style.minHeight = '600px'  // 600px
                eContainer.style.width = '100%'  // 800px
            } else {
                eContainer.style.height = '1080px'
                eContainer.style.width = '1920px'
            }

            const rectObject = eContainer.getBoundingClientRect()
            rectWidth = rectObject.right - rectObject.left
            rectHeight = rectObject.bottom - rectObject.top;
            console.log(rectObject);
            console.log(rectWidth, rectHeight);
        }

        const graph = new G6.Graph({
            container: 'charts1', // String | HTMLElement,必须,在 Step 1 中创建的容器 id 或容器本身
            width: rectWidth - 10, // Number,必须,图的宽度
            height: rectHeight - 10, // Number,必须,图的高度
            fitView: false, // 将图适配到画布
            fitViewPadding: 50, // 画布四周留白宽度
            // 必须将 groupByTypes 设置为 false,带有 combo 的图中元素的视觉层级才能合理
            groupByTypes: false,
            fitCenter: true,
            linkCenter: false,
            //autoPaint: true,
            
            layout: {
                type: 'comboCombined',
                spacing: 20,
                comboPadding: 5
            },
            modes: {
                // 允许拖拽画布、放缩画布、拖拽节点,
                default: [
                    'drag-canvas',
                    'zoom-canvas',
                    {
                        type: 'drag-node',
                        onlyChangeComboSize: true,
                    },
                    {
                        type: "drag-combo",
                        enableDelegate: false,
                        onlyChangeComboSize: true,
                    },
                    {
                        type: 'collapse-expand-combo',
                        trigger: 'click',
                        relayout: false, // 收缩展开后,不重新布局
                    },
                    {
                        type: 'tooltip', // 提示框
                        formatText(model) {
                            // 提示框文本内容
                            const text = 'label: ' + model.label + '<br/> class: ' + model.class;
                            return text;
                        },
                        shouldUpdate: e => {
                            return true;
                        }
                    },
                    {
                        type: 'edge-tooltip', // 边提示框
                        formatText(model) {
                            // 边提示框文本内容
                            const text =
                                'source: ' +
                                model.source +
                                '<br/> target: ' +
                                model.target +
                                '<br/> weight: ' +
                                (model.weight || "");
                            return text;
                        },
                        shouldUpdate: e => {
                            return true;
                        }
                    }
                ],

            },
            defaultNode: {// 默认状态下的节点配置
                size: 30,
                // 节点样式配置
                style: {
                    fill: 'steelblue', // 节点填充色
                    stroke: '#666', // 节点描边色
                    lineWidth: 2, // 节点描边粗细
                },
                // 节点上的标签文本配置
                labelCfg: {
                    // 节点上的标签文本样式配置
                    style: {
                        fill: '#333', // 节点标签文字颜色
                        stroke: '#fff',
                    },
                    position:"bottom"
                },
            },
            defaultEdge: {// 默认状态下的边配置
                style: {
                    //opacity: 0.6, // 边透明度
                    lineWidth: 4, // 线宽
                    stroke: '#D6ECF3', // 线的颜色
                    //endArrow: true,// 默认箭头
                    endArrow: { // 自定义终点箭头
                        path: G6.Arrow.vee(5, 10, 10), // 使用内置箭头路径函数,参数为箭头的 宽度、长度、偏移量(默认为 0,与 d 对应)
                        d: 10
                    }
                },
                // 边上的标签文本配置
                labelCfg: {
                    autoRotate: true, // 边上的标签文本根据边的方向旋转
                    refY: 10,
                },
            },
            defaultCombo: {
                collapsed: true,
                padding:5,
                labelCfg:{
                    "style": {
                        "fontSize": 12,
                        "fill": "r(0.5,0.5,0.1)  0:#ffffff 1:#555555",
                        "opacity": 1,
                        "stroke": "#fff",
                        "lineWidth": 1,
                        "fontFamily": "微软雅黑",
                        "text": "信息中心"
                    },
                    "position": "top"
                },
                collapsedSubstituteIcon: { // 群组收起时的图标
                    show: true,
                    img: groupIcon,
                    height: 30,
                    width: 30,
                  },
            },
            // 节点不同状态下的样式集合
            nodeStateStyles: {
                // 鼠标 hover 上节点,即 hover 状态为 true 时的样式
                hover: {
                    fill: 'lightsteelblue',
                },
                // 鼠标点击节点,即 click 状态为 true 时的样式
                click: {
                    stroke: '#000',
                    lineWidth: 3,
                },
            },
            // 边不同状态下的样式集合
            edgeStateStyles: {
                // 鼠标点击边,即 click 状态为 true 时的样式
                click: {
                    stroke: 'steelblue',
                },
            },
        });

        if (this.chartData.instance) {
            this.chartData.instance.destroy()
        }
        this.chartData.instance = graph
        graph.data(data); // 读取 Step 2 中的数据源到图上
        graph.render(); // 渲染图
        graph.get('canvas').set('localRefresh', false)
        // 监听鼠标进入节点
        graph.on('node:mouseenter', (e) => {
            const nodeItem = e.item;
            // 设置目标节点的 hover 状态 为 true
            graph.setItemState(nodeItem, 'hover', true);
        });
        // 监听鼠标离开节点
        graph.on('node:mouseleave', (e) => {
            const nodeItem = e.item;
            // 设置目标节点的 hover 状态 false
            graph.setItemState(nodeItem, 'hover', false);
        });
        // 监听鼠标点击节点
        graph.on('node:click', (e) => {
            console.log(e);
            this.pointNodeDetail = e.item._cfg.model.pointNodeDetail
            // 先将所有当前有 click 状态的节点的 click 状态置为 false
            const clickNodes = graph.findAllByState('node', 'click');
            clickNodes.forEach((cn) => {
                graph.setItemState(cn, 'click', false);
            });
            const nodeItem = e.item;
            // 设置目标节点的 click 状态 为 true
            graph.setItemState(nodeItem, 'click', true);
        });
        // 监听鼠标点击节点
        graph.on('edge:click', (e) => {
            // 先将所有当前有 click 状态的边的 click 状态置为 false
            const clickEdges = graph.findAllByState('edge', 'click');
            clickEdges.forEach((ce) => {
                graph.setItemState(ce, 'click', false);
            });
            const edgeItem = e.item;
            // 设置目标边的 click 状态 为 true
            graph.setItemState(edgeItem, 'click', true);
        });
    }
    
     /**
     * 对接口数据进行加工
     */
    transformData(data) {
        for (let i = 0; i < data.nodes.length; i++) {
            let node = data.nodes[i]
            console.log(node);
            if (!node.style) {
                node.style = {}
            }

            switch (
            node.class // 根据节点数据中的 class 属性配置图形
            ) {
                case 'c0': {
                    node.type = 'circle'; // class = 'c0' 时节点图形为 circle
                    break;
                }
                case 'c1': {
                    debugger
                    node.type = 'rect'; // class = 'c1' 时节点图形为 rect
                    node.size = [35, 20]; // class = 'c1' 时节点大小
                    break;
                }
                case 'c2': {
                    node.type = 'ellipse'; // class = 'c2' 时节点图形为 ellipse
                    node.size = [35, 20]; // class = 'c2' 时节点大小
                    break;
                }
            }
            if(node.imgType){
                this.transNodeImg(node)
            }


        }

        return data
    }
    
    /**
     * 根据类型设置image图标
     * @param node 
     */
    transNodeImg(node) {
        node.type = 'image'; 
        node.size = 30
        switch (
        node.imgType // 根据节点数据中的 class 属性配置图形
        ) {
            case '1': {
                node.img = domain
                break;
            }
            case '2': {
                node.img = equipment
                break;
            }
            case '3': {
                node.img = assets
                break;
            }
            case '4': {
                node.img = application
                break;
            }
            case '5': {
                node.img = domainY
                break;
            }
            case '6': {
                node.img = equipmentY
                break;
            }
            case '7': {
                node.img = assetsY
                break;
            }
            case '8': {
                node.img = warningY
                break;
            }
            case '9': {
                node.img = domainE
                break;
            }
            case '10': {
                node.img = equipmentE
                break;
            }
            case '11': {
                node.img = assetsE
                break;
            }
            case '12': {
                node.img = warning
                break;
            }
            case '13': {
                node.img = clusterAsset
                break;
            }
            case '14': {
                node.img = belongCenter
                break;
            }
            case '15': {
                node.img = belongCenter
                break;
            }
            case '16': {
                node.img = netDomain
                break;
            }
            case '17': {
                node.img = clusterAssetY
                break;
            }
            case '18': {
                node.img = belongCenterY
                break;
            }
            case '19': {
                node.img = belongCenterY
                break;
            }
            case '20': {
                node.img = netDomainY
                break;
            }
            case '21': {
                node.img = clusterAssetR
                break;
            }
            case '22': {
                node.img = belongCenterR
                break;
            }
            case '23': {
                node.img = belongCenterR
                break;
            }
            case '24': {
                node.img = netDomainR
                break;
            }

        }
    }

页面效果

image.png

image.png

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/347760.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

爬虫js逆向分析——x平台(前置知识:python执行js代码)

import execjs# 读取到js字符串 with open(v1.js, moderb) as f:js_string f.read().decode(utf-8)JSCode execjs.compile(js_string)# 调用js代码&#xff0c;如果有参数则依次往后逗号&#xff0c;写 res JSCode.call(test, eric)print(res)js文件中正常写代码即可。

前端vue集成echarts图形报表样例

文章目录 &#x1f412;个人主页&#x1f3c5;Vue项目常用组件模板仓库&#x1f4d6;前言&#xff1a;&#x1f415;1.在项目终端下载echarts依赖包&#x1f3e8;2.在main.js中导入echarts资源包并使用&#x1f380;3.在.vue文件中直接使用echarts&#xff0c;下面是一个样例&a…

Unity 组合模式(实例详解)

文章目录 示例1&#xff1a;Unity中的图形界面元素组合示例2&#xff1a;Unity中的游戏对象层级组合示例3&#xff1a;Unity中的场景图节点组合 在Unity中&#xff0c;组合模式&#xff08;Composite Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许你将对象组合成…

构建未来的数字世界:创新开放API接口认证解决方案

目录 1、引言 1.1 数字世界的发展 1.2 API接口的重要性 1.3 API接口认证的挑战 2、现有的API接口认证解决方案 2.1 基于令牌的认证方法 2.2 OAuth认证 2.3 OpenID认证 2.4 API密钥认证 3、创新开放API接口认证解决方案 3.1 双因素认证 3.2 生物特征认证 3.3 区块链…

Information Symmetry Matters

RG means ‘Relation Guidance’ 辅助信息 作者未提供代码

MySQL 初识MySQL

目录 1 数据库1.1 前言1.2 数据库分类1.2.1 关系型数据库&#xff08;RDBMS&#xff09;1.2.2 非关系型数据库1.2.3 关系型数据库与非关系型数据库的区别 2 链接数据库3 SQL分类4 存储引擎 1 数据库 1.1 前言 到底什么是MySQL? 大家都知道MySQL叫做数据库。那么什么是数据库…

系统架构15 - 软件工程(3)

软件过程模型 瀑布模型特点缺点 原型化模型特点两个阶段不同类型注意 螺旋模型V 模型特点 增量模型特点 喷泉模型基于构件的开发模型(CBSD)形式化方法模型敏捷模型特点“适应性” (adaptive) 而非“预设性” (predictive)“面向人的” (People-oriented) 而非“面向过程的” (P…

vue2、vue3,生命周期详解

一、Vue2.x Vue2的生命周期 是指Vue实例从创建到销毁的整个过程中&#xff0c;会经历一系列的阶段和回调函数。它分为8个阶段&#xff0c;包括了组件的创建、挂载、更新和销毁等过程。 1、beforeCreate: 在实例初始化之后&#xff0c;但在数据观测和事件配置之前被调用。此…

【Linux编译器-gcc/g++使用】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 设计样例&#xff0c;先见一下 方案一&#xff1a; 方案二&#xff1a; 在企业里面一般维护软件的源代码的话&#xff0c;要维护几份&#xff1f; 方案一&…

如何在短时间内制作出专业的产品说明书模板

产品说明书是企业向客户介绍产品的重要工具&#xff0c;能够直观地展示产品特点、功能以及使用方法。一个好的产品说明书模板可以帮助企业在短时间内制作出专业的产品说明书。那么怎样去做这个产品说明书模板呢&#xff1f;其实主要关注以下几个关键要素。 | 一、明确产品需求和…

x-cmd pkg | 7za - 7-Zip 的命令行版本

目录 简介首次用户主要特征竞品和相关作品进一步阅读 简介 7za 是一个开源的文件压缩和解压工具&#xff0c;是 7-Zip 的命令行版本。 7z 是一种拥有极高压缩比的格式&#xff0c;7za 提供压缩&#xff0c;解压&#xff0c;列举文件等功能除此之外&#xff0c;7za 还支持多种…

多维时序 | Matlab实现EVO-TCN-Multihead-Attention能量谷算法优化时间卷积网络结合多头注意力机制多变量时间序列预测

多维时序 | Matlab实现EVO-TCN-Multihead-Attention能量谷算法优化时间卷积网络结合多头注意力机制多变量时间序列预测 目录 多维时序 | Matlab实现EVO-TCN-Multihead-Attention能量谷算法优化时间卷积网络结合多头注意力机制多变量时间序列预测效果一览基本介绍程序设计参考资…

jQuery语法知识(DOM操作)

一、class 属性: .addClass&#xff08;&#xff09;、.hasClass&#xff08;&#xff09;.removeClass&#xff08;&#xff09;、.toggleClass&#xff08;&#xff09; 二、DOM 插入并包裹现有内容 1、.wrap( wrappingElement): 在每个配的元素外层包上一个html元素。 …

Day45 动态规划part07 70.爬楼梯(进阶) 322. 零钱兑换 279. 完全平方数

动态规划part07 70.爬楼梯&#xff08;进阶&#xff09; 322. 零钱兑换 279. 完全平方数 70.爬楼梯&#xff08;进阶&#xff09;&#xff08;题目链接点我&#xff09; #include<iostream> #include<vector> using namespace std;int main(){int n,m;cin>>…

vit细粒度图像分类(一)CADF学习笔记

1.摘要&#xff1a; 目的 基于Transformer架构的网络在图像分类中表现出优异的性能。然而&#xff0c;注意力机制往往只关注图像中的显著性特征&#xff0c;而忽略了其他区域的次级显著信息&#xff0c;基于自注意力机制的Transformer也是如此。为了获取更多的有效信息&#…

基于51单片机的智能烘干机设计

基于51单片机的智能烘干机设计[proteus仿真] 温湿度检测系统这个题目算是课程设计和毕业设计中常见的题目了&#xff0c;本期是一个基于51单片机的智能烘干机设计 需要的源文件和程序的小伙伴可以关注公众号【阿目分享嵌入式】&#xff0c;赞赏任意文章 2&#xffe5;&#x…

python高级(1): 迭代器详解

文章目录 1. 迭代器与可迭代对象(Iterable)1.1 可迭代对象(Iterable)1.2 迭代器( Iterator) 2. 自定义一个可迭代器2.1 实现迭代器2.2 for 遍历迭代器的过程 3. yolov8 Dataset实现案例 Python迭代器的作用是提供一种遍历数据集合的方式。它是一个可以被迭代的对象&#xff0c;…

使用 Redis 的 List 数据结构实现分页查询的思路

假设有一个存储数据的 List&#xff0c;每个元素代表一个记录&#xff0c;例如 recordsList。 按页存储数据&#xff1a; 每页存储一定数量的记录。例如&#xff0c;第一页存储索引 0 到 N-1 的记录&#xff0c;第二页存储索引 N 到 2N-1 的记录&#xff0c;以此类推。 分页查…

文件上传到本地

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>上传文件</title> </head> <body><form action"/upload" method"post" enctype"multipart/form-data&…

小黑艰难的前端啃bug之路:内联元素之间的间隙问题

今天开始学习前端项目&#xff0c;遇到了一个Bug调了好久&#xff0c;即使margin为0&#xff0c;但还是有空格。 小黑整理&#xff0c;用四种方法解决了空白问题 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></tit…