这次给博客加“书签资源库”时,第一版很自然地做成了分类卡片:每个分类一个区块,下面放链接卡片。它信息清楚,但视觉上很重,也不太像“从个人收藏夹里长出来的一张知识地图”。后来我把它改成了更接近 Obsidian Graph View 的图谱结构:节点漂浮在画布里,主题、标签和链接用不同形状区分,连线展示关系,用户可以拖拽、缩放、筛选和搜索。
这篇文章记录的不是某个库的完整教程,而是一套更通用的判断:什么时候该用知识图谱、节点应该怎么分层、连线怎么控制密度、Canvas 和 SVG 怎么选,以及如何让图谱看起来“有关系”而不是“一团乱麻”。
先判断:图谱不是卡片列表的替代品
知识图谱适合表达“关系”,不适合承载所有详情。
如果页面的主要任务是让用户逐条比较链接的标题、描述、价格、评分,那么卡片或表格更好。如果主要任务是让用户感知一批资源之间的主题关系、标签重叠、知识路径和聚类结构,图谱才有价值。
这次书签页的目标不是“完整公开收藏夹”,而是展示经过筛选的公开资源入口。原始收藏里有账号后台、聊天记录、本地服务、工作台等敏感链接,不能直接公开。因此图谱的任务变成:
- 告诉读者这些资源属于哪些主题分支。
- 展示标签如何把不同资源串起来。
- 保留足够的链接入口,但不让链接卡片淹没页面。
- 让用户先获得“这是一张资源关系图”的感觉,再决定点开哪个资源。
也就是说,图谱承担的是导航和关系感知,不是替代完整数据库。
节点分层:先设计类型,再设计样式
很多图谱做丑,是因为一上来就在想颜色和布局,而不是先定义节点类型。
这次我把节点分成四层:
资源库 root -> 主题分支 group -> 标签 tag -> 具体链接 link这四类节点的责任不同:
| 节点类型 | 作用 | 视觉策略 |
|---|---|---|
| root | 说明整张图的中心对象 | 最大、圆形、偏蓝,作为视觉锚点 |
| group | 表示主题分支,如 AI 工程、设计资源 | 中等尺寸、方形或圆角块,适合承担聚类中心 |
| tag | 表示横向标签,如 prompt、agents、design | 小一些,用菱形或虚线边框,强调“连接器”角色 |
| link | 真实外链入口 | 最小,数量最多,避免喧宾夺主 |
这里的关键是:节点样式不是装饰,而是在帮用户理解数据结构。用户不需要读说明,也应该能大概看出“大的蓝点是中心,绿色节点是主题,橙色节点是标签,小黑点是链接”。
连线密度:少连一点,图才可读
知识图谱最容易失控的地方是连线。每多一类关系,画面复杂度都会明显上升。
这次只保留三种边:
root -> groupgroup -> tagtag -> link我没有直接画 group -> link,也没有画 link -> link。原因是这两类边虽然“真实”,但会迅速把画面变成毛线团。
一个实用规则是:同一张图里,边的意义最好不要超过三种。第一种边提供层级,第二种边提供聚类,第三种边提供具体入口。更多关系可以留给 hover 高亮、搜索结果、详情面板,而不是全部画出来。
布局:固定树图不够像 Obsidian
第一版图谱是静态分层:左边 root,中间 group/tag,右边 link。它比卡片轻,但仍然像“流程图”,不太像 Obsidian 的知识图谱。
Obsidian Graph View 的感觉来自 force-directed graph,也就是力导向图:
- 节点之间有排斥力,避免重叠。
- 连线像弹簧,把相关节点拉近。
- 整张图有中心力,避免散出屏幕。
- 拖拽后图谱会轻微回弹,产生物理感。
这类布局不要求每个节点在固定层级坐标上,而是让关系自己“长”出空间结构。主题节点自然形成几个团,标签节点挂在团之间,链接节点分布在外围。它比树图更适合表达“知识网络”。
Canvas 还是 SVG?
如果节点很少,SVG 更简单:每个节点是一个 DOM 元素,每条边是一个 <path>,样式和可访问性都好处理。
但当节点数量来到几十个以上,还要做物理模拟、拖拽、缩放、hover 高亮时,Canvas 会更顺滑。它的好处是:
- 绘制大量节点和连线时更轻。
- 缩放和平移只需要改变视图矩阵。
- hover 高亮可以每帧重绘,不必反复操作 DOM。
- 可以把动画控制在一个
requestAnimationFrame循环里。
这次书签图谱只有几十个节点,但已经包含标签、链接、连线、搜索和拖拽,所以我选择 Canvas。DOM 只保留工具栏、搜索框和 tooltip。
让图谱“丝滑”的几个细节
1. 初始位置不要完全随机
完全随机会导致图谱加载时抖动很明显,也可能把相关主题甩到很远。更好的方式是半确定布局:root 放中心,group 按主题分布在环上,tag 和 link 根据所属 group 初始化到对应扇区。
这样 force simulation 只是把图谱“整理自然”,而不是从一团随机点里重新爆炸。
2. 节点大小按连接度变化
节点连接越多,越应该更大。这样用户能一眼看到哪些标签或主题更重要。
const radius = baseRadius + Math.min(8, Math.sqrt(degree) * 1.6);不建议线性放大,因为高连接节点会过大。平方根更稳。
3. hover 高亮只突出邻居
图谱默认展示整体关系,hover 时应该回答一个更具体的问题:“这个节点跟谁有关?”
我的处理是:
- hover 一个节点时,它和一阶邻居保持高亮。
- 其他节点和边降低透明度。
- tooltip 显示标题和来源域名。
这比弹出很大的详情卡更轻,也更像 Obsidian 的探索体验。
4. 缩放时标签有显示阈值
不是所有节点都应该永远显示文字。文字太多会让图谱变回卡片墙。
可用策略是:
- root 和 group 默认显示 label。
- tag 只有放大到一定比例后显示。
- link 默认只显示点,hover 或放大时再显示 label。
这样远看是结构,近看是内容。
5. 提供“稳定”和“重置”按钮
力导向图有生命感,但也可能让用户觉得不受控。两个按钮很有用:
Reset:恢复初始布局和缩放。Settle:停止模拟,让当前图谱稳定下来。
这两个控件能让动态图谱从“炫技”变成可操作工具。
过滤和搜索比图例更重要
图例能说明节点颜色,但真正让图谱可用的是过滤。
这次我做了三个轻量控制:
- 显示/隐藏 tag 节点。
- 显示/隐藏 link 节点。
- 搜索节点标题、域名、标签。
隐藏 link 后,图谱会变成“主题—标签”的抽象地图;显示 link 后,图谱变成资源入口。搜索则用于从一张图里快速定位某个主题。
这也对应 Obsidian Graph View 的使用方式:图谱不是静态海报,而是一个可以被过滤、探索和缩放的界面。
性能边界
几十个节点可以手写轻量模拟;几百个节点也还能优化;几千个节点就应该换策略。
常见优化方向:
- 用 Canvas 绘制,不用大量 DOM。
- 限制物理模拟时间,
alpha逐步衰减。 - 节点过多时默认隐藏叶子节点。
- 搜索和过滤后再渲染子图。
- 大规模图谱使用专门库,例如 Sigma.js、Cytoscape.js、D3 force 或 WebGL 方案。
这次没有引入 D3,是因为当前规模不大,手写模拟更容易控制视觉和交互。但如果未来要做完整知识库图谱,建议使用成熟图可视化库。
设计复盘
这次改版的核心不是“把卡片换成点”,而是重新定义信息层级:
卡片页:分类 -> 链接详情图谱页:资源库 -> 主题 -> 标签 -> 链接入口卡片页追求完整,图谱页追求关系。两者不是谁替代谁,而是面向不同任务。
如果以后要继续增强,我会优先做三件事:
- 给节点增加详情侧栏,而不是把更多文字塞进图里。
- 支持按主题聚焦,只显示一个 group 的局部图。
- 把这套图谱抽成组件,用在课程图谱、项目学习路线、知识库概念网络里。
知识图谱界面最重要的不是节点多,而是让用户愿意探索。节点、连线、颜色、动效、过滤都应该服务这个目标:让关系变得可见,同时不让复杂度压倒内容。
COMMUNITY DISCUSSION
评论
使用 GitHub 账号登录后参与讨论,评论会同步到 GitHub Discussions。