深入解析 sigma.js v2 与 v1 的核心架构变迁、API 映射关系、数据模型解耦与交互模式重构,提供从 v1 平滑迁移至 v2 的完整实操步骤、对照示例与踩坑指南。
sigma.js v2 与 v1 版本 API 差异及迁移指南
时间:2026-10-30
浏览:592
文章目录
sigma.js 从 v1 到 v2 并不是一次常规的功能迭代,而是一次底层架构的完全重写。核心变化是图数据模型完全解耦并转交由独立的 graphology 库驱动,渲染引擎全面转向纯 WebGL 高性能流水线,同时 API 全面适配现代 ES Module 与 TypeScript 生态。本文梳理两个版本在架构、数据模型、事件与样式机制上的核心差异,并提供详细的 API 对照与逐步迁移指南。
一、核心架构与设计理念的本质变化
在评估是否升级或准备迁移前,必须先理解 v2 为何做出根本性重构。在 sigma.js v1 时代,框架承担了“全包管家”的角色:它不仅负责在浏览器窗口中绘制圆圈和连线,还自己维护了一套图的数据结构(s.graph),并打包了旧式的 Canvas 渲染逻辑和全局插件机制。
这种设计在图规模达到数千个节点时就会遇到明显的性能瓶颈,且由于图操作逻辑被封装在渲染器内部,外部应用很难将图数据与 React、Vue 等现代状态管理体系深度结合。为此,v2 进行了彻底的“职责剥离”:
- 数据层完全交还社区标准:sigma.js 不再负责维护图的拓扑数据结构,而是完全依赖
graphology。所有节点的增删、属性变更、邻接点查询与图算法均由graphology提供。 - 渲染层专注高性能 WebGL:放弃了旧版维护成本高且性能受限的 2D Canvas 主渲染器,v2 的核心是一个高度优化的纯 WebGL 渲染引擎,节点与边的几何顶点通过着色器在 GPU 中并行绘制。
- 样式驱动转为声明式 Reducer:v1 中若要高亮某个节点,必须遍历图数据直接改写
node.color并调用s.refresh();v2 引入了类似于前端状态管理的nodeReducer与edgeReducer,在不污染底层图数据的前提下动态返回渲染态样式。
二、关键 API 与语法差异对比
迁移过程中最常碰到的就是 API 命名与调用语境的改变。下表列出了 v1 核心方法在 v2 中的直接对标方式:
| 功能模块 | sigma.js v1 语法 | sigma.js v2 语法 |
|---|---|---|
| 类与构造函数 | new sigma({ graph, container }) 或 new sigma('container-id') |
new Sigma(graph, container, [options])(注意首字母大写) |
| 数据载体 | s.graph (内置专用类) |
graphology.Graph (需单独实例化传入) |
| 添加节点 | s.graph.addNode({ id, label, x, y, size }) |
graph.addNode(id, { label, x, y, size })(id 分离为第一个参数) |
| 添加边 | s.graph.addEdge({ id, source, target }) |
graph.addEdgeWithKey(id, source, target, attr) 或 graph.addEdge(s, t, attr) |
| 相机与视角控制 | s.cameras[0].goTo({ x, y, ratio }) |
renderer.getCamera().setState({ x, y, ratio }) |
| 事件监听 | s.bind('clickNode', fn),参数为 e.data.node |
renderer.on('clickNode', fn),参数为 { node, event, ... } |
| 动态高亮样式 | 修改节点对象 n.color = '#f00' 并执行 s.refresh() |
配置 nodeReducer 纯函数返回渲染态属性 |
| 力导向布局 | s.startForceAtlas2(config) |
new FA2Layout(graph, config).start() (来自独立包) |
| 实例销毁 | s.kill() |
renderer.kill() (或 graph.clear() 清空图) |
三、分步迁移实操指南
对已有 v1 项目进行重构时,建议按照“依赖替换 → 数据结构迁移 → 渲染层绑定 → 交互与样式重构 → 布局迁移”的顺序逐步推进,避免多处破坏性变更同时交织导致难以排查问题。
第 1 步:依赖管理与工程环境清理
在项目中移除旧版本的 sigma 库及附属插件,并安装 sigma v2 及其核心依赖 graphology。如果使用了力导向布局,还需要安装对应算法包:
# 卸载旧版依赖
npm uninstall sigma
# 安装 v2 核心渲染库及图模型
npm install sigma@^2.4.0 graphology@^0.25.4
# 若需要 ForceAtlas2 布局支持,安装对应 graphology 扩展
npm install graphology-layout-forceatlas2@^0.10.1
第 2 步:重写图数据生成与属性绑定
在 v1 中,节点数据通常是一个包含 id 的对象,且经常直接丢进 graph.read({ nodes, edges })。在 v2 中,必须先构建 Graphology 实例。另外需要特别注意:每个节点必须明确具备 x、y、size 和 color 属性,WebGL 着色器依赖这些数值计算顶点缓冲区;如果缺少 x 或 y,渲染器会抛出异常或无法呈现。
// ==================== v1 做法 ====================
var s = new sigma('container');
s.graph.read({
nodes: [
{ id: 'n1', label: '节点 A', x: 0, y: 0, size: 5, color: '#6487A5' },
{ id: 'n2', label: '节点 B', x: 10, y: 10, size: 5, color: '#C28B68' }
],
edges: [
{ id: 'e1', source: 'n1', target: 'n2', size: 1, color: '#CCCCCC' }
]
});
s.refresh();
// ==================== v2 迁移后 ====================
import Graph from 'graphology';
const graph = new Graph();
// 添加节点:第一个参数为唯一 Key/ID,第二个参数为属性字典
graph.addNode('n1', {
label: '节点 A',
x: 0,
y: 0,
size: 10,
color: '#6487A5'
});
graph.addNode('n2', {
label: '节点 B',
x: 1,
y: 1,
size: 10,
color: '#C28B68'
});
// 添加边:可以使用 addEdgeWithKey 显式指定边 ID,或由系统自动生成
graph.addEdgeWithKey('e1', 'n1', 'n2', {
size: 2,
color: '#CCCCCC'
});
避坑提示:坐标系差异
v1 的渲染引擎会自动根据容器大小进行宽松的缩放和中心对齐;而 v2 基于 WebGL 坐标系,更倾向于使用归一化坐标或比例较为平衡的数值范围(例如 [0, 1] 或 [-100, 100])。如果原有数据的坐标跨度极大(如数万像素),请在录入前进行一次归一化处理,或通过相机初始化配置来适配视口。
第 3 步:重构渲染器实例化与事件绑定
v2 统一采用 new Sigma(graph, container, [options]),首字母必须大写。同时,事件绑定由 bind() 变为标准的 on(),事件回调的载荷(payload)由包含深层嵌套的 e.data 简化为展开后的事件上下文:
// ==================== v1 事件与相机 ====================
s.bind('clickNode', function(e) {
var clickedNodeId = e.data.node.id;
console.log('点击节点:', clickedNodeId);
});
// 相机定位移动
s.cameras[0].goTo({ x: 0, y: 0, ratio: 0.5 });
// ==================== v2 迁移后 ====================
import Sigma from 'sigma';
const container = document.getElementById('container');
const renderer = new Sigma(graph, container, {
renderEdgeLabels: true,
allowInvalidContainer: false
});
// 事件监听:结构解构更直接
renderer.on('clickNode', ({ node, event }) => {
console.log('点击节点 key:', node);
console.log('原始 DOM 事件:', event);
});
// 相机控制:通过专用 Camera 实例操作
const camera = renderer.getCamera();
camera.setState({
x: 0.5,
y: 0.5,
ratio: 0.5,
angle: 0
});
// 也可以调用动画重置:camera.animatedReset();
第 4 步:动态样式重构——使用 Reducer 替代破坏性改值
在图分析应用中,最常见的交互是“悬停(Hover)或点击某个节点时,将其邻居高亮,其余节点暗化”。在 v1 中,通常是通过循环遍历所有节点,临时将非邻居节点的 color 改为浅灰,最后调用 s.refresh()。这种方式不仅破坏了原本的真实业务数据,而且在大图频繁触发时会造成严重的性能卡顿。
v2 引入了 Node Reducer 与 Edge Reducer 模式。Reducer 是纯函数,负责在每一帧渲染时决定某个节点在当前状态下的视觉属性(如颜色、大小、隐藏与否),完全不改写 Graph 存储的底层数据:
// 当前选中的焦点节点 ID
let hoveredNode = null;
// 设置节点样式 Reducer
renderer.setSetting('nodeReducer', (node, data) => {
const res = { ...data };
// 若存在激活节点
if (hoveredNode) {
if (node === hoveredNode) {
res.color = '#C28B68'; // 选中节点高亮强调色
res.size = data.size * 1.3;
res.highlighted = true;
} else if (graph.areNeighbors(node, hoveredNode)) {
res.color = '#6487A5'; // 邻接节点保持主色
res.highlighted = false;
} else {
res.color = '#E5E7EB'; // 非关联节点灰度暗化
res.label = ''; // 隐藏无关文本
}
}
return res;
});
// 监听鼠标移入与移出,直接触发轻量渲染,无需遍历改写图数据
renderer.on('enterNode', ({ node }) => {
hoveredNode = node;
renderer.refresh(); // 仅通知渲染层重新执行 Reducer,极速轻量
});
renderer.on('leaveNode', () => {
hoveredNode = null;
renderer.refresh();
});
第 5 步:布局计算(ForceAtlas2)迁移
在 v1 中,ForceAtlas2 作为一个内置插件挂载在 sigma 实例上:s.startForceAtlas2()。在 v2 中,布局算法独立为一个单独的运算工具,支持同步迭代计算,也支持在 Web Worker 线程中后台运行:
// ==================== v1 布局 ====================
s.startForceAtlas2({
worker: true,
barnesHutOptimize: true,
iterationsPerRender: 2
});
// 稍后停止
s.stopForceAtlas2();
// ==================== v2 迁移后 ====================
import FA2Layout from 'graphology-layout-forceatlas2/worker';
// 实例化布局 Worker,将 graph 实例传入
const layout = new FA2Layout(graph, {
settings: {
barnesHutOptimize: true,
gravity: 1,
scalingRatio: 2
}
});
// 启动后台计算(不阻塞 UI 主线程)
layout.start();
// 当需要停止时
// layout.stop();
// 也可以监听计算步进事件(可选)
四、常见问题排查与注意事项
1. 控制台报错:“Node X does not have an 'x' coordinate”
原因:v2 要求所有节点在加入 Graphology 时必须含有 x 和 y。如果导入的 JSON 数据未经过布局预计算,请先调用 graphology-layout/random 或 circular 等轻量布局赋予初始坐标,再挂载到 Sigma 渲染器中。
2. 文本标签(Label)显示截断或无法展示中文字符
原因:v2 默认将非激活态的文字渲染委托给 Canvas 覆盖层(或 WebGL 字体纹理)。若要展示中文,应在 Sigma 初始化选项中明确指定系统字体回退链,例如:
{ labelFont: '"PingFang SC", "Microsoft YaHei", sans-serif', labelSize: 12 }。
3. 原有的自定义节点形状(如星形、饼图、图片节点)失效
原因:v1 基于 2D Canvas 的 canvas.nodes.custom.js 绘制 API 无法直接在 v2 中运行。v2 中实现自定义形状需要编写继承自 NodeProgram 的 WebGL 着色器程序,或使用社区提供的 @sigma/node-image 等现成扩展包。
五、总结
从 sigma.js v1 迁移到 v2 的实质,是将图应用从传统的“单体 DOM/Canvas 插件”转换为“标准拓扑数据模型(Graphology)+ GPU 硬件加速渲染管线(Sigma v2)”的现代化技术架构。尽管构造方式与事件交互有破坏性调整,但随着职责边界的彻底理清,不仅解决了数万量级图节点的流畅交互难题,也使得状态管理、算法拓展与组件化封装变得更为健壮可维护。
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。