如何在Apache ECharts关系图中实现分类筛选并隐藏无关联节点?
需求实现方案
这个需求完全可以实现,核心是通过监听分类选择操作,动态筛选出选中分类下存在关联链接的节点及对应链接,再更新ECharts配置来刷新图表。以下是具体修改步骤和代码调整:
1. 添加顶部分类选择控件
在页面顶部(<div id="container">之前)添加分类选择下拉框,用于触发分类筛选:
<div style="padding: 10px; background: #f5f5f5;"> <label>选择分类:</label> <select id="categorySelect"> <option value="all">全部分类</option> <!-- 选项将通过JS动态生成 --> </select> </div>
2. 保存原始数据,避免重复请求
获取JSON数据后,将原始的节点、链接和分类数据保存到全局变量,方便切换分类时复用:
// 在getJSON回调内部保存原始数据 window.rawGraphData = { nodes: [...graph.nodes], links: [...graph.links], categories: [...graph.categories] };
同时动态生成下拉框的分类选项:
// 生成分类选择项 const select = document.getElementById('categorySelect'); graph.categories.forEach(cat => { const option = document.createElement('option'); option.value = cat.name; option.textContent = cat.name; select.appendChild(option); });
3. 添加分类筛选与图表更新逻辑
编写筛选函数,根据选中分类过滤出关联节点和链接,再更新图表:
// 分类筛选函数 function filterGraphByCategory(categoryName) { let filteredNodes = [...window.rawGraphData.nodes]; let filteredLinks = [...window.rawGraphData.links]; if (categoryName !== 'all') { // 获取选中分类的ID const targetCategoryId = window.rawGraphData.categories.find(c => c.name === categoryName).id; // 找出该分类下的所有节点ID const targetNodeIds = window.rawGraphData.nodes.filter(node => node.category === targetCategoryId).map(node => node.id); // 筛选出与目标节点有关联的链接 const relatedLinks = window.rawGraphData.links.filter(link => { // 兼容links中source/target为对象或ID值的情况 const sourceId = typeof link.source === 'object' ? link.source.id : link.source; const targetId = typeof link.target === 'object' ? link.target.id : link.target; return targetNodeIds.includes(sourceId) || targetNodeIds.includes(targetId); }); // 收集所有关联节点的ID const relatedNodeIds = new Set(); relatedLinks.forEach(link => { const sourceId = typeof link.source === 'object' ? link.source.id : link.source; const targetId = typeof link.target === 'object' ? link.target.id : link.target; relatedNodeIds.add(sourceId); relatedNodeIds.add(targetId); }); // 最终筛选出关联节点 filteredNodes = window.rawGraphData.nodes.filter(node => relatedNodeIds.has(node.id)); filteredLinks = relatedLinks; } // 更新图表配置 myChart.setOption({ series: [{ data: filteredNodes, links: filteredLinks }] }); } // 绑定分类选择事件 document.getElementById('categorySelect').addEventListener('change', function(e) { filterGraphByCategory(e.target.value); });
完整修改后的代码
整合所有修改后的完整代码如下:
<!-- Knowledge Map v2 --> <!DOCTYPE html> <html lang="en" style="height: 100%"> <head> <meta charset="utf-8"> </head> <body style="height: 100%; margin: 0"> <!-- 添加分类选择控件 --> <div style="padding: 10px; background: #f5f5f5;"> <label>选择分类:</label> <select id="categorySelect"> <option value="all">全部分类</option> </select> </div> <div id="container" style="height: 100%"></div> <script type="text/javascript" src="jquery.min.js"></script> <script type="text/javascript" src="echarts.min.js"></script> <script type="text/javascript"> var dom = document.getElementById('container'); var myChart = echarts.init(dom, null, { renderer: 'canvas', useDirtyRect: false }); var app = {}; var ROOT_PATH = ''; var option; myChart.showLoading(); $.getJSON(ROOT_PATH + '/Graph_Data/KnowledgeMapData.json', function (graph) { myChart.hideLoading(); // 保存原始数据 window.rawGraphData = { nodes: [...graph.nodes], links: [...graph.links], categories: [...graph.categories] }; // 生成分类选择选项 const select = document.getElementById('categorySelect'); graph.categories.forEach(cat => { const option = document.createElement('option'); option.value = cat.name; option.textContent = cat.name; select.appendChild(option); }); option = { tooltip: {}, legend: [ { data: graph.categories.map(function (a) { return a.name; }) } ], series: [ { name: 'Aranea Knowledge Map', type: 'graph', layout: 'none', data: graph.nodes, links: graph.links, categories: graph.categories, roam: true, label: { show: true, position: 'right', formatter: '{b}' }, labelLayout: { hideOverlap: true }, scaleLimit: { min: 0.4, max: 2 }, lineStyle: { color: 'source', curveness: 0.1 } } ] }; myChart.setOption(option); // 分类筛选函数 function filterGraphByCategory(categoryName) { let filteredNodes = [...window.rawGraphData.nodes]; let filteredLinks = [...window.rawGraphData.links]; if (categoryName !== 'all') { const targetCategoryId = window.rawGraphData.categories.find(c => c.name === categoryName).id; const targetNodeIds = window.rawGraphData.nodes.filter(node => node.category === targetCategoryId).map(node => node.id); const relatedLinks = window.rawGraphData.links.filter(link => { const sourceId = typeof link.source === 'object' ? link.source.id : link.source; const targetId = typeof link.target === 'object' ? link.target.id : link.target; return targetNodeIds.includes(sourceId) || targetNodeIds.includes(targetId); }); const relatedNodeIds = new Set(); relatedLinks.forEach(link => { const sourceId = typeof link.source === 'object' ? link.source.id : link.source; const targetId = typeof link.target === 'object' ? link.target.id : link.target; relatedNodeIds.add(sourceId); relatedNodeIds.add(targetId); }); filteredNodes = window.rawGraphData.nodes.filter(node => relatedNodeIds.has(node.id)); filteredLinks = relatedLinks; } myChart.setOption({ series: [{ data: filteredNodes, links: filteredLinks }] }); } // 绑定分类选择事件 document.getElementById('categorySelect').addEventListener('change', function(e) { filterGraphByCategory(e.target.value); }); }); window.addEventListener('resize', myChart.resize); </script> </body> </html>
注意事项
- 代码兼容了
links中source/target为节点对象或ID值的两种情况,适配不同的数据格式。 - 原始数据通过全局变量存储,确保每次切换分类都能从完整数据集中重新筛选,避免数据丢失。
内容的提问来源于stack exchange,提问作者Paul Agerbeek
相关产品推荐
相关产品推荐

