Cytoscape.js 使用文档与说明
基于 Cytoscape.js v3.34 官方文档 整理
一、什么是 Cytoscape.js
Cytoscape.js 是一个由多伦多大学 Donnelly Centre 开发的开源 JavaScript 图论/网络可视化库,采用 MIT 许可证,已在《Bioinformatics》(2016、2023)期刊发表学术论文。不同于 AntV X6(偏图编辑器),Cytoscape.js 专注于图数据的可视化分析,擅长处理大规模节点-边关系展示与交互。
支持的图模型
| 图类型 | 支持 |
|---|---|
| 有向图(Directed) | ✅ |
| 无向图(Undirected) | ✅ |
| 混合图(Mixed) | ✅ |
| 多重图(Multigraph,多重边) | ✅ |
| 自环(Loops) | ✅ |
| 复合图(Compound,父子节点嵌套) | ✅ |
核心特性
- 图论原生支持:内置节点度、最短路径(Dijkstra/A*)、连通分量、PageRank 等图算法
- 丰富布局算法:8 种核心内置布局(circle、concentric、breadthfirst、grid、cose、random、preset、null),通过官方第一方扩展可扩展至 15+(dagre、klay、avsdf、cola、fcose、elk 等)
- 高性能渲染:Canvas 2D 渲染,支持数千节点的流畅交互
- 移动端友好:原生触摸手势支持(pinch-zoom、pan 双指缩放)
- 可扩展架构:通过
cytoscape.use(ext)注册第一方及社区扩展,涵盖布局、UI 控件、数据导入等 - 多模块格式:支持 UMD(
cytoscape.min.js)、ESM(cytoscape.esm.min.mjs)、CommonJS(cytoscape.cjs.js) - 跨环境运行:支持所有现代浏览器,Node.js headless 模式可用于纯计算/服务端渲染
适用场景
| 场景 | 是否推荐 |
|---|---|
| 人物关系图、组织架构图 | ✅ 强推 |
| 知识图谱可视化 | ✅ 强推 |
| 网络拓扑图 | ✅ 推荐 |
| 社交网络分析 | ✅ 强推 |
| 流程图编辑器 | ❌ 不适合(用 X6) |
| 思维导图 | ❌ 不适合(用 X6) |
二、快速开始
模块格式说明
根据构建目标选择合适的引入方式:
| 格式 | 文件 | 引入方式 |
|---|---|---|
| ESM(推荐) | cytoscape.esm.min.mjs | import cytoscape from 'cytoscape' |
| CJS | cytoscape.cjs.js | const cytoscape = require('cytoscape') |
| UMD | cytoscape.min.js | <script src="..."></script> |
安装
1 | # npm |
cy.ready() 回调
官方推荐使用 cy.ready() 替代手动监听 layoutstop 来等待图初始化完成(因为可能没有 layout 事件):
1 | cy.ready(event => { |
基础示例
1 |
|
在 Vue 3 项目中使用:
1 | <!-- GraphDemo.vue --> |
三、核心概念
3.1 核心对象(Core)
cytoscape() 返回的 cy 对象是整个图实例,所有操作都通过它进行。
1 | const cy = cytoscape({ /* options */ }) |
3.2 集合(Collection)
cy.nodes()、cy.edges()、cy.filter() 等返回的是集合(Collection),支持链式调用:
1 | // 获取所有被选中的节点 |
3.3 元素(Elements)
每个节点和边都是一个元素对象:
1 | const node = cy.getElementById('a'); |
3.4 Notation(关键位置/尺寸概念)
Cytoscape.js 官网清晰区分了以下 notation,理解它们是深入使用的关键:
| 术语 | 官方定义 | 示例 / 说明 |
|---|---|---|
| model position | 元素的图模型坐标,即 node.position() 返回的 {x, y} | 布局算法操作的坐标,存储在图模型中 |
| model dimensions | 元素的图模型宽高,受 style width/height 控制 | 影响布局的碰撞检测 |
| rendered position | 元素在 Canvas 视口上的屏幕像素坐标 | 随 pan/zoom 变化,用于右键菜单位置等 UI 交互 |
| rendered dimensions | 元素在 Canvas 视口上的屏幕像素尺寸 | 受 zoom 缩放影响 |
1 | // 坐标转换 |
3.5 Compound Nodes(复合节点 / 父子嵌套)
Cytoscape.js 原生支持父子节点嵌套——节点可以包含子节点,形成层级结构的复合图。这是 AntV X6 不具备的原生能力。
1 | // 定义父子关系(在 data 中通过 parent 字段指定) |
关键 API:
1 | // 检查节点是否为父节点 |
3.6 Scratch Data(临时绑定数据)
除 node.data()(会被序列化)外,Cytoscape.js 还提供 scratch() 方法用于绑定运行时临时数据,不会被导出/序列化:
1 | // 绑定临时数据 |
3.7 Batch Operations(批量操作)
官网推荐使用 cy.batch() 进行批量操作以提升性能。批量回调中的位置变化会在回调结束后一次性应用,减少多次重绘:
1 | // 批量添加节点并设置初始位置,只触发一次重绘 |
cy.batch() 与 cy.startBatch() / cy.endBatch() 的区别:
| 方法 | 说明 |
|---|---|
cy.batch(callback) | 推荐方式,自动管理批处理周期。callback 可嵌套(内层与外层共享同一个批) |
cy.startBatch() | 手动开始批处理 |
cy.endBatch() | 手动结束批处理 |
注意:多层嵌套的
batch()调用中,渲染只在最外层 batch 结束后触发一次。
3.8 Graph Model(elements JSON 格式)
Cytoscape.js 的 elements 使用扁平 JSON 格式,不同于 X6 的嵌套 model:
1 | const elements = { |
重要:节点的
position是可选字段,如果不指定则布局算法自动计算。data中除id/source/target外的字段都是自定义业务数据。
四、选择器系统(Selectors)
Cytoscape.js 的选择器与 CSS 非常相似,用于从图中筛选元素。所有 cy.filter()、cy.nodes()、cy.edges()、cy.$() 等方法都接受选择器字符串。
4.1 基础选择器
| 选择器 | 语法 | 示例 | 说明 |
|---|---|---|---|
| 按类型 | node / edge / * | cy.nodes() = cy.filter('node') | * 匹配所有元素 |
| 按 ID | #id | cy.$('#a') | 精确匹配元素 ID |
| 按类名 | .className | cy.$('.a-class') | 元素可以有多个类名(空格分隔) |
| 按数据字段 | [field] / [field = value] | cy.$('[type = "root"]') | 支持 =, !=, >, >=, <, <= |
| 按 scratch 数据 | [[field]] / [[field = value]] | cy.$('[[expanded = true]]') | 匹配 scratch() 绑定的临时数据 |
4.2 复合选择器
1 | // 同时匹配多个条件(AND) |
4.3 状态伪类选择器
| 选择器 | 说明 |
|---|---|
:selected | 被选中的元素 |
:unselected | 未被选中的元素 |
:selectable | 可被选中的元素 |
:visible | 可见元素 |
:hidden | 隐藏元素(display: none 或 visibility: hidden) |
:locked | 被锁定的节点 |
:animated | 正在执行动画的元素 |
:childless | 无子节点的节点 |
:parent | 有子节点的节点 |
:orphan | 无父节点的节点 |
4.4 图元字段选择器(Metadata / degree 等)
以下字段作为元素的原生图元属性,可使用 ? 前缀查询:
| 字段 | 说明 | 适用于 |
|---|---|---|
?degree | 度(相连边数) | node |
?indegree | 入度 | node |
?outdegree | 出度 | node |
?isEdge | 是否为边 | node, edge |
?isLoop | 是否为自环 | edge |
?isSimple | 是否为简单边(非 Loop) | edge |
?source | 源节点 ID | edge |
?target | 目标节点 ID | edge |
?group | 元素分组 (‘nodes’/‘edges’) | node, edge |
?removed | 是否已被移除 | node, edge |
1 | // 实用选择器示例 |
4.5 函数式选择器
1 | // 使用函数作为过滤器 |
五、节点与边的样式(Style)
5.1 声明式样式架构
Cytoscape.js 的样式系统是全声明式的,与 CSS 高度相似,使用选择器 + 属性对象进行组织:
1 | const style = [ |
重要:样式更新必须调用
.update()才会生效。如果忘记调用,样式不会应用到画布。
5.2 核心 / 容器级样式
这些样式属性在 cytoscape() 初始化选项中直接配置(不在 style 数组内):
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
selectionType | string | 'single' | 选择模式:'single'(单选)、'additive'(多选/按住 Shift) |
selectionBoxColor | string | '#2a65b7' | 框选矩形边框颜色 |
selectionBoxOpacity | number | 0.3 | 框选矩形填充透明度 |
selectionBoxBorderWidth | number | 1 | 框选矩形边框宽度 |
activeBgColor | string | '#35b757' | 活跃背景色(用于指示拖拽目标等) |
activeBgOpacity | number | 0.2 | 活跃背景透明度 |
activeBgSize | number | 1 | 活跃背景相对于节点尺寸的缩放比例 |
5.3 节点形状完整列表
Cytoscape.js 官方共提供 12 种内置节点形状,通过 shape 属性控制:
| 形状名 | 效果 | 说明 |
|---|---|---|
ellipse | 椭圆形 | 默认形状,width=height 时即为正圆 |
rectangle | 矩形 | 直角矩形 |
roundrectangle | 圆角矩形 | 配合 border-radius 控制圆角半径 |
round-rectangle | 圆角矩形(别名) | 同上 |
triangle | 三角形 | 等边三角形 |
pentagon | 五边形 | 正五边形 |
hexagon | 六边形 | 正六边形 |
heptagon | 七边形 | 正七边形 |
octagon | 八边形 | 正八边形 |
diamond | 菱形 | 旋转 45° 的正方形 |
vee | V 形 | 倒三角形/箭头形 |
star | 星形 | 五角星 |
tag | 标签形 | 右侧有尖角的标签形状 |
rhomboid | 平行四边形 | 倾斜的矩形 |
cut-rectangle | 切角矩形 | 右上角被切掉的矩形 |
barrel | 桶形 | 上下边弯曲的矩形 |
bottom-round-rectangle | 底部圆角矩形 | 仅底部有圆角 |
concave-hexagon | 凹六边形 | 凹进的六边形 |
polygon | 多边形 | 通过 shape-polygon-points 自定义多边形边数 |
1 | // 形状示例 |
5.4 完整节点样式属性表
| 属性 | 类型 | 说明 |
|---|---|---|
width | number / string | 节点宽度(px),可动态函数 |
height | number / string | 节点高度(px),可动态函数 |
shape | string | 节点形状(见上表) |
shape-polygon-points | number | 当 shape 为 polygon 时的边数 |
border-radius | number | 圆角半径(roundrectangle 时有效) |
background-color | string | 节点背景色 |
background-opacity | number (0-1) | 背景透明度 |
background-image | string / function | 背景图片 URL |
background-fit | string | 图片适配:'none'、'contain'、'cover' |
background-image-opacity | number (0-1) | 背景图片透明度 |
background-clip | string | 裁剪:'none'、'node' |
background-width / background-height | number / string | 背景图尺寸(相对于节点) |
background-position-x / background-position-y | number / string | 背景图偏移 |
border-width | number | 边框宽度 |
border-style | string | 'solid'、'dotted'、'dashed'、'double' |
border-color | string | 边框颜色 |
border-opacity | number (0-1) | 边框透明度 |
padding | number / string | 内容内边距(影响复合节点的子节点边界) |
padding-relative-to | string | 'width' / 'height' / 'average' / 'min' / 'max' |
| Label 属性 | ||
label | string / function | 标签内容,支持 'data(key)' 或函数 |
color | string | 标签文字颜色 |
font-size | number | 字体大小(px) |
font-family | string | 字体族 |
font-weight | string | 字重:'normal'、'bold'、'lighter'、数字 |
font-style | string | 字体样式:'normal'、'italic' |
text-valign | string | 垂直对齐:'top'、'center'、'bottom' |
text-halign | string | 水平对齐:'left'、'center'、'right' |
text-margin-x | number | 文字水平偏移 |
text-margin-y | number | 文字垂直偏移 |
text-wrap | string | 换行:'none'、'wrap'、'ellipsis' |
text-max-width | number | 文字最大宽度(超出则换行) |
text-rotation | number / string | 文字旋转角度(deg/rad) |
text-outline-width | number | 文字描边宽度 |
text-outline-color | string | 文字描边颜色 |
text-outline-opacity | number (0-1) | 文字描边透明度 |
text-background-color | string | 文字背景色 |
text-background-opacity | number (0-1) | 文字背景透明度 |
text-background-shape | string | 文字背景形状:'rectangle'、'roundrectangle' |
text-background-padding | string | 文字背景内边距,如 '3px' |
text-border-color | string | 文字边框颜色 |
text-border-width | number | 文字边框宽度 |
text-border-style | string | 文字边框样式 |
text-border-opacity | number (0-1) | 文字边框透明度 |
| Ghost 效果 | ||
ghost | string | 'yes' / 'no' — 拖拽时显示节点半透明鬼影 |
active-bg-color | string | 活跃状态背景色 |
active-bg-opacity | number (0-1) | 活跃状态背景透明度 |
active-bg-size | number | 活跃状态背景缩放比例 |
| 其他 | ||
display | string | 'element' / 'none' — 隐藏节点(不参与布局) |
visibility | string | 'visible' / 'hidden' — 隐藏节点(仍占布局空间) |
opacity | number (0-1) | 元素透明度 |
z-index | number | 层级(影响渲染顺序和事件命中顺序) |
z-compound-depth | string | 'auto' / 'top' / 'bottom' — 复合层级中的 z 排序策略 |
z-index-compare | string | 'auto' / 'manual' — 是否自动处理子元素 z-index |
min-zoomed-font-size | number | 最小可读字体(缩小时字体不会小于此值) |
events | string | 'yes' / 'no' — 是否接收事件 |
overlay-color | string | 遮罩颜色 |
overlay-opacity | number (0-1) | 遮罩透明度 |
overlay-padding | number | 遮罩扩展宽度 |
5.5 完整边样式属性表
| 属性 | 类型 | 说明 |
|---|---|---|
width | number | 边线宽度 |
line-color | string | 边线颜色 |
line-style | string | 'solid'、'dotted'、'dashed'、'double' |
line-opacity | number (0-1) | 边线透明度 |
line-cap | string | 端点样式:'butt'、'round'、'square' |
line-fill | string | 填充模式:'solid'、'linear-gradient'、'radial-gradient' |
line-dash-pattern | number[] | 虚线模式,如 [6, 3] |
line-dash-offset | number | 虚线偏移 |
| 曲线样式 | ||
curve-style | string | 'haystack'(直线)、'straight'(可弯曲直线)、'bezier'(贝塞尔曲线、默认)、'unbundled-bezier'(不捆绑贝塞尔、平行边自动分离)、'segments'(自定义折线)、'taxi'(直角折线/正交) |
haystack-radius | number | haystack 曲线半径 |
control-point-step-size | number | bezier 控制点的步进大小 |
control-point-distance | number | unbundled-bezier 控制点距离 |
control-point-weight | number | unbundled-bezier 控制点权重 |
segment-distances | number[] | segments 曲线各段的长度 |
segment-weights | number[] | segments 曲线各段的权重 |
edge-distances | string | taxi 曲线模式:'node-position' / 'intersection' / 'node-center' |
| 箭头 | ||
arrow-scale | number | 箭头缩放比例 |
target-arrow-shape | string | 目标端箭头形状 |
target-arrow-color | string | 目标端箭头颜色 |
target-arrow-fill | string | 箭头填充:'filled'、'hollow' |
source-arrow-shape | string | 源端箭头形状 |
source-arrow-color | string | 源端箭头颜色 |
source-arrow-fill | string | 箭头填充:'filled'、'hollow' |
mid-target-arrow-shape | string | 中段目标箭头 |
mid-target-arrow-color | string | 中段目标箭头颜色 |
mid-source-arrow-shape | string | 中段源箭头 |
mid-source-arrow-color | string | 中段源箭头颜色 |
| Label 属性 | (与节点 label 属性基本相同) | |
source-label | string | 源端标签文本 |
target-label | string | 目标端标签文本 |
source-text-offset | number | 源端标签偏移 |
target-text-offset | number | 目标端标签偏移 |
| 其他 | ||
opacity | number (0-1) | 透明度 |
display | string | 'element' / 'none' |
visibility | string | 'visible' / 'hidden' |
z-index | number | 层级 |
events | string | 'yes' / 'no' |
overlay-color | string | 遮罩颜色 |
overlay-opacity | number (0-1) | 遮罩透明度 |
overlay-padding | number | 遮罩扩展 |
5.6 完整箭头形状列表
| 箭头形状名 | 效果说明 |
|---|---|
triangle | 标准三角形 |
triangle-tee | 三角形 + 横线(T 边框效果) |
circle-triangle | 圆形三角形 |
triangle-cross | X 形三角 |
triangle-backcurve | 后弯三角 |
vee | V 形 |
tee | 横线 |
square | 方块 |
circle | 圆形 |
diamond | 菱形 |
chevron | V 形箭头 |
none | 无箭头 |
half-triangle-overshot | 半三角超伸 |
5.7 样式声明完整示例
1 | const style = [ |
5.8 使用图片作为节点背景
不同类型节点使用不同图标是最常见的需求:
1 | // 方案一:通过样式声明 |
5.9 暗色主题
1 | const darkThemeStyle = [ |
5.10 常用样式属性速查
节点样式
| 属性 | 说明 | 示例值 |
|---|---|---|
width / height | 节点尺寸 | 60 |
background-color | 背景色 | '#4e56fd' |
background-image | 背景图片 | 'url(path)' |
background-fit | 背景图适配方式 | 'cover' / 'contain' / 'none' |
border-width | 边框宽度 | 2 |
border-color | 边框颜色 | '#fff' |
border-style | 边框样式 | 'solid' / 'dashed' / 'double' |
shape | 节点形状 | 'ellipse' / 'rectangle' / 'roundrectangle' / 'diamond' / 'hexagon' 等 |
label | 标签文本 | 'data(label)' |
color | 标签颜色 | '#fff' |
font-size | 字体大小 | 12 |
text-valign | 文字垂直对齐 | 'center' / 'top' / 'bottom' |
text-halign | 文字水平对齐 | 'center' / 'left' / 'right' |
text-margin-y | 文字垂直偏移 | 8 |
opacity | 透明度 | 0.8 |
z-index | 层级 | 10 |
边样式
| 属性 | 说明 | 示例值 |
|---|---|---|
width | 边宽度 | 2 |
line-color | 边颜色 | '#999' |
line-style | 边样式 | 'solid' / 'dashed' / 'dotted' |
curve-style | 曲线样式 | 'bezier' / 'haystack' / 'straight' / 'unbundled-bezier' |
target-arrow-shape | 箭头形状 | 'triangle' / 'triangle-backcurve' / 'chevron' / 'tee' / 'diamond' / 'none' |
target-arrow-color | 箭头颜色 | '#999' |
source-arrow-shape | 源端箭头 | 同上 |
arrow-scale | 箭头缩放 | 1.5 |
六、布局系统(Layout)
6.1 内置布局速查
Cytoscape.js 提供 10+ 内置布局,无需额外安装:
| 布局名 | 说明 | 适用场景 |
|---|---|---|
dagre | 层次布局(自上而下) | ⭐ 人员关系、组织架构 |
breadthfirst | 广度优先布局 | 树状层级数据 |
concentric | 同心圆布局 | 中心辐射关系 |
circle | 圆形布局 | 对等关系展示 |
cose | 力导向布局(CoSE) | 社交网络、大规模图 |
cose-bilkent | 增强力导向布局 | 大规模图优化 |
grid | 网格布局 | 等距排列 |
random | 随机布局 | 初始占位 |
preset | 预设位置 | 保持已有坐标 |
null | 空布局(不改变位置) | 手动管理位置 |
6.2 布局配置详解
1 | // dagre - 树形层次布局(最常用) |
6.3 官方第一方扩展布局
| 扩展包 | 布局名 | 适用场景 | 安装 |
|---|---|---|---|
cytoscape-dagre | dagre | 层次布局(自上而下/左到右) | npm i cytoscape-dagre |
cytoscape-klay | klay | Klay 分层布局(支持端口/复合节点) | npm i cytoscape-klay |
cytoscape-avsdf | avsdf | 圆形力导向(避免节点重叠) | npm i cytoscape-avsdf |
cytoscape-cola | cola | CoLa 约束布局(支持对齐约束) | npm i cytoscape-cola |
cytoscape-fcose | fcose | fCoSE 快速力导向(CoSE 的增强版) | npm i cytoscape-fcose |
cytoscape-cise | cise | CiSE 圆形簇布局 | npm i cytoscape-cise |
cytoscape-spread | spread | 展开布局(将重叠节点分散) | npm i cytoscape-spread |
cytoscape-elk | elk | ELK 布局引擎(最强分层布局) | npm i cytoscape-elk |
cytoscape-cose-bilkent | cose-bilkent | 大规模力导向(支持万级节点) | npm i cytoscape-cose-bilkent |
常用扩展布局:
1 | pnpm add cytoscape-avsdf # 圆形力导向布局 |
1 | import cytoscape from 'cytoscape'; |
6.4 布局切换实战
1 | // 布局切换函数 |
七、事件系统
7.1 事件绑定与解绑
1 | // 绑定事件 |
7.2 常用事件分类
交互事件
| 事件 | 触发时机 |
|---|---|
tap | 点击 |
dbltap | 双击 |
cxttap | 右键点击(context menu) |
tapstart / tapend | 按下 / 释放 |
mousedown / mouseup / mousemove | 鼠标事件 |
mouseover / mouseout | 鼠标进入/离开 |
拖拽事件
| 事件 | 触发时机 |
|---|---|
grab | 开始拖拽节点 |
drag | 拖拽过程中(高频触发) |
free | 释放节点 |
dragfree | 释放后(别名) |
dragfreeon | 释放到某个位置 |
视口事件
| 事件 | 触发时机 |
|---|---|
zoom | 缩放变化 |
pan | 平移变化 |
resize | 容器尺寸变化 |
viewport | 视口任何变化(zoom/pan/resize) |
布局事件
| 事件 | 触发时机 |
|---|---|
layoutstart | 布局开始 |
layoutready | 布局就绪(初始位置已计算) |
layoutstop | 布局完成 |
元素变更事件
| 事件 | 触发时机 |
|---|---|
add | 添加元素 |
remove | 删除元素 |
data | 元素的 data 更新 |
position | 节点位置变化 |
7.3 实战:交互示例
1 | // 右键菜单 |
八、交互与操作
8.1 画布控制
1 | // 缩放 |
8.2 元素操作
1 | // 添加元素 |
在 CSS 中配合:
1 | .light-off { |
8.3 撤销/重做
1 | // 自建历史栈 |
注意:
cy.json()会导出完整的元素和样式信息,对大规模图会有性能开销。可以优化为只保存 elements JSON。
8.4 导出图片
1 | // 导出 PNG |
8.5 搜索与定位
1 | // 搜索节点并居中 |
九、动画系统
Cytoscape.js 提供两套动画 API:
cy.animate()— 对整个视口(zoom/pan)做动画ele.animation()— 对单个元素(节点/边)做动画
9.1 视口动画(cy.animate)
1 | // 视口平滑过渡 |
9.2 元素动画(ele.animation)
1 | // 对单个节点做位置动画 |
9.3 缓动函数(Easing)
| 缓动函数 | 曲线效果 |
|---|---|
'linear' | 匀速 |
'ease' | 标准缓入缓出 |
'ease-in' | 缓入 |
'ease-out' | 缓出 |
'ease-in-out' | 缓入缓出 |
'ease-in-sine' | 正弦缓入 |
'ease-out-sine' | 正弦缓出 |
'ease-in-out-sine' | 正弦缓入缓出 |
'ease-in-quad' / 'ease-out-quad' / 'ease-in-out-quad' | 二次缓动 |
'ease-in-cubic' / 'ease-out-cubic' / 'ease-in-out-cubic' | 三次缓动 |
'ease-in-back' / 'ease-out-back' / 'ease-in-out-back' | 回弹缓动 |
'ease-in-bounce' / 'ease-out-bounce' / 'ease-in-out-bounce' | 弹跳缓动 |
9.4 动画控制
1 | const anim = node.animation({ position: { x: 300, y: 200 } }, { duration: 1000 }) |
9.5 布局动画
布局本身也支持 animate 选项,运行布局时会平滑过渡节点位置:
1 | cy.layout({ |
十、插件生态
10.1 常用插件
1 | pnpm add cytoscape-edgehandles # 边手动拖拽连线 |
1 | import cytoscape from 'cytoscape'; |
10.2 其他推荐插件
| 插件 | 功能 | 安装 |
|---|---|---|
cytoscape-context-menus | 右键菜单(比手写更规范) | npm i cytoscape-context-menus |
cytoscape-cxtmenu | 圆形右键菜单 | npm i cytoscape-cxtmenu |
cytoscape-navigator | 缩略图导航 | npm i cytoscape-navigator |
cytoscape-cola | CoLa 约束布局 | npm i cytoscape-cola |
cytoscape-popper | Tooltip 定位 | npm i cytoscape-popper |
cytoscape-fcose | fCoSE 快速力导向 | npm i cytoscape-fcose |
cytoscape-spread | 展开布局 | npm i cytoscape-spread |
cytoscape-svg | SVG 渲染器 | npm i cytoscape-svg |
10.3 右键菜单插件示例
1 | import cytoscape from 'cytoscape'; |
十一、数据接口对接
Cytoscape.js 使用扁平 JSON 格式管理图数据,后端返回的数据通常需要转换才能渲染。
11.1 后端数据格式转换
常见的后端图数据需要通过转换函数转为 Cytoscape elements 格式:
1 | // 后端返回的数据格式示例 |
11.2 节点增量展开
1 | // 展开某个节点的关联数据 |
11.3 数据清洗
推荐在添加到画布前对数据进行清洗,避免脏数据影响渲染效果:
1 | const cleanData = (rawData) => { |
十二、性能优化
Cytoscape.js 通过 Canvas 渲染已经相当高效,但对于大规模图(1000+ 节点),官方提供了以下性能优化选项。
12.1 渲染性能初始化选项
这些选项在 cytoscape() 初始化时配置,直接影响渲染帧率和交互流畅度:
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
hideEdgesOnViewport | boolean | false | 推荐开启。交互时(pan/zoom/动画)自动隐藏边,大幅提升帧率。释放后恢复显示 |
textureOnViewport | boolean | false | 交互时使用纹理缓存渲染节点(降低精度换取性能) |
motionBlur | boolean | false | 开启运动模糊(让低帧率动画看起来更平滑) |
pixelRatio | number / 'auto' | 'auto' | 渲染像素比。大图可设为 1(牺牲清晰度换性能) |
wheelSensitivity | number | 1 | 滚轮缩放灵敏度,减小可降低重绘次数 |
headless | boolean | false | 无头模式。无 DOM 渲染,仅用于纯计算(服务端/单元测试) |
styleEnabled | boolean | true | 是否启用样式解析。在纯计算场景设为 false 可跳过样式计算 |
1 | // 高性能配置示例(适用 2000+ 节点场景) |
12.2 边曲线优化
边的曲线样式对性能影响很大,按性能排序:
| 曲线样式 | 性能 | 视觉效果 | 建议 |
|---|---|---|---|
haystack | ⭐⭐⭐ 最快 | 直线(忽略节点位置) | 适合大规模图(5000+ 节点) |
straight | ⭐⭐ 较快 | 可弯曲直线 | 中等规模 |
bezier | ⭐ 正常 | 标准贝塞尔曲线 | 中小规模(< 500 节点) |
unbundled-bezier | 💤 最慢 | 平行边自动分离 | 仅复杂关系图 |
segments | ⭐ 正常 | 自定义折线 | 按需使用 |
taxi | ⭐ 正常 | 正交折线 | 按需使用 |
1 | // 大规模图下的边样式 |
12.3 元素层级与事件优化
| 优化项 | 说明 |
|---|---|
z-index | 给重要节点更高的 z-index,减少事件命中计算量 |
events: 'no' | 对纯装饰性边/节点禁用事件 |
display: 'none' | 隐藏视口外元素(不参与布局和渲染) |
text-wrap: 'ellipsis' | 限制标签长度,减少文本渲染开销 |
min-zoomed-font-size | 设置最小可视化字体,缩小后自动不渲染小文字 |
12.4 Node.js 无头模式
用于纯图算法计算或服务端布局预计算:
1 | const cytoscape = require('cytoscape'); |
12.5 实用性能检查清单
| 场景 | 建议配置 |
|---|---|
| 节点数 < 200 | 默认配置即可 |
| 200 - 1000 节点 | curve-style: 'bezier',开启 hideEdgesOnViewport |
| 1000 - 5000 节点 | curve-style: 'haystack',pixelRatio: 1,textureOnViewport: true |
| 5000+ 节点 | curve-style: 'haystack',pixelRatio: 1,hideEdgesOnViewport,motionBlur,禁用 label |
| 服务端计算 | headless: true, styleEnabled: false |
十三、Vue 3 集成实战
Cytoscape.js 在 Vue 3 中的集成模式比较固定,核心是管理好 cytoscape 实例的生命周期:mounted 时创建,unmounted 时销毁。
13.1 基础组件结构
1 | <!-- GraphCanvas.vue --> |
13.2 加载数据
1 | const loadGraphData = async () => { |
13.3 布局切换
1 | const layoutConfigs = { |
13.4 交互事件
1 | // 节点点击 → 显示详情 |
13.5 工具函数
1 | // dataTransform.js —— 数据格式转换 |
1 | // graphConfig.js —— 默认样式配置 |
十四、AntV X6 vs Cytoscape.js 对比
| 维度 | AntV X6 | Cytoscape.js |
|---|---|---|
| 定位 | 图编辑器(Diagram Editor) | 图可视化分析(Graph Visualization) |
| 渲染方式 | SVG | Canvas |
| 性能(大图) | 500+ 节点开始卡顿 | 2000+ 节点仍流畅 |
| 内置布局 | 依赖 @antv/layout,需额外安装 | 10+ 内置布局,开箱即用 |
| 图算法 | 无 | 最短路径、度数、连通分量等原生支持 |
| 自定义节点 | React/Vue 组件注册(强大但重) | Canvas 绘制(高性能) |
| 编辑功能 | 连线、对齐、吸附(原生) | 需插件(edgehandles) |
| 撤销重做 | History 插件 | 需自建或插件 |
| 移动端 | 一般 | 原生触摸手势 |
| 包体积 | ~800KB(+ layout) | ~300KB(完整版 ~500KB) |
| 学习曲线 | 较陡(概念多) | 较低(风格扁平) |
选型建议
| 需求 | 推荐 |
|---|---|
| 图编辑器、流程图、ER 图 | AntV X6 |
| 社交网络图、知识图谱、关系分析 | Cytoscape.js |
| 支持自定义 Vue 组件作节点 | AntV X6 |
| 大规模节点(1000+)高性能渲染 | Cytoscape.js |
| 精细的编辑操作(拽线、吸附) | AntV X6 |
十五、从 AntV X6 迁移到 Cytoscape.js
15.1 概念映射
| X6 概念 | Cytoscape.js 对应 |
|---|---|
new Graph({ container }) | cytoscape({ container }) |
graph.addNode({ id, x, y }) | cy.add({ data: { id }, position: { x, y } }) |
graph.addEdge({ source, target }) | cy.add({ data: { source, target } }) |
node.setPosition(x, y) | node.position({ x, y }) |
node.attr({ ... }) | node.style('prop', value) |
node.getData() / node.setData() | node.data() / node.data('key', val) |
graph.getNodes() | cy.nodes() |
graph.getEdges() | cy.edges() |
graph.removeCell(node) | cy.remove(node) |
graph.centerContent() | cy.fit() |
graph.zoom(1.5) | cy.zoom(1.5) |
| X6 自定义 Cell | 样式选择器 node[type="root"] |
| X6 Port | 无原生 Port,通过节点 click + 边创建模拟 |
graph.freeze() / unfreeze() | 不需要(Canvas 批量渲染天然高效) |
15.2 迁移步骤
第一步:替换依赖
1 | pnpm remove @antv/x6 @antv/layout |
第二步:替换初始化代码
1 | // Before (X6) |
第三步:替换数据模型
1 | // Before (X6) |
第四步:替换自定义节点
1 | // Before (X6) - 注册 Vue 组件作为节点 |
第五步:替换布局切换
1 | // Before (X6) - 依赖 @antv/layout |
15.3 关键差异备忘
- 没有 freeze/unfreeze:Cytoscape 的 Canvas 渲染天然支持批量操作,不需要手动控制
- 没有 Port 概念:边的关系由
source/targetID 直接确定,不依赖 Port - 样式是 CSS-like 声明式:主题切换可以直接替换 style 数组
- 布局不需要手动读取坐标:
layout.run()自动更新节点位置 - 数据是扁平的 JSON:没有 Model 类,纯数据驱动
十六、常见问题与排查
Q1: 布局切换后节点位置不更新?
A: layout.run() 是异步的,需要监听 layoutstop 事件或确保 animate: true 的动画已完成。不要手动调用 layout.forEachNode()。
官方推荐使用 layout.promiseOn('layoutstop') 替代事件监听:
1 | const layout = cy.layout({ name: 'dagre' }); |
Q2: 节点图片不显示?
A: 检查:
background-image的值是否正确(需是url(path)格式,或直接 URL 字符串)- 图片路径是否正确(相对于 HTML 页面的路径)
- CORS 问题(跨域图片需要设置
crossorigin)
官方支持多种背景图格式:
1 | // URL 字符串 |
Q3: 大图(1000+ 节点)渲染卡顿?
A: 参考 十二、性能优化 章节:
- 启用
hideEdgesOnViewport: true— 交互时自动隐藏边 - 使用
curve-style: 'haystack'替代'bezier'— 直线比曲线快 3-5 倍 - 设置
pixelRatio: 1— 牺牲清晰度换性能 - 启用
textureOnViewport: true— 纹理缓存 - 使用
motionBlur: true— 视觉掩盖掉帧 - 考虑
text-wrap: 'ellipsis'限制标签长度
Q4: Cytoscape 和 X6 能共存吗?
A: 技术上可以(不同 DOM 容器),但不推荐:
- 图谱库体积叠加,打包体积 ~1MB+
- API 风格差异大,维护成本高
- 建议统一为一个库
Q5: 如何自定义节点形状?
A: Cytoscape 支持多种内置形状,自定义形状需用 Canvas API:
1 | // 内置形状映射 |
如需完全自定义节点,参考官方文档的 Custom Node Shapes 部分。
Q6: 多个实例时如何管理?
A:
1 | // 推荐:用一个 Map 管理多实例 |
Q7: cy.resize() 什么时候需要调用?
A: 当容器尺寸变化时(如侧边栏展开/收起、窗口 resize),需要手动调用:
1 | // 监听容器尺寸变化 |
Q8: 如何正确销毁 Cytoscape 实例?
A:
1 | // 完整销毁流程 |
cy.destroy() 会做以下清理:
- 移除所有绑定的事件监听
- 取消所有动画和布局
- 从 DOM 中移除 Canvas 元素
- 释放内部图数据
参考资源
- Cytoscape.js 官方文档 — 完整 API 参考
- Cytoscape.js GitHub — 源码与 issue 追踪
- Cytoscape.js 示例集 — 官方 Demo
- 扩展插件列表 — 第一方及社区扩展
- Neo4j + Cytoscape 最佳实践 — 图数据库配合
- Cytoscape Desktop — 桌面端姊妹项目(生物信息学)