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

4 篇文章 0 订阅
1 篇文章 0 订阅

目录

一、需求背景与效果

二、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);
        }
    }
}

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个示例代码,用于展示企业组织结构关系图谱: ```html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>ECharts企业组织结构关系图谱示例</title> <!-- 引入 ECharts 文件 --> <script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script> </head> <body> <!-- 绘制图表的容器 --> <div id="chart" style="width: 1000px;height: 600px;"></div> <!-- 图表的 JavaScript 代码 --> <script> // 基于准备好的dom,初始化echarts实例 var myChart = echarts.init(document.getElementById('chart')); // 数据 var data = { "name": "公司总部", "children": [ { "name": "财务部", "children": [ { "name": "会计" }, { "name": "出纳" }, { "name": "审计师" } ] }, { "name": "人力资源部", "children": [ { "name": "人事专员" }, { "name": "薪酬专员" }, { "name": "培训专员" } ] }, { "name": "研发部", "children": [ { "name": "前端开发工程师" }, { "name": "后端开发工程师" }, { "name": "测试工程师" } ] } ] }; // 配置项 var option = { tooltip: { trigger: 'item', triggerOn: 'mousemove' }, series: [ { type: 'tree', data: [data], top: '1%', left: '7%', bottom: '1%', right: '20%', symbolSize: 7, label: { position: 'left', verticalAlign: 'middle', align: 'right', fontSize: 14 }, leaves: { label: { position: 'right', verticalAlign: 'middle', align: 'left' } }, expandAndCollapse: true, animationDuration: 550, animationDurationUpdate: 750 } ] }; // 使用刚指定的配置项和数据显示图表。 myChart.setOption(option); </script> </body> </html> ``` 以上代码中,我们使用 ECharts 的 `tree` 类型来绘制企业组织结构关系图谱。具体来说,我们通过一个 JSON 数据来定义组织结构的层级关系,然后在配置项中设置相关参数,例如节点大小、标签位置、动画效果等,最后调用 `setOption` 方法来绘制图表。 需要注意的是,这只是一个简单的示例代码,实际情况下,我们可能需要根据具体的业务需求来调整相关参数和样式,以达到更好的可视化效果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值