【前端工具】使用Echats生成关系图谱,可展开折叠

news2024/12/26 23:05:15

目录

一、需求背景与效果

二、echarts源码


一、需求背景与效果

根据服务关系制作关系图谱,echarts官方关系图没有想要的案例,网上也没有好的效果,故参考网上已有的部分案例,自行写了一个,效果还不错。

当前echarts版本信息:

话不多说,直接上效果:

1、默认展示查询到的所有路径列表

 2、点击路径,可展开详细信息

二、echarts源码

 源码与案例数据:

let data = {
  nodes: [{
		"cNumber": 20207,
		"category": 0,
		"name": "custom/data/service1-aliyun/vault-activemq"
	}, {
		"cNumber": 20207,
		"category": 1,
		"name": "service1-aliyun"
	}, {
		"cNumber": 2248,
		"category": 2,
		"name": "192.168.44.73"
	}, {
		"cNumber": 2247,
		"category": 2,
		"name": "192.168.44.76"
	}, {
		"cNumber": 2247,
		"category": 2,
		"name": "192.168.48.186"
	}, {
		"cNumber": 2246,
		"category": 2,
		"name": "192.168.44.77"
	}, {
		"cNumber": 2244,
		"category": 2,
		"name": "192.168.44.74"
	}, {
		"cNumber": 2244,
		"category": 2,
		"name": "192.168.44.75"
	}, {
		"cNumber": 2244,
		"category": 2,
		"name": "192.168.48.184"
	}, {
		"cNumber": 2244,
		"category": 2,
		"name": "192.168.48.187"
	}, {
		"cNumber": 2243,
		"category": 2,
		"name": "192.168.48.185"
	}, {
		"cNumber": 9743,
		"category": 0,
		"name": "cloud/data/devops-service1/tencent-service2"
	}, {
		"cNumber": 9743,
		"category": 1,
		"name": "devops-service1"
	}, {
		"cNumber": 2244,
		"category": 2,
		"name": "192.168.129.172"
	}, {
		"cNumber": 1893,
		"category": 2,
		"name": "192.168.0.117"
	}, {
		"cNumber": 1844,
		"category": 2,
		"name": "192.168.6.149"
	}, {
		"cNumber": 3869,
		"category": 0,
		"name": "custom/data/service1-tencent/vault-activemq"
	}, {
		"cNumber": 3869,
		"category": 1,
		"name": "service1-tencent"
	}, {
		"cNumber": 1926,
		"category": 2,
		"name": "192.169.35.217"
	}, {
		"cNumber": 150,
		"category": 2,
		"name": "192.169.32.2"
	}, {
		"cNumber": 150,
		"category": 2,
		"name": "192.169.33.118"
	}, {
		"cNumber": 150,
		"category": 2,
		"name": "192.169.33.59"
	}, {
		"cNumber": 150,
		"category": 2,
		"name": "192.169.34.153"
	}, {
		"cNumber": 150,
		"category": 2,
		"name": "192.169.34.99"
	}, {
		"cNumber": 150,
		"category": 2,
		"name": "192.169.35.122"
	}, {
		"cNumber": 149,
		"category": 2,
		"name": "192.169.32.151"
	}, {
		"cNumber": 149,
		"category": 2,
		"name": "192.169.33.165"
	}, {
		"cNumber": 149,
		"category": 2,
		"name": "192.169.33.197"
	}, {
		"cNumber": 149,
		"category": 2,
		"name": "192.169.33.238"
	}, {
		"cNumber": 149,
		"category": 2,
		"name": "192.169.33.84"
	}, {
		"cNumber": 149,
		"category": 2,
		"name": "192.169.35.152"
	}, {
		"cNumber": 149,
		"category": 2,
		"name": "192.169.35.172"
	}, {
		"cNumber": 9743,
		"category": 0,
		"name": "custom/data/devops-service1/ci-jiratool"
	}, {
		"cNumber": 1906,
		"category": 2,
		"name": "192.168.13.11"
	}, {
		"cNumber": 1856,
		"category": 2,
		"name": "192.168.13.95"
	}, {
		"cNumber": 9743,
		"category": 0,
		"name": "cloud/data/devops-service1/tencent-service1"
	}],
	links: [{
		"name": "20207",
		"source": "service1-aliyun",
		"target": "custom/data/service1-aliyun/vault-activemq"
	}, {
		"name": "2248",
		"source": "192.168.44.73",
		"target": "service1-aliyun"
	}, {
		"name": "2247",
		"source": "192.168.44.76",
		"target": "service1-aliyun"
	}, {
		"name": "2247",
		"source": "192.168.48.186",
		"target": "service1-aliyun"
	}, {
		"name": "2246",
		"source": "192.168.44.77",
		"target": "service1-aliyun"
	}, {
		"name": "2244",
		"source": "192.168.44.74",
		"target": "service1-aliyun"
	}, {
		"name": "2244",
		"source": "192.168.44.75",
		"target": "service1-aliyun"
	}, {
		"name": "2244",
		"source": "192.168.48.184",
		"target": "service1-aliyun"
	}, {
		"name": "2244",
		"source": "192.168.48.187",
		"target": "service1-aliyun"
	}, {
		"name": "2243",
		"source": "192.168.48.185",
		"target": "service1-aliyun"
	}, {
		"name": "9743",
		"source": "devops-service1",
		"target": "cloud/data/devops-service1/tencent-service2"
	}, {
		"name": "2244",
		"source": "192.168.129.172",
		"target": "devops-service1"
	}, {
		"name": "1893",
		"source": "192.168.0.117",
		"target": "devops-service1"
	}, {
		"name": "1844",
		"source": "192.168.6.149",
		"target": "devops-service1"
	}, {
		"name": "3869",
		"source": "service1-tencent",
		"target": "custom/data/service1-tencent/vault-activemq"
	}, {
		"name": "1926",
		"source": "192.169.35.217",
		"target": "service1-tencent"
	}, {
		"name": "150",
		"source": "192.169.32.2",
		"target": "service1-tencent"
	}, {
		"name": "150",
		"source": "192.169.33.118",
		"target": "service1-tencent"
	}, {
		"name": "150",
		"source": "192.169.33.59",
		"target": "service1-tencent"
	}, {
		"name": "150",
		"source": "192.169.34.153",
		"target": "service1-tencent"
	}, {
		"name": "150",
		"source": "192.169.34.99",
		"target": "service1-tencent"
	}, {
		"name": "150",
		"source": "192.169.35.122",
		"target": "service1-tencent"
	}, {
		"name": "149",
		"source": "192.169.32.151",
		"target": "service1-tencent"
	}, {
		"name": "149",
		"source": "192.169.33.165",
		"target": "service1-tencent"
	}, {
		"name": "149",
		"source": "192.169.33.197",
		"target": "service1-tencent"
	}, {
		"name": "149",
		"source": "192.169.33.238",
		"target": "service1-tencent"
	}, {
		"name": "149",
		"source": "192.169.33.84",
		"target": "service1-tencent"
	}, {
		"name": "149",
		"source": "192.169.35.152",
		"target": "service1-tencent"
	}, {
		"name": "149",
		"source": "192.169.35.172",
		"target": "service1-tencent"
	}, {
		"name": "9743",
		"source": "devops-service1",
		"target": "custom/data/devops-service1/ci-jiratool"
	}, {
		"name": "1906",
		"source": "192.168.13.11",
		"target": "devops-service1"
	}, {
		"name": "1856",
		"source": "192.168.13.95",
		"target": "devops-service1"
	}, {
		"name": "9743",
		"source": "devops-service1",
		"target": "cloud/data/devops-service1/tencent-service1"
	}]

}

const color1 = '#006acc';
const color2 = '#ff7d18';
const color3 = '#45b97c';

data.nodes.forEach(node => {
  if (node.category === 0) {
    node.symbolSize = 70;
    node.itemStyle = {
      color: color1
    };
  } else if (node.category === 1) {
    node.symbolSize = 50;
    node.itemStyle = {
      color: color2
    };
  } else if (node.category === 2) {
    node.symbolSize = 30;
    node.itemStyle = {
      color: color3
    };
  }
  node.symbolSize = node.symbolSize + node.cNumber/1000
  node.open = false
});

data.links.forEach(link => {
  link.label = {
    align: 'center',
    fontSize: 12
  };

});

let categories = [{
    name: '路径',
    itemStyle: {
        color: color1
    }
  },
  {
    name: '目标对象',
    itemStyle: {
        color: color2
    }
},
{
    name: '客户端IP',
    itemStyle: {
        color: color3
    }
}]

option = {
  title: {
    text: '关系图谱',
  },
  legend: [{
    data: categories.map(x => x.name),
  }],
  series: [{
    type: 'graph',
    layout: 'force',
    symbolSize: 58,
    draggable: true,
    roam: true,
    focusNodeAdjacency: true,
    categories: categories,
    edgeSymbol: ['', 'arrow'],
    // edgeSymbolSize: [80, 10],
    edgeLabel: {
      normal: {
        show: true,
        textStyle: {
          fontSize: 20
        },
        formatter(x) {
          return x.data.name;
        }
      }
    },
    label: {
      fontSize: 12,
        show: true
    },
    force: {
      repulsion: 2000,
      edgeLength: 120
    },
    data: data.nodes,
    links: data.links
  }]
}

myChart.setOption(option);
bindChartClickEvent(myChart);

/**
 * 绑定图表的点击事件
 * @param chart
 */
function bindChartClickEvent(chart) {
    chart.on('click', function (params) {
        var category = params.data.category,
            nodeType = params.data.nodeType;
            toggleShowNodes(chart, params);
    });
    
    for (var j = 0; j < data.nodes.length; j++) {
      if (data.nodes[j].category !==  0 ) {
          data.nodes[j].data = {};
          data.nodes[j].seriesIndex=0;
          data.nodes[j].open=false;
          data.nodes[j].category=-1;
          toggleShowNodes(chart, data.nodes[j]);
      }
    }
}

/**
 * 展开或关闭节点
 * @param chart
 * @param params
 */
function toggleShowNodes(chart, params) {
    var open = !!params.data.open,
        options = chart.getOption(),
        seriesIndex = params.seriesIndex,
        srcLinkName = params.name,
        serieLinks = options.series[seriesIndex].links,
        serieData = options.series[seriesIndex].data,
        serieDataMap = new Map(),
        serieLinkArr = [];
    // 当前根节点是展开的,那么就需要关闭所有的根节点
    if (open) {
        // 递归找到所有的link节点的target的值
        findLinks(serieLinkArr, srcLinkName, serieLinks, true);
        if (serieLinkArr.length) {
            serieData.forEach(sd => serieDataMap.set(sd.name, sd));
            for (var i = 0; i < serieLinkArr.length; i++) {
                if (serieDataMap.has(serieLinkArr[i])) {
                    var currentData = serieDataMap.get(serieLinkArr[i]);
                    currentData.category = -Math.abs(currentData.category);
                }
            }
            
            serieDataMap.get(srcLinkName).open = false;
            chart.setOption(options);
        }
    } else {
        // 当前根节点是关闭的,那么就需要展开第一层根节点
        findLinks(serieLinkArr, srcLinkName, serieLinks, true);
        if (serieLinkArr.length) {
            serieData.forEach(sd => serieDataMap.set(sd.name, sd));
            for (var j = 0; j < serieLinkArr.length; j++) {
                if (serieDataMap.has(serieLinkArr[j])) {
                    var currentData = serieDataMap.get(serieLinkArr[j]);
                    currentData.category = Math.abs(currentData.category);
                }
            }
            serieDataMap.get(srcLinkName).open = true;
            chart.setOption(options);
        }
    }
}

/**
 * 查找连接关系
 * @param links 返回的节点放入此集合
 * @param srcLinkName 源线的名称
 * @param serieLinks 需要查找的集合
 * @param deep 是否需要递归进行查找
 */
function findLinks(links, srcLinkName, serieLinks, deep) {
    var targetLinks = [];
    serieLinks.filter(link => link.target === srcLinkName).forEach(link => {
        targetLinks.push(link.source);
        links.push(link.source)
    });
    if (deep) {
        for (var i = 0; i < targetLinks.length; i++) {
            findLinks(links, targetLinks[i], serieLinks, deep);
        }
    }
}

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

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

相关文章

Centos7单机安装Redis

安装Redis依赖 Redis是基于C语言&#xff0c;因此首先需要安装Redis所需要的gcc依赖&#xff1a; yum install -y gcc tcl ​ 上传安装包并解压 上传安装包redis-6.2.12至/home目录下 ​ # 解压 tar -xzf redis-6.2.12.tar.gz # 安装 cd redis-6.2.12 make && mak…

react ant table设置动态scroll,且某些列的长度固定

设置scroll x的值为列的个数*100 1.代码 const columns [ {title: 料号描述,dataIndex: itemDesc,align:left,width: 200,ellipsis: true,} ]<EditableProTableclassName"details-table"columns{columns}loading{loading}rowKey"id"value{dataSource}…

C++笔记之自引用结构体

C笔记之自引用结构体 code review! 文章目录 C笔记之自引用结构体1.在结构体中引用相同类型的结构体&#xff0c;并且可以使用指针或引用来实现。2.自引用结构体构建链表3.自引用结构体构建二叉树附:代码随想录——链表定义附:代码随想录——二叉树定义 1.在结构体中引用相同…

分布式幂等问题解决方案

目录 一 背景 二 什么是幂等 三 解决方案三部曲 第一部曲&#xff1a;识别相同请求 第二部曲&#xff1a;列出并减少副作用的分析维度 第三部曲&#xff1a;识别细粒度副作用&#xff0c;针对性设计解决方案 四 总结 一 背景 分布式系统由众多微服务组成&#xff0c;微…

从0到1搭建Springboot整合Quartz定时任务框架(保姆级教学+Gitee源码)

前言&#xff1a;最近学习了目前主流的若依框架&#xff0c;这是一个非常优秀的开源项目&#xff0c;故此我这边把它的源码全部剖析了一遍&#xff0c;简化了它的框架&#xff0c;我会通过这篇博客详细讲解我是如何进行推敲和从0到1搭建这个项目的流程。 目录 一、Quartz简介 …

Java并发(十二)----线程应用之多线程解决烧水泡茶问题

1、背景 统筹方法&#xff0c;是一种安排工作进程的数学方法。它的实用范围极广泛&#xff0c;在企业管理和基本建设中&#xff0c;以及关系复杂的科研项目的组织与管理中&#xff0c;都可以应用。 怎样应用呢&#xff1f;主要是把工序安排好。 比如&#xff0c;想泡壶茶喝。…

【前后端分离开发及项目部署流程】

文章目录 前后端分离开发技术1 前后端分离开发1.1 介绍1.2 开发流程1.3 前端技术栈&#xff08;了解&#xff09; 2 Yapi&#xff08;定义API接口&#xff09;2.1 介绍2.2 使用 3 Swagger3.1 介绍3.2 使用方式3.3 常用注解 4 项目部署4.1 部署架构4.2 部署环境说明4.3 部署前端…

chatgpt赋能python:如何使用Python访问共享目录——让共享变得简单易行

如何使用Python访问共享目录 —— 让共享变得简单易行 作为一种高效而强大的编程语言&#xff0c;Python拥有各种各样的应用。其中一个非常重要的应用场景就是对共享目录的访问和操作。无论是在家庭网络&#xff0c;企业内网或者云存储平台&#xff0c;共享目录的重要性毋庸置…

两个链表的入环节点(java)

两个链表的入环节点 两个链表的入环节点解题思路代码演示 链表相关的题 两个链表的入环节点 给定两个可能有环也可能无环的单链表&#xff0c;头节点head1和head2 请实现一个函数&#xff0c;如果两个链表相交&#xff0c;请返回相交的第一个节点。如果不相交返回null 要求如果…

ATTCK(一)之为什么要学习ATTCK

ATT&CK 简介 本系列旨在介绍网络红蓝对抗领域最好的ATT&CK矩阵模型&#xff0c;以期帮助有意愿深耕在红蓝对抗领域的人员能系统性的掌握红蓝对抗领域的知识和经验。本系列将详细ATT&CK的起源、发展历史&#xff0c;ATT&CK矩阵相对其他High-Level红蓝对抗模型…

Redis7【② Key通用命令 十大数据类型】

1 Key的通用命令 redis命令不区分大小写&#xff0c;但是key是区分大小写的。没有返回值的命令执行成功会返回1&#xff0c;失败返回0。 1. KEYS 查看所有的key&#xff0c;返回值是一个数组 2. EXISTS EXISTS key [key ...]&#xff1a;返回给定的key中已存在的个数&#xf…

前端Vue自定义验证码密码登录切换tabs选项卡标签栏标题栏 验证码登录模版 密码登录模版

前端Vue自定义验证码密码登录切换tabs选项卡标签栏标题栏 验证码登录模版 密码登录模版&#xff0c; 请访问uni-app插件市场地址&#xff1a;https://ext.dcloud.net.cn/plugin?id13221 效果图如下&#xff1a; 实现代码如下&#xff1a; # cc-selectBox #### 使用方法 使…

【计算机网络】可靠传输的实现机制

1、停止-等待协议SW 信道利用率 题目 小结 2.回退N帧协议GBN Go-Back-N 题目 小结

设计模式3:单例模式:JMM与volatile和synchronized的关系

本文目录 JMM简介Java 内部内存模型(The Internal Java Memory Model)硬件内存架构(Hardware Memory Architecture)弥合 Java 内存模型和硬件内存架构之间的差距(Bridging The Gap Between The Java Memory Model And The Hardware Memory Architecture)1.共享对象的可见性2.竞…

OpenStack(T版)——计算(Nova)服务介绍与安装

文章目录 OpenStack(T版)——计算(Nova)服务介绍与安装安装与配置(controller)准备(1)创建数据库(2)加载环境变量(3)创建认证服务凭据(4)创建Nova计算服务组件的API endpoint 安装和配置Nova计算服务组件(1)安装软件包(2)编辑/etc/nova/nova.conf 完成以下操作(3)同步数据库验证…

云服务器Linux防火墙云锁安装部署及使用 技术支持服务器安全运维

服务器必备安全防护及运维管理SAAS解决方案&#xff0c;支持windows/linux服务器跨平台实时、批量、远程安全管理&#xff0c;有效对抗服务器入侵和网络攻击。 服务器&#xff1a;Redhat/CentOS/Ubuntu/SUSE/中标麒麟 64位 Web中间件&#xff1a;Apache/Nginx/kangle/Tomcat/W…

【软考网络管理员】2023年软考网管初级常见知识考点(26)- HTML常见属性标签、表格、表单详解

涉及知识点 Html的概念&#xff0c;html常见标签&#xff0c;html常见属性&#xff0c;html表格&#xff0c;html表单&#xff0c;软考网络管理员常考知识点&#xff0c;软考网络管理员网络安全&#xff0c;网络管理员考点汇总。 原创于&#xff1a;CSDN博主-《拄杖盲学轻声码…

5-2图像处理经典案例:正弦噪声图像去噪

学习目标&#xff1a; 图像处理经典案例 去除噪声 1.简述 图像降噪的英文名称是Image Denoising&#xff0c; 图像处理中的专业术语。是指减少数字图像中噪声的过程&#xff0c;有时候又称为图像去噪。图像的噪声来源相对复杂&#xff0c;搞清楚图像噪声的成因对我们进行…

B+树

B树 B树是对B树的一种变形树&#xff0c;它与B树的差异在于: 非叶结点仅具有索引作用&#xff0c;也就是说&#xff0c;非叶子结点只存储key&#xff0c;不存储value 树的所有叶结点构成一个有序链表&#xff0c;可以按照key排序的次序遍历全部数据 B树存储数据 若参数M选…

使用影刀RPA拆分excel数据

首先&#xff0c;要使程序有一定的兼容性&#xff0c;即增加互动性&#xff0c;认为选择要拆分的文件和拆分的依据列&#xff0c;可以利用影刀中的‘打开选择对话框’和‘打开输入对话框’来实现&#xff0c;这样一来便不用考虑待拆分excel的路径问题获取1中选择的依据拆分列&a…