| domain | contrib |
|---|---|
| title | knowledge graph ux patterns from high star projects |
| verification | metadata-normalized |
| {"title" | 知识图谱 UX 增强: 从高星项目提炼的 7 个交互模式", "domain": "development", "tags": ["knowledge-graph", "d3js", "ux", "graph-visualization", "force-directed"], "domain_expert": "unknown"} |
| created | 2026-07-06 |
| source | unknown |
知识图谱可视化项目存在典型问题: 节点过多导致信息过载、关系缺乏上下文、无法聚焦局部视图。 参考 GitHub 高星项目 (GraphRAG 25k⭐, Logseq 32k⭐, Cytoscape.js 10k⭐, react-force-graph 10k⭐) 的设计模式, 提炼出 7 个可复用的交互增强方案。
知识图谱可视化的核心矛盾是 全局概览 vs 局部细节 的平衡。 高星项目的共同策略是 渐进式披露 (Progressive Disclosure): 先展示局部, 再允许探索全局。
点击节点后只展示 N 跳邻居, 解决信息过载:
function getNHopNeighbors(nodeId, hops, edges) {
const visited = new Set([nodeId]);
let frontier = [nodeId];
for (let i = 0; i < hops; i++) {
const next = new Set();
frontier.forEach(id => {
edges.forEach(e => {
const sid = e.source?.id || e.source;
const tid = e.target?.id || e.target;
if (sid === id && !visited.has(tid)) { next.add(tid); visited.add(tid); }
if (tid === id && !visited.has(sid)) { next.add(sid); visited.add(sid); }
});
});
frontier = [...next];
}
return visited;
}面包屑导航支持逐级返回: 全局图谱 > 节点A > 节点B
给 D3 force simulation 添加自定义聚类力:
function forceCluster(nodes, getCategory) {
const clusterCenters = {};
const categories = [...new Set(nodes.map(n => getCategory(n)))];
const radius = 250;
categories.forEach((cat, i) => {
const angle = (2 * Math.PI * i) / categories.length;
clusterCenters[cat] = { x: Math.cos(angle) * radius, y: Math.sin(angle) * radius };
});
return alpha => {
nodes.forEach(d => {
const center = clusterCenters[getCategory(d)];
if (center) {
d.vx += (center.x - d.x) * alpha * 0.08;
d.vy += (center.y - d.y) * alpha * 0.08;
}
});
};
}同类节点间距缩小, 不同类间距增大, 形成视觉分组。
用透明宽线条作为 hover 区域, 解决细线条难以 hover 的问题:
// 透明 hover 区域 (12px 宽)
linkGroup.selectAll('.edge-hit-area').data(links).join('line')
.attr('class', 'edge-hit-area') // stroke: transparent; stroke-width: 12;
.on('mouseover', showEdgeTooltip)
.on('mousemove', showEdgeTooltip)
.on('mouseout', hideEdgeTooltip);多维筛选: 节点类型 / 实体类型 / 分类, 加上孤立节点隐藏和核心节点高亮:
function isNodeVisible(node, filterState) {
if (!filterState.types.has(node.type)) return false;
if (node.type === 'entity' && !filterState.entityTypes.has(node.entityType)) return false;
if (filterState.hideOrphans && !connectedIds.has(node.id)) return false;
return true;
}滑块控制引力、连接距离、碰撞半径, 实时更新 simulation:
function updatePhysics(simulation, charge, dist, collide) {
simulation.force('charge').strength(-charge);
simulation.force('link').distance(dist);
simulation.force('collision').radius(d => baseRadius(d) + collide);
simulation.alpha(0.3).restart();
}按连接数标记高权重节点, 帮助识别关键节点:
// 连接数 >= threshold 的节点加红色边框
d3.select(this).select('circle')
.attr('stroke-width', isHub ? 3 : 2)
.attr('stroke', isHub ? '#f85149' : defaultStroke);双击任意节点进入局部图谱, 单击打开详情面板。两种交互互不干扰。
- 局部视图: 双击高连接节点 → 只显示 10-30 个邻居, 面包屑可见
- 筛选器: 取消某类型 → 对应节点和边消失, 计数正确
- 聚类: 同类节点自动聚集, 不同类间距增大
- 边悬浮: hover 细线条 → tooltip 显示关系类型
- 物理控制: 拖动滑块 → 节点间距实时变化
- 核心高亮: 启用后 → 高连接节点出现红色边框
- 渐进式披露: 默认局部视图, 按需展开全局
- 多维筛选: 不只是类型过滤, 要支持属性维度
- 物理可调: 让用户自定义布局参数, 而非固定
- 边可读: 细线条需要 hover 区域增强
- 聚类力: 自定义 D3 force 实现社区分组