antv/g6绘制数据流向图

news2024/12/23 11:57:52

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.coloradmin.cn/o/1407718.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UCAS-AOD遥感旋转目标检测数据集——基于YOLOv8obb,map50已达96.7%

1.UCAS-AOD简介 1.1数据说明 遥感图像&#xff0c;又名高分辨率遥感图像。遥感图像的分类依据是根据成像的介质不同来进行分类的。UCAS-AOD (Zhu et al.&#xff0c;2015)用于飞机和汽车的检测&#xff0c;包含飞机与汽车2类样本以及一定数量的反例样本&#xff08;背景&…

【arthas诊断CPU和内存问题实战】thread -n 5 + cpu火焰图 +内存火焰图

通过线程信息分析CPU 1.查看线程信息 step1: 先查看哪个线程占比cpu最高 分析&#xff1a; 可与看出 SceneWorker占比最高&#xff0c;但是是哪个类中哪个方法则不是太清楚。 我们还需要去分析代码&#xff1a; step2.分析代码 1.AbstractSceneManager的 this.sceneWorke…

DES算法的局限性与改进需求

DES算法的局限性与改进需求 DES算法是一种对称加密算法&#xff0c;具有高度的安全性和可靠性。然而&#xff0c;随着计算机技术的发展&#xff0c;DES算法的密钥长度逐渐被攻击者攻破&#xff0c;安全性受到威胁。因此&#xff0c;对DES算法进行改进以提高安全性是必要的。 3…

数字创新巨头PLAN B KRYPTO ASSETS普兰资产管理

Schutz AI金融隐私匿名公链引领全球数字金融浪潮 随着摩根大通推出颠覆性的「IndexGPT」软件服务&#xff0c;AI在金融领域的发展愈发引人瞩目。而PLAN B KRYPTO ASSETS普兰资产管理公司正积极响应这一变革&#xff0c;推出的Schutz AI金融隐私匿名公链成为全球关注的焦点。 在…

java web mvc-06-play framework intro

拓展阅读 Spring Web MVC-00-重学 mvc mvc-01-Model-View-Controller 概览 web mvc-03-JFinal web mvc-04-Apache Wicket web mvc-05-JSF JavaServer Faces web mvc-06-play framework intro web mvc-07-Vaadin web mvc-08-Grails 开源 The jdbc pool for java.(java …

Oracle2-Rollup和Cube用法

在Oracle的聚合函数中&#xff0c;会有按照维度统计的情况,比如上图按照job 和 deptno统计 sal的sum 但是也会遇到同时要求统计只按照job维度统计的情况&#xff0c;并且做到一张表里 1 union 来实现维度不一致 首先反应过来的是分两步查询&#xff0c;再讲结果union起来 s…

使用axios库创建实例的示例,(创建实例时,传入了一个配置对象)同时还包含了请求拦截器和响应拦截器

第一步&#xff1a; 在vue项目中src目录下创建utils>request.js 第二步&#xff1a; 在 request.js中&#xff0c;使用axios.create方法创建了一个名为request的axios实例&#xff08;设置基本配置信息&#xff09;通过request.interceptors.request.use方法添加了请求拦…

html页面练习——公司发展流程图

1.效果图 2.html <div class"center"><header><h1>发展历程</h1><h3>CONMPANY HISTORY</h3></header><main><div class"left"><div class"time1">2012.12</div><div cla…

WebRTC之服务器搭建

前言 在前面的WebRTC介绍中我们已经介绍了WebRTC的编译以及成功地把WebRTC在Android Studio中运行了起来&#xff0c;详情请猛击<WebRTC之Android编译> 《WebRTC导入Android Studio》 在后面的学习过程中&#xff0c;我们将进一步使用WebRTC实现Android端的实时通信对话…

【JAVA】Java并发编程中的锁升级机制

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;JAVA ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 四个级别锁 锁升级的过程&#xff1a; 偏向锁升级为轻量级锁&#xff1a; 轻量级锁升级为重量级锁&#xff1a; 结语 我的其他…

vue3 中组合键 command+Enter / shift+Enter / alt + Enter 实现换行,详细实现

vue3 中组合键实现换行 需求背景 有一个聊天室功能&#xff0c;采用输入框的形式&#xff0c;输入完毕使用Enter&#xff0c;可以直接进行发送。使用一些组合键 比如 commandEnter / shiftEnter / alt Enter … 可以实现换行操作。但现实的情况是&#xff0c;原生 Enter 天然…

DC-9靶机做题记录

靶机下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1LR44-oFnO6NU6bTNs7VNrw?pwdhzke 提取码&#xff1a;hzke 参考&#xff1a; 【DC系列靶机DC9通关讲解】 https://www.bilibili.com/video/BV1p24y1s78C/?share_sourcecopy_web&vd_source12088c392…

推特Twitter账号被冻结?IP代理选对了吗?

Twitter 拥有庞大的用户群和日常内容流&#xff0c;是沟通、网络和营销的重要平台。然而&#xff0c;处理其限制和潜在的帐户问题可能很棘手。有许多跨境社媒小伙伴反馈&#xff0c;账号无故被冻结&#xff0c;导致内容与客户尽失&#xff01;其实除了账户养号、被举报、广告信…

MySQL--删除数据表(6)

MySQL中删除数据表是非常容易操作的&#xff0c;但是你在进行删除表操作时要非常小心&#xff0c;因为执行删除命令后所有数据都会消失。 语法 以下为删除 MySQL 数据表的通用语法&#xff1a; DROP TABLE table_name ; -- 直接删除表&#xff0c;不检查是否存在 或 DROP…

【MIdjourney】五个特殊物体关键词

1.碳酸(Carbonate) 这一词语的本意是指包含碳&#xff08;C&#xff09;、氧&#xff08;O&#xff09;和氢&#xff08;H&#xff09;元素的化合物。而在MIdjourney中添加该词汇会使得生成的图片具有水滴效果且富有动态感。 2.灯丝(Filament) Filament效果可能包括更逼真的…

Unity中URP下获取额外灯数量

文章目录 前言一、SimpleLit下额外灯数量的获取1、在 SimpleLit 下&#xff0c;先获取了额外灯的数量2、对其进行循环计算每一个额外灯3、GetAdditionalLightsCount在这里插入图片描述 二、GetAdditionalLightsCount实现了什么1、_AdditionalLightsCount.x2、unity_LightData.y…

【Leetcode】2765. 最长交替子数组

文章目录 题目思路代码结果 题目 2765. 最长交替子数组 题目&#xff1a;给你一个下标从 0 开始的整数数组 nums 。如果 nums 中长度为 m 的子数组 s 满足以下条件&#xff0c;我们称它是一个 交替子数组 &#xff1a; m 大于 1 。 s1 s0 1 。 下标从 0 开始的子数组 s 与…

JL-03-Q6 校园气象站

产品概述 校园气象站针对测量与环境、科学研究等相关的气象指标进行设计制造&#xff0c;气象站对采集数据信息以图表、数据的形式真实、直观的反应当前环境数据指标。可通过各种传感器对气压、气温、相对湿度、风向、风速、雨量、太阳辐射、乃至空气质量等要素进行采集、存储…

【数学建模】综合评价方法

文章目录 综合评价的基本理论和数据预处理综合评价的基本概念综合评价体系的构建综合指标的预处理方法评价指标预处理示例 常用的综合评价数学模型线性加权综合评价模型TOPSIS法灰色关联度分析熵值法秩和比&#xff08;RSR&#xff09;法综合评价示例 综合评价的基本理论和数据…

基于SSM的企业文档管理系统

末尾获取源码作者介绍&#xff1a;大家好&#xff0c;我是何时&#xff0c;本人4年开发经验&#xff0c;专注定制项目开发 更多项目&#xff1a;CSDN主页YAML 我欲乘风归去 又恐琼楼玉宇 高处不胜寒 -苏轼 一、项目简介 现代经济快节奏发展以及不断完善升级的信息化技术&…